Spec backfill
Backfill @spec annotations on existing code for an APPROVED spec (or --all specs)From its SKILL.md
npx -y skills add telefrek/vallorcine --skill spec-backfillAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
26.5 KB, ~6.9k tokens by cl100k_base, as published. Nobody here has run it
/spec-backfill
Walk every requirement of an APPROVED spec that has zero @spec annotations
in code, present likely enforcement sites for each, and apply annotations
the user chooses. The catch-up tool for mature corpora authored before
@spec annotation enforcement (v0.16.5 / PR #67) was added.
Two modes:
/spec-backfill <spec-id>— walk one spec./spec-backfill --all— iterate every APPROVED spec in the manifest, running the per-spec walk against each. The catch-up tool for whole corpora (e.g. jlsm: 75 specs / 12 domains, mostly authored before enforcement existed).
When to use: APPROVED spec(s) whose requirements pre-date annotation
enforcement and which have uncovered R-ids. /curate annotation-drift
analysis routes here when a spec falls below 50% coverage.
Not for: active features mid-pipeline. The /feature-test and
/feature-implement substages already gate on annotation coverage; the
forward-enforcement gate is the right tool there. /spec-backfill is for
existing pre-enforcement code that no live feature touches.
Pre-flight
-
Verify
jqis installed:command -v jq >/dev/null 2>&1If missing, tell the user and stop.
-
Verify
.spec/registry/manifest.jsonexists. If not, tell the user to run/spec-initand stop. -
Determine mode from
$ARGUMENTS:--all(or-a) → corpus mode (jump to "Corpus mode" section below after pre-flight).- empty → ask the user which spec to backfill via AskUserQuestion.
Build the option list from APPROVED specs in the manifest (limit to
4 + Other; if more candidates exist, hint that
/spec-backfill --allcovers the corpus). - non-empty, not
--all→ treat as a literal spec-id and use it.
-
Read
rules/spec-annotation-protocol.md(already in your context as a project rule) — you must follow its comment-syntax-per-language and placement guidance when applying annotations below.
Phase 1 — Discover uncovered requirements
Run the trace primitive in --uncovered mode:
bash .claude/scripts/spec-trace.sh --uncovered <spec-id>
Output is a parseable list, one fully-qualified R-id per line on
stdout (e.g. auth.token-validation.R3); a count summary is on stderr.
Important — strip the <spec-id>. prefix before passing to downstream
scripts. spec-backfill-candidates.sh and spec-backfill-log.sh
both expect bare R-ids (e.g. R3), not fully-qualified ones. Pass
the FQ form and the candidate finder errors with "Requirement '...' not
found"; the log helpers' has-decision key never matches an annotated
row. The 2026-05-11 adversarial finding (CRIT 4) confirmed this caused
Phase 1's terminal-decision filter to silently no-op, re-walking
already-annotated requirements.
For each FQ R-id captured (e.g. auth.token-validation.R3), compute
the bare form via shell expansion: r_id="${fq_rid##*.}" (yields
R3). Use r_id for ALL subsequent spec-backfill-candidates.sh /
spec-backfill-log.sh invocations.
If output is empty: tell the user "spec is fully annotated — nothing to backfill" and stop.
If non-empty: capture the list and the count. Read .spec/backfill-log.md
(initialize with bash .claude/scripts/spec-backfill-log.sh init .spec/backfill-log.md if it does not exist) and filter the list down to
R-ids (bare form) that do NOT yet have a terminal decision (annotated
or waived). skipped rows from prior runs are NOT terminal — those
resurface by design.
Tell the user the plan in one or two sentences:
spec <id> has <N> uncovered requirement(s). <K> were skipped on prior
runs and will resurface; <M> are already annotated or waived in the log
and will be skipped. Walking <N - already-decided> now.
Phase 2 — Walk uncovered requirements
For each R-id remaining (in spec order):
2a. Surface the requirement text
Read the spec file (path resolved via spec_file_for_id). Locate the
matching ^R<n>[a-z]*(-…)?\. line under ## Requirements and extract the
requirement text (may span multiple lines until the next R-id).
2b. Find candidate sites
Run the candidate finder:
bash .claude/scripts/spec-backfill-candidates.sh <spec-id> <r-id>
Output is one row per candidate, ranked by token-overlap score:
<score>\t<rel-path>:<line>\t<truncated-context>
Stderr surfaces the requirement text and the extracted subject tokens for display. Read both. The candidate finder may return zero rows for very short or token-poor requirements — that is expected.
2c. Present and decide
Present the requirement text and top candidates to the user.
Build the AskUserQuestion options dynamically from the candidate rows. Show up to 4 candidates as labeled options; always include "Other (specify file:line)" and "Skip this R-id". Add "Waive (intentionally uncovered)" when the user signals at top of session that they want this option, or when a candidate set is empty.
R3 — The system must enforce token expiry by rejecting tokens whose
exp claim is in the past at validation time.
Subject tokens: TokenValidator, expiry, validate
Likely sites:
(a) src/auth/TokenValidator.java:78 (overlap: 3)
if (claims.getExpiry().isBefore(now)) {
(b) src/auth/TokenValidator.java:45 (overlap: 2)
public boolean validateExpiry(Claims claims) {
(c) test/auth/TokenValidatorTest.java:120 (overlap: 2)
@Test void expiredTokensRejected() {
Use AskUserQuestion with the constructed options. Do NOT prompt with prose ("Type a / b / c") — that does not stop generation; AskUserQuestion does.
2d. Apply the user's decision
Based on the choice:
-
Candidate selected — read the file, locate the chosen line, and insert a
@spec <spec-id>.<R-id>annotation in a comment ABOVE the line (not on the same line) using the comment syntax for that language. Perrules/spec-annotation-protocol.md:// @spec <ref>for C-family,# @spec <ref>for Python/Ruby/Bash,-- @spec <ref>for Lua/SQL,<!-- @spec <ref> -->for HTML/XML. If a sibling annotation already exists at that location, append the new ref to the existing comment rather than adding a separate line. Use Edit to apply.Then append to the log:
bash .claude/scripts/spec-backfill-log.sh append \ .spec/backfill-log.md "$(date +%F)" <spec-id> <r-id> annotated \ "<rel-path>:<line>" -
Other — ask the user via AskUserQuestion follow-up for the file:line. Validate the path exists. Apply annotation as above. Log as
annotatedwith the user-supplied location. -
Skip — append
skippedto the log with no location. Move on. The R-id will resurface on the next run. -
Waive — ask follow-up via AskUserQuestion for a one-line reason. Append
waivedwith the reason in the notes column. Waived R-ids do NOT resurface; the user has declared the requirement intentionally uncovered (e.g., aspirational, deprecated, enforced externally).
2e. Re-trace after each annotation (cheap correctness check)
After applying an annotated decision, the next loop iteration starts
with a stale picture of what is already covered. That is acceptable for
performance — the candidate finder still scores correctly because tokens
do not change. The end-of-session re-trace below catches any drift.
Phase 3 — Confirm coverage moved
After all R-ids are processed (decided or skipped), re-run:
bash .claude/scripts/spec-trace.sh --uncovered <spec-id>
Compute and report:
- How many R-ids were uncovered at start.
- How many are uncovered now.
- Of the difference: how many were
annotated, how manyskipped(will resurface), how manywaived.
Surface the report inline. Do NOT write a separate report file — the
.spec/backfill-log.md is the authoritative record.
If skipped count > 0, tell the user how to resume:
<K> requirement(s) were skipped and will resurface on rerun. Run
/spec-backfill <spec-id> again when you're ready to revisit them.
Corpus mode (--all)
Subagent contract — MANDATORY for every dispatch. Every per-spec sub-agent this skill dispatches MUST be given this preamble at the top of its prompt:
Subagent contract: Honor
rules/completeness-contract.md(load-bearing — no silent deferrals; trigger phrases = escalation signals, not completion modes). If you cannot complete assigned scope, escalate via AskUserQuestion with user-validatable proof. A return claiming COMPLETE alongside deferred items is a contract violation.
When per-spec sub-agents return, the coordinator MUST run the validation script BEFORE accepting:
mkdir -p /tmp/vallorcine
return_file=/tmp/vallorcine/spec-backfill-return-"<spec-id>".txt
printf '%s\n' "$FULL_RETURN_TEXT" > "$return_file"
bash .claude/scripts/validate-subagent-return.sh "$return_file" 2>/tmp/vallorcine/validator-stderr.txt
rc=$?
rc=0→ accept and continue to the next spec.rc=1→ trigger phrase detected. Surface to user via AskUserQuestion with validator stderr. Do not advance to the next spec until resolved.rc=2→ tooling error. Log and treat asrc=0.
When invoked with --all, iterate every APPROVED spec in the manifest
and run the per-spec walk against each via the subagent dispatch
pattern — each spec is processed by a dedicated sub-agent that owns
all file reads, the candidate-finding subprocess, and edit application.
The coordinator (this skill, in the user's conversation) only holds
per-spec one-line summaries, keeping its context bounded as the corpus
grows. Pre-flight runs once; the backfill log is the same
.spec/backfill-log.md so progress and prior decisions persist across
the whole corpus.
Why dispatch instead of inline iteration
Inline iteration accumulates context linearly: spec 1's candidates + requirement text + edit application stay in the coordinator's window while spec 2 begins, and so on. By spec 12 a coordinator running inline holds 12 × (5–30 KB) of read state. Dispatching each spec as a sub-agent gives that spec a fresh context window; the coordinator absorbs only the return summary (~80 bytes per spec). 12 specs ≈ 1 KB of accumulated summaries — bounded forever.
The dispatch boundary lines up with per-spec independence: backfill
decisions for spec A do not affect spec B's candidate scoring or
requirement text. Cross-spec resumption is already handled by the
append-only backfill-log.md — already-decided (spec, R-id) pairs
auto-skip on subsequent runs regardless of which run made the decision.
C0. Pre-flight: surface stuck dispatches from prior runs
Before enumerating, check for unacknowledged dispatch markers under
.spec/_backfill-dispatches/:
bash .claude/scripts/dispatch-marker.sh stuck .spec/_backfill-dispatches
Each line is <dispatch-id>|<dispatched_at>|.... Dispatch IDs for
this skill are suffixed: <spec-id>--propose (Phase A markers)
or <spec-id>--apply (Phase B markers). The stuck output may show
both, the same spec, or just one. Group stuck markers by spec-id
before surfacing (2026-05-11 adversarial HIGH #2) — otherwise the
user sees "Re-dispatch <spec>--propose" + "Re-dispatch <spec>--apply"
as two separate prompts for the same spec, with no clear meaning
because the user doesn't necessarily know what "--propose" vs
"--apply" implies.
For each unique <spec-id> (stripping the --propose/--apply
suffix via ${id%--*}), pick the appropriate routing based on
which markers exist:
| Markers present | Meaning | Recommended action |
|---|---|---|
--propose only | Phase A ran but Phase B never dispatched. Decisions in memory were lost. | Re-dispatch Phase A (the user's prior decisions are gone; walk the spec again). |
--apply only | Phase B dispatched but never ack'd. Some annotations may already exist; the log records them. | Investigate first — list completed rows via spec-backfill-log.sh list-decisions <log> <spec>. Re-dispatching Phase A is safe (the log's terminal-decision filter skips them), but a partial Phase B's skipped rows from the lost run will surface again. |
| Both | Phase A and Phase B both fired; result lost mid-Phase-B. | Same as --apply only — investigate the log first. |
Use AskUserQuestion per unique spec-id, with options drawn from
the table above:
- "Re-dispatch Phase A (walk spec again)" — clears any
<spec>--proposemarker, runs Phase A fresh. - "Investigate via
spec-backfill-log.sh list-decisions" — print the per-R-id state and stop the run for this spec. - "Skip <spec> for now" — leave markers; spec resurfaces next run.
This mirrors /work-resume rule 0 (PR #79) — any unacknowledged marker
pre-empts the normal flow because it represents a previous run whose
result the coordinator never saw.
C1. Discover the candidate set
Enumerate APPROVED specs by reading the manifest:
jq -r '
if .specs then
.specs[] | select(.state == "APPROVED") | .id
else
(.features // {}) | to_entries[] | select(.value.state == "APPROVED") | .key
end
' .spec/registry/manifest.json
Both v1 (features object keyed by ID) and v2 (specs array of objects)
manifest schemas are handled by the if .specs then switch — the same
dual-schema pattern spec-lib.sh uses.
For each ID, run bash .claude/scripts/spec-trace.sh --uncovered <id>
and capture only the count of uncovered R-ids. Skip specs that return
zero uncovered (already fully annotated). The pre-flight scan is the
ONLY place the coordinator reads spec-trace output for the corpus —
per-spec depth lives inside each dispatched sub-agent.
Tell the user the corpus picture in one paragraph:
Corpus has <N> APPROVED specs. <K> already fully annotated — skipping.
<M> have at least one uncovered requirement, totalling <U> uncovered
R-ids across the corpus. Dispatching one sub-agent per spec to keep
this conversation's context bounded. Break out at any time and rerun
/spec-backfill --all to resume.
Use AskUserQuestion to confirm before starting if <U> exceeds 50:
- "Run all" (Recommended)
- "Cap at 10 specs" (or another cap)
- "Cancel"
C2. Per-spec two-phase dispatch loop
For each spec with uncovered R-ids, in manifest order, run this loop until the dispatched count reaches the cap (if set) or the eligible set is empty.
The two-phase pattern is mandatory. The single-spec flow's Phase 2
uses AskUserQuestion per R-id. Dispatched sub-agents (Agent tool) run
to a single final-message return; the codebase convention is that
sub-agents do NOT call AskUserQuestion mid-flow (the only documented
sub-agent contract — see /work-start all, /feature-coordinate — is
"run autonomously and return one message"). Two-phase dispatch
respects that contract by splitting the work: sub-agent A runs the
read-heavy discover + propose stage with no user prompting, the
coordinator surfaces the per-R-id decisions via AskUserQuestion, then
sub-agent B applies the decisions mechanically.
C2a. Phase A — discover + propose (sub-agent, autonomous).
Write the marker, then dispatch:
bash .claude/scripts/dispatch-marker.sh begin .spec/_backfill-dispatches <spec-id>--propose
Agent prompt verbatim (substitute <spec-id>):
You are the discover + propose stage for /spec-backfill <spec-id>.
Run, in order:
1. bash .claude/scripts/spec-trace.sh --uncovered <spec-id>
This emits FULLY-QUALIFIED R-ids (e.g., `auth.foo.R3`).
2. For each uncovered R-id (cap at 12 — surface "more remain" in
output if there are more):
- Strip the spec-id prefix to get the bare R-id:
r_id="${fq_rid##*.}" (e.g., `auth.foo.R3` → `R3`).
spec-backfill-candidates.sh and spec-backfill-log.sh both
require BARE R-ids; passing the FQ form errors. (CRIT 4,
2026-05-11 adversarial.)
- Extract the requirement text from the spec file under
## Requirements (match `^<r_id>[a-z]*(-…)?\.`).
- Run `bash .claude/scripts/spec-backfill-candidates.sh <spec-id>
<r_id>` (bare) and capture the top 5 candidates.
3. Read .spec/backfill-log.md if it exists; for each bare R-id, run
`bash .claude/scripts/spec-backfill-log.sh has-decision
.spec/backfill-log.md <spec-id> <r_id>`; mark R-ids whose
has-decision returns `annotated|waived` as "already_decided" so
the coordinator can skip them.
Return EXACTLY ONE LINE — a JSON object — matching this shape:
{"spec_id":"<spec-id>","total_uncovered":<int>,"more_remain":<bool>,
"items":[
{"r_id":"R3","requirement_text":"<≤200 chars>",
"candidates":[{"file":"<path>","line":<int>,"context":"<≤80 chars>","score":<float>}],
"already_decided":null},
...
]}
If `total_uncovered` is 0, return:
{"spec_id":"<spec-id>","total_uncovered":0,"items":[]}
DO NOT call AskUserQuestion. DO NOT edit any files. DO NOT log anything.
Read-only stage. Coordinator handles all user interaction + log writes.
Any other return shape is treated as a parse failure.
C2b. Parse the proposal + ack marker.
Receive the JSON. Validate via jq -e '.spec_id and .items'. On
parse failure, mark the propose-stage marker as failed and continue
to next spec (the surfacing logic is in C2e — mark the propose marker
as failed via bash .claude/scripts/dispatch-marker.sh fail .spec/_backfill-dispatches <spec-id>--propose "parse-failed: <first 80 chars>", surface to user, continue).
bash .claude/scripts/dispatch-marker.sh ack .spec/_backfill-dispatches <spec-id>--propose "<one-line-summary>"
C2c. Coordinator AskUserQuestion loop (per R-id).
For each item in items where already_decided is null:
Build AskUserQuestion options dynamically from the top candidates plus the standard tail (Skip, Waive, Other). Present:
R3 — <requirement_text>
Suggested annotation sites:
(a) <file>:<line> (score: <s>) <context>
(b) ...
Pick one, or Skip / Waive / specify Other.
Collect the user's decision into a decision-set:
{"spec_id":"<spec-id>","decisions":[
{"r_id":"R3","action":"annotate","file":"...","line":123},
{"r_id":"R5","action":"skip"},
{"r_id":"R7","action":"waive","reason":"<≤100 chars>"}
]}
If the user picks "Other", validate the file path exists in coordinator before adding to the decision-set (same validation as today's inline flow).
The decision-set lives in coordinator context briefly (~500 bytes per spec at most) — released as soon as Phase B returns.
Skip Phase B dispatch when the decision-set is no-op (2026-05-11 adversarial HIGH #4). Before invoking C2d:
- If
decisionsis empty AND every item wasalready_decided(this is a no-op re-run of an already-completed spec), skip C2d entirely. Print<spec-id> — all uncovered R-ids already terminal (no-op)and ack the propose marker with that summary. Continue to next spec. - If
decisionsis non-empty but contains ONLYskipactions (user declined every R-id this round), there are still log rows to write for audit trail — dispatch C2d normally so theskippedrows are recorded (they're non-terminal and will resurface on the next run with a forward-progress signal). - Otherwise dispatch C2d normally.
This guard avoids paying full sub-agent overhead to log zero rows
when re-running /spec-backfill --all after a clean completion (every
Phase A returns items with already_decided set; previously the
coordinator dispatched Phase B per spec just to confirm "no work to
do").
C2d. Phase B — apply (sub-agent, autonomous, idempotent).
bash .claude/scripts/dispatch-marker.sh begin .spec/_backfill-dispatches <spec-id>--apply
Agent prompt verbatim (substitute the JSON):
You are the apply stage for /spec-backfill <spec-id>.
Decisions (JSON):
<paste the decision-set JSON here>
For each decision, in order:
- action="annotate" → read the file at <file>, locate <line>, insert
a `@spec <spec-id>.<R-id>` annotation in a comment ABOVE the line
(per rules/spec-annotation-protocol.md comment syntax). If a sibling
@spec annotation already exists at that location, append to the
existing comment rather than adding a new line. Use the Edit tool.
Append to the log:
bash .claude/scripts/spec-backfill-log.sh append \
.spec/backfill-log.md "$(date +%F)" <spec-id> <R-id> annotated \
"<file>:<line>"
- action="skip" → append `skipped` row to the log (no location).
- action="waive" → append `waived` row with the reason in notes.
Before each apply, query `bash .claude/scripts/spec-backfill-log.sh
has-decision .spec/backfill-log.md <spec-id> <R-id>`. If a terminal
decision (annotated | waived) already exists, skip this decision
silently — the apply stage MUST be idempotent so a re-dispatch after a
crash does not double-annotate.
After all decisions, run:
bash .claude/scripts/spec-trace.sh --uncovered <spec-id>
and count the remaining uncovered R-ids.
Return EXACTLY ONE LINE:
COMPLETE <spec-id> annotated=<N> skipped=<K> waived=<W> uncovered_after=<U>
DO NOT call AskUserQuestion. The decision set is final; do not
re-prompt. Any other return is treated as a parse failure.
C2e. Parse Phase B return + ack the apply-stage marker.
Classify into one of:
-
COMPLETE … — ack the marker:
bash .claude/scripts/dispatch-marker.sh ack .spec/_backfill-dispatches <spec-id>--apply "<return-line>"Print
<spec-id> — <return-line>to the user. Continue to next spec. -
Payload lost — Agent return literally equals
[Tool result missing due to internal error]. Mark the apply markerpayload-lost. The propose marker is still acked, and the log captured partial progress if Phase B did any work. Surface via AskUserQuestion: "Re-dispatch <spec-id> apply" / "Skip and continue" / "Investigate manually". -
User stopped — Agent return contains
The user doesn't want to proceed with this tool use. Markuser-stopped. Same recovery options. -
Parse failed — return present but does not match. Mark
parse-failed: <first-80-chars>. Print raw return; same recovery options.
C2f. Forward-progress re-loop for >12 uncovered specs (2026-05-11
adversarial HIGH #3). Phase A's prompt caps at 12 uncovered R-ids per
dispatch and sets more_remain=true in the JSON when there are more.
Without a re-loop, a spec with 30 uncovered R-ids only ever surfaces
R-ids 1-12 across any number of /spec-backfill --all runs — R-ids
13-30 are invisible because skipped rows from the first batch keep
the same 12 surfacing first.
After C2e ack, check the Phase A return's more_remain flag:
- If
more_remain == false→ continue to next spec (current behavior). - If
more_remain == true:- Count this round's forward progress = number of decisions
whose action was
annotateorwaive(terminal in the log). - If forward progress is zero (user skipped every R-id this
round), stop iterating this spec — the next batch would just
re-surface the same 12. Continue to next spec. The skipped R-ids
will resurface on the next
/spec-backfill --allrun. - If forward progress is >= 1, re-dispatch Phase A for the same
spec (new propose marker, fresh AskUserQuestion loop). The
already-annotated/waived R-ids will be filtered by Phase A's
already_decidedcheck; the user sees the next batch of 12 uncovered R-ids. Cap the inner loop at 3 iterations per spec to prevent pathological cases.
- Count this round's forward progress = number of decisions
whose action was
This makes the corpus walk eventually-complete for specs with >12 uncovered R-ids, as long as the user makes forward progress at least once per round.
C2g. Honor the cap. If a cap was set in C1 and the dispatched count has reached it, exit the loop after acking the current spec.
C3. Corpus summary
After the loop exits, emit a final aggregate report:
- Total specs dispatched / completed / stopped / empty / failed
- Total annotations applied this session (sum from return lines)
- Total R-ids skipped (will resurface) / waived
- Any remaining stuck markers (re-run pre-flight count)
- Pointer to
.spec/backfill-log.mdfor the canonical record
If any spec returned STOPPED or any marker is still failed, tell the user how to resume:
<X> spec(s) left work undone this run. Rerun /spec-backfill --all
to resume — already-decided R-ids will be skipped automatically, and
the pre-flight will offer to re-dispatch any stuck markers.
C4. Cost awareness
Even with dispatch, whole-corpus runs are still long because each
sub-agent does real work — the win is coordinator context economy,
not wall-clock. The C1 confirmation step surfaces the cost note when
the uncovered count exceeds 50, but a corpus with 50+ specs may still
benefit from a Cap at 10 first pass to validate the dispatch is
behaving as expected.
Failure modes and recovery
-
Manifest does not resolve the spec ID. Tell the user the spec ID is unknown; suggest
/specto list available specs. Stop. -
Candidate finder returns zero rows for every R-id. Likely indicates the requirement text is too prose-y for token extraction. Fall through to "Other" / "Skip" — do not silently advance.
-
Edit collides with an existing annotation that already covers this R-id. That should not happen if Phase 1 filtered correctly, but if it does: log as
annotated(idempotent on the log) and continue. -
User aborts mid-walk (single-spec mode). The log preserves every decision applied so far; rerunning resumes from where the user left off. Do not revert applied annotations.
-
User aborts mid-AskUserQuestion loop (corpus mode C2c) — 2026-05-11 adversarial MED #2. In corpus mode, decisions are collected in coordinator memory across multiple
AskUserQuestionprompts (one per R-id) BEFORE Phase B dispatches and writes log rows. A user abort (ESC) after, say, 5 of 12 R-ids leaves 5 answered decisions in memory with 7 unanswered. Without explicit handling, the run exits and ALL 5 decisions are discarded — the user has to redo them on the next run.When a corpus-mode C2c AskUserQuestion returns a user-abort signal:
- Dispatch Phase B with the PARTIAL decision-set the user has already answered. Phase B is idempotent (log dedupe + has-decision filter) so this is safe.
- After Phase B completes, surface to the user that the run is
stopping with progress preserved:
Aborted mid-walk on <spec-id> at R-id <N>/<total>. <K> decisions applied to log; <total - K> R-ids will resurface on the next /spec-backfill --all run. - Exit the corpus loop (do NOT continue to the next spec).
The full corpus run is interruptible at any boundary; this fix makes the in-spec walk interruptible too without losing answered decisions.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.