* fix(#3132): realign spec/plan/ui-phase workflow prose from retired covered/backstop-as-status to resolved+verification The edge-probe resolution model splits status (resolved|dismissed|unresolved) from verification (explicit|backstop). The workflow prose in three files still used the pre-re-cut covered/backstop-as-status vocabulary that validateResolution rejects. Swept all three prose surfaces: - spec-phase.md: Step 5.5 resolution options, --auto mode + log line, comment, Step 6 row list - plan-phase.md: lift rule (L778/L780), comments (L564/L706), quality gate (L826-827) - ui-phase.md: resolution loop (L391), --auto mode (L405-409), write-back format (L415) Added regression test in edge-probe-spec-phase-contract.test.cjs asserting the retired vocab is absent and resolved+verification is used instead. * chore(#3132): add changeset + emitted-drift ack for workflow vocab realignment * fix(#3132): update planner contract tests for resolved+verification vocabulary RR-02 and RR-03 tests asserted the old covered/backstop-as-status vocab. Updated to match the realigned prose (resolved edge → must_haves). * fix(#3132): fix specless-probe-fallback test assertion + merge duplicate ack Test assertion was too strict (expected auto-resolved + verification:explicit on same line). Split into two independent assertions. Merged plan-phase.md ack into existing #2658 fragment to resolve duplicate-path rule violation. * fix(#3132): use bare filenames in ack keys (size map keys are bare, not full paths) * fix(#3132): amend existing acks instead of duplicating — remove plan-phase from #2658, spec-phase from #3132, append #3132 reason to #0000 and #2650 * chore(#3132): backfill changeset PR number 3138 --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -561,8 +561,8 @@ PATTERNS_PATH=$(_gsd_field "$INIT" patterns_path)
|
||||
SPIKE_FINDINGS_PATH=$(ls ./.claude/skills/spike-findings-*/SKILL.md 2>/dev/null | head -1 || true)
|
||||
SKETCH_FINDINGS_PATH=$(ls ./.claude/skills/sketch-findings-*/SKILL.md 2>/dev/null | head -1 || true)
|
||||
|
||||
# Resolve the phase SPEC (carries the ## Edge Coverage section the planner lifts covered/
|
||||
# backstop edges from). UNCONDITIONAL — must NOT live in §4.5 Check AI-SPEC, which is skipped
|
||||
# Resolve the phase SPEC (carries the ## Edge Coverage section the planner lifts resolved
|
||||
# edges from). UNCONDITIONAL — must NOT live in §4.5 Check AI-SPEC, which is skipped
|
||||
# on non-AI phases; gating it there silently starves the planner of the SPEC (#550 review).
|
||||
# Glob the plain phase SPEC, excluding the -AI-SPEC.md / -UI-SPEC.md variants.
|
||||
PHASE_DIR_FOR_SPEC=$(_gsd_field "$INIT" phase_dir)
|
||||
@@ -703,7 +703,7 @@ Planner prompt:
|
||||
- {reviews_path} (Cross-AI Review Feedback - if --reviews; actionable findings must be incorporated or explicitly deferred/rejected in PLAN.md)
|
||||
- {AI_SPEC_PATH} (AI Design Contract — framework and evaluation strategy, if exists)
|
||||
- {UI_SPEC_PATH} (UI Design Contract — visual/interaction specs, if exists)
|
||||
- {SPEC_PATH} (Phase SPEC — carries the ## Edge Coverage section to lift covered/backstop edges from, if exists)
|
||||
- {SPEC_PATH} (Phase SPEC — carries the ## Edge Coverage section to lift resolved edges from, if exists)
|
||||
- {SPIKE_FINDINGS_PATH} (Spike Findings — validated patterns, constraints, landmines from experiments, if exists)
|
||||
- {SKETCH_FINDINGS_PATH} (Sketch Findings — validated design decisions, CSS patterns, visual direction, if exists)
|
||||
- {API_SURFACE_PATH} (API Surface — HINT ONLY, when intel capability is active; see <intel_surface_hint> below)
|
||||
@@ -775,9 +775,9 @@ Output consumed by /gsd:execute-phase. Plans need:
|
||||
- Tasks in XML format with read_first and acceptance_criteria fields (MANDATORY on every task)
|
||||
- Verification criteria
|
||||
- must_haves for goal-backward verification
|
||||
- If the SPEC has an `## Edge Coverage` section, lift every `covered` edge's acceptance criterion into `must_haves.truths` as a plain string, and every `backstop` edge **as a structured flat-scalar marker** — an object item `{ statement: <the check>, verification: backstop }`, NOT a prose note (the verifier branches deterministically on the `verification: backstop` field; a parenthetical is unparseable — the #1110 fragility). Use a flat scalar `verification:` continuation key, never a nested object (ADR-550 #1278). At verify time a `backstop` truth the verifier cannot confirm with explicit evidence abstains → `human_needed` (reason `insufficient_spec`), never a silent pass (#1154; see `references/honest-verifier.md`). `unresolved` edges are explicit assumptions — surface them in the plan, do not silently drop them. **Otherwise** (`EDGE_ABSENT`): apply the SAME lift to the fallback report `{COVERAGE}` (per §C of `references/specless-probe-fallback.md`); a SPEC-supplied section is never re-run.
|
||||
- If the SPEC has an `## Edge Coverage` section, lift every resolved (verification: explicit) edge's acceptance criterion into `must_haves.truths` as a plain string, and every resolved (verification: backstop) edge **as a structured flat-scalar marker** — an object item `{ statement: <the check>, verification: backstop }`, NOT a prose note (the verifier branches deterministically on the `verification: backstop` field; a parenthetical is unparseable — the #1110 fragility). Use a flat scalar `verification:` continuation key, never a nested object (ADR-550 #1278). At verify time a `backstop` truth the verifier cannot confirm with explicit evidence abstains → `human_needed` (reason `insufficient_spec`), never a silent pass (#1154; see `references/honest-verifier.md`). `unresolved` edges are explicit assumptions — surface them in the plan, do not silently drop them. **Otherwise** (`EDGE_ABSENT`): apply the SAME lift to the fallback report `{COVERAGE}` (per §C of `references/specless-probe-fallback.md`); a SPEC-supplied section is never re-run.
|
||||
- If the SPEC has a `## Prohibitions` section, lift every resolved prohibition into the `must_haves.prohibitions:` sibling block (NOT `truths` — ADR-550 D3) with `statement`+`status`+`verification`, via the single `projectProhibitions` serializer (Hyrum — no second serializer); unresolved -> flagged assumptions, don't drop; never put a must-NOT under `truths`. **Otherwise** (`PROHIB_ABSENT`), author the recalled prohibitions into the SAME block via the SAME `projectProhibitions` contract but **descriptor-less** (no `check_*`) so each disposes flagged-unverified; never auto-dismiss. Section-level precedence + no-silent-drop equality apply (§C).
|
||||
- If a `-UI-SPEC.md` exists (resolved above as `UI_SPEC_PATH`) with a `## UI Considerations` section, lift it by the **identical rule** as `## Edge Coverage` above — `covered` → `must_haves.truths` string, `backstop` → flat scalar `{ statement, verification: backstop }`, `unresolved` → explicit planner assumption (no new verb — ADR-550 #1278/#1154; #1867). Read it from `UI_SPEC_PATH` (the SPEC glob excludes `-UI-SPEC.md`).
|
||||
- If a `-UI-SPEC.md` exists (resolved above as `UI_SPEC_PATH`) with a `## UI Considerations` section, lift it by the **identical rule** as `## Edge Coverage` above — resolved (explicit) → `must_haves.truths` string, resolved (backstop) → flat scalar `{ statement, verification: backstop }`, `unresolved` → explicit planner assumption (no new verb — ADR-550 #1278/#1154; #1867). Read it from `UI_SPEC_PATH` (the SPEC glob excludes `-UI-SPEC.md`).
|
||||
- **"Artifacts this phase produces" section (MANDATORY)** — list every symbol this phase creates: decorators, classes, functions, CLI flags, struct/dataclass fields, new file paths. The plan-review-convergence source-grounding pass reads this section to exclude newly-created symbols from drift verification; omitting it causes new symbols to be flagged for acknowledgement.
|
||||
</downstream_consumer>
|
||||
|
||||
@@ -823,8 +823,8 @@ Every task MUST include these fields — they are NOT optional:
|
||||
- [ ] Waves assigned for parallel execution
|
||||
- [ ] must_haves derived from phase goal
|
||||
- [ ] Every PLAN.md includes an "Artifacts this phase produces" section listing symbols created by this phase (decorators, classes, functions, CLI flags, struct/dataclass fields, new file paths)
|
||||
- [ ] Every SPEC ## Edge Coverage covered/backstop edge is represented in a plan's must_haves (no silent drops)
|
||||
- [ ] Every UI-SPEC ## UI Considerations covered/backstop consideration is represented in a plan's must_haves (no silent drops)
|
||||
- [ ] Every SPEC ## Edge Coverage resolved edge is represented in a plan's must_haves (no silent drops)
|
||||
- [ ] Every UI-SPEC ## UI Considerations resolved consideration is represented in a plan's must_haves (no silent drops)
|
||||
- [ ] Every SPEC ## Prohibitions resolved item is represented in a plan's must_haves.prohibitions (no silent drops)
|
||||
</quality_gate>
|
||||
```
|
||||
|
||||
@@ -251,7 +251,8 @@ if ! node -e 'const a=require(process.argv[1]);if(!Array.isArray(a)||a.length===
|
||||
exit 1
|
||||
fi
|
||||
# Invoke the compiled engine and CAPTURE its report — it computes which categories apply per
|
||||
# requirement. The covered/backstop/dismissed/unresolved rows in $COVERAGE drive the
|
||||
# requirement. The resolved/dismissed/unresolved rows in $COVERAGE (resolved items carry
|
||||
# verification: explicit|backstop) drive the
|
||||
# resolution loop below (canonical taxonomy compute, NOT LLM re-derivation from prose).
|
||||
# The engine FAILS CLOSED (exit 2) on an invalid authored shape or bad input — so the capture
|
||||
# MUST be exit-checked. A bare `COVERAGE=$(node …)` swallows that exit code, leaves $COVERAGE
|
||||
@@ -288,14 +289,15 @@ an empty `## Edge Coverage` section after explicit confirmation.
|
||||
For each Requirement gathered so far:
|
||||
1. Classify its shape and raise only applicable edge categories (relevance filter — see
|
||||
the taxonomy in the reference). Reuse any edges the Round-4 Failure Analyst already
|
||||
surfaced as pre-`covered`.
|
||||
surfaced as pre-resolved.
|
||||
2. For each raised category, propose a CONCRETE candidate edge (not "consider
|
||||
boundaries" — e.g. "R2 merges intervals; what about `[[1,2],[2,3]]` that only touch?").
|
||||
3. Resolve each with the user (AskUserQuestion; text mode → numbered list):
|
||||
- **Specify it** → write a new pass/fail line into Acceptance Criteria AND mark the
|
||||
edge `covered`.
|
||||
edge `resolved` with `verification: explicit`.
|
||||
- **Dismiss (reason)** → mark `dismissed` with a required non-empty reason.
|
||||
- **Backstop with a test** → mark `backstop`; note "held-out edge test" for plan-phase.
|
||||
- **Backstop with a test** → mark `resolved` with `verification: backstop`; note
|
||||
"held-out edge test" for plan-phase.
|
||||
- **Defer** → leave `unresolved`.
|
||||
- An `unclassified` row (probe `unclassified — review manually`) means the requirement's
|
||||
prose matched no shape cue (#1110) — treat it like any other candidate (**Specify**,
|
||||
@@ -311,13 +313,14 @@ For each Requirement gathered so far:
|
||||
- On "anyway": write SPEC.md with those rows marked `⚠ Edge unresolved — planner must
|
||||
treat as assumption`.
|
||||
|
||||
**`--auto` mode:** auto-`covered` where a defensible acceptance criterion can be written;
|
||||
otherwise auto-`backstop` (never auto-dismiss — a wrong dismissal is the exact silent
|
||||
failure being eliminated). Log: `[auto] edge coverage: C covered, B backstop, U unresolved`.
|
||||
**`--auto` mode:** auto-`resolved` (verification: explicit) where a defensible acceptance
|
||||
criterion can be written; otherwise auto-`resolved` (verification: backstop) (never
|
||||
auto-dismiss — a wrong dismissal is the exact silent failure being eliminated). Log:
|
||||
`[auto] edge coverage: E explicit, B backstop, U unresolved`.
|
||||
|
||||
**`unclassified` exception (#1110):** `--auto` leaves an `unclassified` candidate
|
||||
**`unresolved`** (the soft gate surfaces it as a flagged planner assumption) — it never
|
||||
auto-`backstop`s it. A missing shape is not evidence an edge exists, so minting a held-out
|
||||
auto-resolves it with `verification: backstop`. A missing shape is not evidence an edge exists, so minting a held-out
|
||||
edge obligation on a requirement that may be genuinely edge-free would be a false claim and
|
||||
risks a vacuous edge test. Leaving it `unresolved` keeps the zero-cue requirement visible
|
||||
(never a silent drop) without fabricating an edge — which is exactly #1110's purpose: surface
|
||||
@@ -425,7 +428,7 @@ downstream rather than blocking authoring.
|
||||
|
||||
Use the SPEC.md template from @~/.claude/gsd-core/templates/spec.md.
|
||||
|
||||
- Populate the **Edge Coverage** section from Step 5.5 (covered/dismissed/backstop/unresolved rows).
|
||||
- Populate the **Edge Coverage** section from Step 5.5 (resolved/dismissed/unresolved rows; resolved items carry `verification: explicit|backstop`).
|
||||
- Populate the **Prohibitions** section from Step 5.6 (resolved/dismissed/unresolved rows with the test|judgment tier).
|
||||
|
||||
**Requirements for every requirement entry:**
|
||||
|
||||
@@ -388,8 +388,8 @@ SIGNAL, not proof the element is only that kind — the confirm step, not the he
|
||||
coverage sound.
|
||||
|
||||
**Resolution loop** (mirror spec-phase 5.5): resolve each applicable consideration via
|
||||
AskUserQuestion — **Specify** (→ `covered`, write a concrete truth) / **Dismiss (reason required)** /
|
||||
**Backstop** (a held-out/visual UI-state test) / **Defer** (→ `unresolved`). An `unclassified` row is
|
||||
AskUserQuestion — **Specify** (→ `resolved`, verification: explicit; write a concrete truth) / **Dismiss (reason required)** /
|
||||
**Backstop** (→ `resolved`, verification: backstop; a held-out/visual UI-state test) / **Defer** (→ `unresolved`). An `unclassified` row is
|
||||
a manual-review nudge, not a hard block. Text mode (`workflow.text_mode` / `--text`) → numbered lists.
|
||||
|
||||
**Kind-confirmation under `--auto`.** The propose-then-confirm step above is an AskUserQuestion, so
|
||||
@@ -402,17 +402,18 @@ recover a kind that was never surfaced, so recall is fixed HERE, at kind-confirm
|
||||
resolution runs.
|
||||
|
||||
**`--auto` mode (two layers).** The adapter's `autoResolve` is the CODE floor: every applicable
|
||||
consideration auto-`backstop`s (carrying the taxonomy question as its resolution) and an
|
||||
`unclassified` candidate stays `unresolved` — it NEVER auto-`dismiss`es and never auto-backstops an
|
||||
unclassified item (#1110). On top of that floor the workflow MAY upgrade an item to `covered` when a
|
||||
consideration auto-resolves with `verification: backstop` (carrying the taxonomy question as its
|
||||
resolution) and an `unclassified` candidate stays `unresolved` — it NEVER auto-`dismiss`es and never
|
||||
auto-resolves an unclassified item with backstop (#1110). On top of that floor the workflow MAY
|
||||
upgrade an item to `resolved` (verification: explicit) when a
|
||||
defensible acceptance criterion can be written (the same judgment spec-phase 5.5 applies in prose).
|
||||
An auto `--auto` run therefore leaves un-upgraded backstops as `backstop`: at verify time each one
|
||||
An auto `--auto` run therefore leaves un-upgraded items as `resolved` (verification: backstop): at verify time each one
|
||||
with no wired evidence routes to `insufficient_spec → human_needed` — never a silent pass (#1154).
|
||||
That surfacing is the intended honest-verifier behavior, not over-flagging.
|
||||
|
||||
**Write-back.** Populate a `## UI Considerations` section in the UI-SPEC from the resolved
|
||||
considerations, in the format the shipped plan-phase `## UI Considerations` lift rule reads:
|
||||
`covered` → a truth string; `backstop` → a flat scalar `{ statement, verification: backstop }`;
|
||||
`resolved` (explicit) → a truth string; `resolved` (backstop) → a flat scalar `{ statement, verification: backstop }`;
|
||||
`unresolved` → an explicit `⚠ unresolved — planner must treat as assumption` row. Empty-state and
|
||||
error-state COPY stays in `## Copywriting Contract` — the considerations section covers shape-rooted
|
||||
STATE coverage and REFERENCES those rows rather than restating the copy (de-dup). IDEMPOTENT: if a
|
||||
|
||||
Reference in New Issue
Block a user