feat(#1820): spec-optional predicate rail — author probe predicates into must_haves when SPEC omits them
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
"workflow.plan_bounce_script",
|
||||
"workflow.plan_bounce_passes",
|
||||
"workflow.plan_chunked",
|
||||
"workflow.specless_probe_fallback",
|
||||
"workflow.plan_review_convergence",
|
||||
"code_quality.fallow.enabled",
|
||||
"code_quality.fallow.scope",
|
||||
|
||||
@@ -269,6 +269,7 @@ Set via `workflow.*` namespace in config.json (e.g., `"workflow": { "research":
|
||||
| `workflow.mvp_mode` | boolean | `false` | `true`, `false` | Persist the MVP-mode flag in config so every phase defaults to MVP framing without requiring `--mvp` on the CLI. Resolved via the chain: `--mvp` CLI flag → ROADMAP.md `**Mode:** mvp` field → this config value → `false`. When `true`, the planner, executor, verifier, and discovery surfaces (progress, stats, graphify) all treat the phase as an MVP vertical slice (UI → API → DB) of one user-visible capability. |
|
||||
| `workflow.context_guard_mode` | string | `"warn"` | `"auto"`, `"warn"`, `"off"` | Context exhaustion guard mode for `execute-phase`. Before each wave, the orchestrator self-assesses context pressure using degradation signals from `context-budget.md`. `"warn"` (default): emit a warning and recommend `/gsd:pause-work` when POOR tier is detected. `"auto"`: automatically invoke `/gsd:pause-work` before the next wave when POOR tier is detected. `"off"`: disable the guard. The guard is heuristic — no programmatic context-% API exists. |
|
||||
| `workflow.plan_chunked` | boolean | `false` | `true`, `false` | Enable chunked planning mode. When `true`, the plan-phase orchestrator splits the single long-lived planner Task into a short outline Task followed by N short per-plan Tasks (~3–5 min each). Each plan is committed individually for crash resilience. Particularly useful on Windows where long-lived Tasks may hang on stdio. Also activated by the `--chunked` flag. |
|
||||
| `workflow.specless_probe_fallback` | boolean | `true` | `true`, `false` | Gate the SPEC-less probe fallback in `plan-phase`. When `true` (default), a phase that did not supply a `## Edge Coverage` / `## Prohibitions` SPEC section (header absent or present-but-empty) runs the existing probe protocol — the deterministic `edge-probe.cjs` for edges and an in-planner LLM recall pass for prohibitions — and authors the resulting predicates into PLAN.md `must_haves` (section-level precedence: a SPEC-supplied section is never re-run or overwritten). When `false`, the fallback is skipped but the skip is recorded: plan-phase emits a visible "probe fallback disabled" marker, never a silent skip. |
|
||||
| `workflow.code_review_command` | string\|null | `null` | Any shell command | External code-review command integrated into `/gsd:ship`. The diff is piped to the command via stdin; the command must output JSON with a `verdict` field (`"APPROVED"` or `"REVISE"`). Non-zero exit or `"REVISE"` verdict blocks the ship workflow. When unset, the built-in review flow runs. Example: `my-review-tool --review`. |
|
||||
| `workflow.inline_plan_threshold` | number | `2` | `0`–`10` | Plans with ≤N tasks execute inline instead of spawning a subagent |
|
||||
| `workflow.code_review` | boolean | `true` | `true`, `false` | Enable built-in code review step in the ship workflow |
|
||||
|
||||
172
gsd-core/references/specless-probe-fallback.md
Normal file
172
gsd-core/references/specless-probe-fallback.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# Spec-less Probe Fallback — protocol
|
||||
|
||||
Lazy-loaded by `workflows/plan-phase.md` step 7.95 (the gate) and the `<specless_probe_fallback>`
|
||||
planner block. When a phase SPEC did NOT supply `## Edge Coverage` / `## Prohibitions`, plan-phase
|
||||
runs the same probe protocol the SPEC path uses and authors the predicates into PLAN.md `must_haves`
|
||||
(ADR-857 Phase 6 — the *else branch* of the `<downstream_consumer>` SPEC-conditional lift). This is
|
||||
core workflow-body substrate — NOT the `PLAN_PRE_HOOKS_JSON contribution into planner` capability rail
|
||||
(D-03). Section absence is detected by the shared `spec-section` helper in the gate; this file holds the
|
||||
*run-the-probe* half so the capped plan-phase.md stays lean (#717/#1074 budget).
|
||||
|
||||
## 0. Gate — toggle + per-section absence (run first, in the orchestrator)
|
||||
|
||||
Reads the default-ON toggle and computes `EDGE_ABSENT` / `PROHIB_ABSENT` via the shared `spec-section`
|
||||
helper; records a VISIBLE skip when disabled or when the phase has no requirement IDs (never a silent
|
||||
skip, never a hard-fail). Sets `SPECLESS_FALLBACK`, `EDGE_ABSENT`, `PROHIB_ABSENT`, and
|
||||
`SPECLESS_FALLBACK_DISABLED` for §A and the planner prompt.
|
||||
|
||||
```bash
|
||||
# Toggle defaults ON (D-04 / RAIL-05): any value other than literal "false" enables.
|
||||
SPECLESS_CFG=$(gsd_run query config-get workflow.specless_probe_fallback 2>/dev/null || echo "true")
|
||||
SPECLESS_FALLBACK=true; [[ "$SPECLESS_CFG" == "false" ]] && SPECLESS_FALLBACK=false
|
||||
|
||||
# Per-section absence (D-05 / RAIL-03): "not supplied" = header absent OR present-but-empty. The
|
||||
# shared, tested `spec-section` helper (src/spec-section.cts -> bin/lib/spec-section.cjs) is the SINGLE
|
||||
# source of truth for the canonical SPEC headings (suffix-tolerant) and table-row counting, replacing
|
||||
# ad-hoc awk (contract pinned by tests/spec-section.test.cjs). Resolve via the edge-probe install-dir
|
||||
# idiom; build only in a source checkout, else fail loud (never silently mis-detect).
|
||||
_GSD_RT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
||||
_gsd_lib() { for _d in "$_GSD_RT/gsd-core/bin/lib" "$_GSD_RT/bin/lib" "$_GSD_RT/.claude/bin/lib" "$HOME/.claude/gsd-core/bin/lib" "$HOME/.claude/bin/lib"; do [ -f "$_d/$1" ] && { echo "$_d/$1"; return; }; done; }
|
||||
SPEC_SECTION_JS=$(_gsd_lib spec-section.cjs)
|
||||
if [ -z "$SPEC_SECTION_JS" ] && [ -f "$_GSD_RT/tsconfig.build.json" ] && [ -f "$_GSD_RT/src/spec-section.cts" ]; then
|
||||
npm --prefix "$_GSD_RT" run build:lib 2>/dev/null || true; SPEC_SECTION_JS=$(_gsd_lib spec-section.cjs)
|
||||
fi
|
||||
[ -n "$SPEC_SECTION_JS" ] || { echo "ERROR: spec-section.cjs not found - reinstall GSD or run build:lib." >&2; exit 1; }
|
||||
# supplied => header present AND >=1 row; missing $SPEC_FILE => supplied:false => fallback fires.
|
||||
EDGE_ABSENT=1; node "$SPEC_SECTION_JS" "$SPEC_FILE" edges 2>/dev/null | grep -q '"supplied":true' && EDGE_ABSENT=0
|
||||
PROHIB_ABSENT=1; node "$SPEC_SECTION_JS" "$SPEC_FILE" prohibitions 2>/dev/null | grep -q '"supplied":true' && PROHIB_ABSENT=0
|
||||
|
||||
# Disabled path - record the skip VISIBLY, never silently (RAIL-05 / PROH-4); the note rides into the
|
||||
# planner prompt (Step 8) so the plan records that no probe predicates were generated.
|
||||
SPECLESS_FALLBACK_DISABLED=""
|
||||
if [[ "$SPECLESS_FALLBACK" != "true" ]]; then
|
||||
echo "WARNING: probe fallback disabled (workflow.specless_probe_fallback=false); skip recorded, not silent." >&2
|
||||
SPECLESS_FALLBACK_DISABLED="probe fallback disabled (workflow.specless_probe_fallback=false): no probe-derived predicates generated for SPEC-absent sections this run."
|
||||
fi
|
||||
|
||||
# Nothing-to-probe guard: the fallback derives predicates from requirement TEXT, so zero requirement
|
||||
# IDs => nothing to probe => skip VISIBLY (like the disabled path), NOT a hard-fail. Prevents a
|
||||
# no-SPEC + no-requirements phase from aborting under the default-ON fallback. The orchestrator
|
||||
# substitutes {phase_req_ids}; empty/whitespace/TBD => no requirements. (A still-literal token is
|
||||
# non-empty, so an unsubstituted run correctly hits the reference's fail-loud guard instead.)
|
||||
SPECLESS_REQ_IDS="{phase_req_ids}"
|
||||
if [[ "$SPECLESS_FALLBACK" == "true" ]] && { [ -z "${SPECLESS_REQ_IDS// /}" ] || [ "${SPECLESS_REQ_IDS}" = "TBD" ]; }; then
|
||||
echo "info: spec-less probe fallback: phase has no requirement IDs - nothing to probe; skipping (visible skip)." >&2
|
||||
SPECLESS_FALLBACK=false
|
||||
SPECLESS_FALLBACK_DISABLED="spec-less probe fallback skipped: phase has no requirement IDs to probe (visible skip)."
|
||||
fi
|
||||
```
|
||||
|
||||
## A. Edge probe (deterministic) — run when `SPECLESS_FALLBACK=true` AND `EDGE_ABSENT=1`
|
||||
|
||||
Mirrors spec-phase Step 5.5 verbatim; the ONLY divergence (D-02) is sourcing `$REQS_JSON` from the
|
||||
phase requirement IDs (`{phase_req_ids}`) instead of a SPEC interview. Leave `$COVERAGE` empty when
|
||||
`EDGE_ABSENT=0` — a SPEC-supplied section is never re-run (section-level precedence).
|
||||
|
||||
```bash
|
||||
# Resolve the compiled edge-probe.cjs against the GSD install dir via RUNTIME_DIR (#448) — NOT the
|
||||
# consuming project's git root — falling back to git toplevel / $HOME/.claude (spec-phase.md:198 idiom).
|
||||
_GSD_RT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
||||
EDGE_PROBE_JS=$(for _c in \
|
||||
"$_GSD_RT/gsd-core/bin/lib/edge-probe.cjs" "$_GSD_RT/bin/lib/edge-probe.cjs" \
|
||||
"$_GSD_RT/.claude/bin/lib/edge-probe.cjs" "$HOME/.claude/gsd-core/bin/lib/edge-probe.cjs" \
|
||||
"$HOME/.claude/bin/lib/edge-probe.cjs"; do [ -f "$_c" ] && { echo "$_c"; break; }; done)
|
||||
# Build ONLY inside a verified GSD source checkout; --prefix pins npm so we never trigger the
|
||||
# consuming project's build:lib. Never silent-skip (RR-04) — fail loud if unresolvable.
|
||||
if [ -z "$EDGE_PROBE_JS" ]; then
|
||||
if [ -f "$_GSD_RT/tsconfig.build.json" ] && [ -f "$_GSD_RT/src/edge-probe.cts" ]; then
|
||||
npm --prefix "$_GSD_RT" run build:lib 2>/dev/null || true
|
||||
EDGE_PROBE_JS=$(for _c in \
|
||||
"$_GSD_RT/gsd-core/bin/lib/edge-probe.cjs" "$_GSD_RT/bin/lib/edge-probe.cjs" \
|
||||
"$_GSD_RT/.claude/bin/lib/edge-probe.cjs" "$HOME/.claude/gsd-core/bin/lib/edge-probe.cjs" \
|
||||
"$HOME/.claude/bin/lib/edge-probe.cjs"; do [ -f "$_c" ] && { echo "$_c"; break; }; done)
|
||||
fi
|
||||
[ -n "$EDGE_PROBE_JS" ] || { echo "ERROR: edge-probe.cjs not found — reinstall GSD or run \`npm run build:lib\`." >&2; exit 1; }
|
||||
fi
|
||||
|
||||
# THE ONE DIVERGENCE (D-02): source requirements from THIS phase. Populate the heredoc from
|
||||
# {phase_req_ids}, pulling each requirement's text from REQUIREMENTS.md: {"id","text","shapes"?}.
|
||||
# mktemp suffix trick is BSD/GNU portable (#1520).
|
||||
REQS_JSON=$(mktemp "${TMPDIR:-/tmp}/edge-probe-reqs-XXXXXX") && mv "$REQS_JSON" "${REQS_JSON}.json" && REQS_JSON="${REQS_JSON}.json" || exit 1
|
||||
cat > "$REQS_JSON" <<'JSON'
|
||||
[
|
||||
{ "id": "R1", "text": "<replace: requirement text from REQUIREMENTS.md for each {phase_req_ids} id>" }
|
||||
]
|
||||
JSON
|
||||
# Guard — fail loud on empty/invalid array OR a still-present `<replace:>` placeholder (forgotten
|
||||
# substitution would yield a bogus report). Never a silent no-op.
|
||||
if ! node -e 'const a=require(process.argv[1]);if(!Array.isArray(a)||a.length===0)process.exit(1);if(a.some(r=>typeof r.text!=="string"||!r.text.trim()||r.text.includes("<replace:")))process.exit(1)' "$REQS_JSON" 2>/dev/null; then
|
||||
echo "ERROR: edge-probe requirements JSON is empty/invalid or still holds the <replace: …> placeholder — populate \$REQS_JSON from {phase_req_ids} before running." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Invoke + CAPTURE, exit-checked (engine FAILS CLOSED exit 2 on bad shape; a bare COVERAGE=$(node …)
|
||||
# would swallow it and fall through to prose re-derivation = fail-OPEN).
|
||||
if ! COVERAGE=$(node "$EDGE_PROBE_JS" "$REQS_JSON"); then
|
||||
rm -f "$REQS_JSON"
|
||||
echo "ERROR: edge-probe engine failed (invalid shapes or bad input) — fix the requirement(s); never proceed with empty coverage." >&2
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$REQS_JSON"
|
||||
# Exit-0-but-garbage guard: report must parse as JSON with { items[], coverage{} }.
|
||||
if ! printf '%s' "$COVERAGE" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{let r;try{r=JSON.parse(s)}catch{process.exit(1)}if(!r||!Array.isArray(r.items)||typeof r.coverage!=="object"||r.coverage===null)process.exit(1)})'; then
|
||||
echo "ERROR: edge-probe produced an unparseable/malformed coverage report — refusing to proceed." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Zero-applicable guard: surface a likely classification miss loudly (spec-phase 5.5:277 shape).
|
||||
APPLICABLE=$(printf '%s' "$COVERAGE" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{let n=0;try{n=JSON.parse(s).coverage.applicable}catch{n=0}process.stdout.write(String(n))})')
|
||||
if [ "$APPLICABLE" = "0" ]; then
|
||||
echo "WARNING: edge-probe proposed ZERO applicable edges across all phase requirements — likely a classification miss, not a genuinely edge-free phase. Do NOT silently write an empty fallback Edge Coverage." >&2
|
||||
fi
|
||||
```
|
||||
|
||||
**Edge `--auto` resolution rules (reuse spec-phase 5.5 verbatim, D-06):** auto-`covered` where a
|
||||
defensible acceptance criterion can be written (→ a plain `must_haves.truths` string); else
|
||||
auto-`backstop` → author it as a **structured flat-scalar marker** `{ statement: <the check>,
|
||||
verification: backstop }` in `must_haves.truths`, NOT a prose note (the verifier branches
|
||||
deterministically on the `verification: backstop` field; a parenthetical is unparseable — the #1110
|
||||
fragility; flat scalar `verification:` key, never a nested object, ADR-550 #1278). A `backstop` truth
|
||||
the verifier cannot confirm with explicit evidence abstains → `human_needed` (reason
|
||||
`insufficient_spec`), never a silent pass (#1154; `references/honest-verifier.md`). **Never
|
||||
auto-dismiss** (a wrong dismissal is the exact silent failure this eliminates). An `unclassified` row
|
||||
stays **`unresolved`** (#1110) — never auto-`backstop`ped — and is surfaced to the planner as a flagged
|
||||
assumption. Pass `$COVERAGE` (+ the gate's `$SPECLESS_FALLBACK_DISABLED` note) into the gsd-planner
|
||||
prompt (Step 8). When `EDGE_ABSENT=0`, `$COVERAGE` is empty and this does not run.
|
||||
|
||||
## B. Prohibition recall (LLM prose pass) — run when `PROHIB_ABSENT=1`
|
||||
|
||||
There is NO compiled prohibition engine and NO `node` invocation (ADR-550 D7b) — the gsd-planner runs
|
||||
this in-prompt. Full two-stage protocol, canon-referral rule, and status×verification schema live in
|
||||
`~/.claude/gsd-core/references/prohibition-probe.md` (do not inline it). Summary:
|
||||
|
||||
- **Stage 1 — Recall (adversarial).** Per requirement: *"What could this feature silently become that
|
||||
the author would NOT want, but the spec does not forbid?"* Over-produce (~10 raw must-NOT candidates).
|
||||
- **Stage 2 — Precision.** DROP routine-engineering (normal correctness/hygiene — owned by the edge
|
||||
probe or code review); KEEP values / safety / ethics (~2–3 survive).
|
||||
- **Canon-referral drop (ADR-550 D6).** A kept candidate that is canon security/compliance (OWASP /
|
||||
prototype-pollution / path-traversal / injection / GDPR / generic fairness) is NOT minted — emit a
|
||||
one-line breadcrumb and DROP it.
|
||||
|
||||
**Fallback `--auto` divergence (D-06 / RAIL-04 / PROH-1):** author each kept prohibition as
|
||||
**flagged-unverified with NO wired-check descriptor**. NEVER write `check_kind` / `check_target` /
|
||||
`check_rule` / `check_violation_fixture` / `check_clean_fixture` — there is no human to wire/verify a
|
||||
check, and a descriptor-less item is what keeps it fail-closed (it disposes
|
||||
`{status:'unverified', flagged:true}` downstream via the reused `dispositionForProhibition`). **Never
|
||||
auto-dismiss**; never fabricate a check path. Surface any `unresolved` prohibition as a flagged
|
||||
assumption — never a silent drop.
|
||||
|
||||
## C. Authoring (the `<downstream_consumer>` else-branch)
|
||||
|
||||
Author the fallback report into `must_haves` with the SAME lift the SPEC path uses — only the source
|
||||
changes (the fallback report, not the SPEC):
|
||||
|
||||
- **Edges →** every `covered` edge's acceptance criterion → `must_haves.truths` as a plain string;
|
||||
every `backstop` edge → `must_haves.truths` as a structured `{ statement, verification: backstop }`
|
||||
marker (NOT prose; #1110/#1278), which abstains → `human_needed` at verify time when unconfirmed
|
||||
(#1154); every `unresolved`/`unclassified` row → an explicit flagged assumption (never a silent drop).
|
||||
- **Prohibitions →** every kept prohibition → the `must_haves.prohibitions:` sibling block (NOT
|
||||
`truths`, ADR-550 D3) via the single `projectProhibitions` serializer (Hyrum — no second
|
||||
serializer), authored **descriptor-less** (no `check_*` scalar) so each disposes flagged-unverified.
|
||||
- **Section-level precedence:** a SPEC-supplied section is never re-run or overwritten — exactly one
|
||||
producer per section.
|
||||
- **No-silent-drop equality:** for each section, (# probe-surfaced items) == (# authored into
|
||||
`must_haves` + # surfaced as flagged assumptions).
|
||||
@@ -693,6 +693,19 @@ echo "✓ API surface regenerated: ${API_SURFACE_PATH}" # injected into step 8
|
||||
|
||||
Continue to step 8.
|
||||
|
||||
## 7.95. Spec-less Probe Fallback (gate)
|
||||
|
||||
When the SPEC did not supply `## Edge Coverage` / `## Prohibitions`, plan-phase runs the probe protocol
|
||||
and authors the predicates into PLAN.md `must_haves` (ADR-857 Phase 6 — the *else branch* of the
|
||||
`<downstream_consumer>` lift below). Core workflow-body substrate, not a capability rail (D-03). Runs
|
||||
after `$SPEC_FILE` (Step 7), before the gsd-planner spawn (Step 8).
|
||||
|
||||
**Read and run** the gate + edge probe in `~/.claude/gsd-core/references/specless-probe-fallback.md`
|
||||
(§0 default-ON toggle + per-section absence via the `spec-section` helper, visibly skipping when
|
||||
disabled or no requirement IDs; §A deterministic edge probe → `$COVERAGE` when `EDGE_ABSENT`; §B
|
||||
prohibition recall in the planner). Pass `$COVERAGE` and `$SPECLESS_FALLBACK_DISABLED` into Step 8.
|
||||
|
||||
|
||||
## 8. Spawn gsd-planner Agent
|
||||
|
||||
Display banner:
|
||||
@@ -769,6 +782,22 @@ ${MVP_MODE === 'true' ? `
|
||||
**MVP Mode is ENABLED.** Read `~/.claude/gsd-core/references/planner-mvp-mode.md` now and follow its vertical-slice planning rules. Each plan must deliver a complete vertical slice — thin end-to-end functionality rather than horizontal layers.
|
||||
</mvp_mode_active>
|
||||
` : ''}
|
||||
|
||||
<specless_probe_fallback>
|
||||
**Spec-less probe fallback** (only when step 7.95 set `EDGE_ABSENT` and/or `PROHIB_ABSENT`). The SPEC
|
||||
omitted that section — author its predicates into `must_haves` via the `<downstream_consumer>`
|
||||
else-branch below, per §A/§B/§C of `~/.claude/gsd-core/references/specless-probe-fallback.md`
|
||||
(descriptor-less prohibitions, never auto-dismiss, no silent drops).
|
||||
|
||||
Edge coverage report (`$COVERAGE`, present when `EDGE_ABSENT`):
|
||||
|
||||
```json
|
||||
{COVERAGE}
|
||||
```
|
||||
${SPECLESS_FALLBACK_DISABLED ? `
|
||||
**⚠ ${SPECLESS_FALLBACK_DISABLED}** — record this in the plan (a visible, recorded choice); do not generate probe predicates this run.
|
||||
` : ''}
|
||||
|
||||
</planning_context>
|
||||
|
||||
<downstream_consumer>
|
||||
@@ -777,8 +806,8 @@ 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.
|
||||
- If the SPEC has a `## Prohibitions` section, lift every resolved prohibition into the `must_haves.prohibitions:` sibling block (NOT `truths` — ADR-550 D3) carrying `statement` + `status` + `verification`; unresolved prohibitions are explicit assumptions — surface them in the plan, do not silently drop them. A prohibition is a must-NOT (negative) check that belongs in its own `must_haves.prohibitions` block. Never place a must-NOT under `must_haves.truths` — that block keeps positive-observable semantics only.
|
||||
- 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 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).
|
||||
- **"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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user