Development record
**Every citation abcd publishes is provably alive and honestly labelled — and the gate that enforces it never flakes.** A cited reference page is only as trustworthy as its links, and links rot silently: pages retitle, URLs redirect, whole platforms announce their own shutdown. abcd splits citation validation across a deterministic gate and an explicit refresh. An offline lint family checks structure and source policy on every commit — footnote markers and definitions in bijection, URLs and DOIs well-formed, aggregator domains refused — with zero network in the gate. `abcd docs cite refresh` does the live fetching on demand and writes a committed baseline: per URL, the final resolved address, when it was last checked, and whether verification was automatic or manual — never how. Sources that block automated fetchers join a manual queue the maintainer clears link by link: printed as a checklist first, later as a generated, disposable checklist page that hands back a receipt file the verb ingests. The lint then enforces the baseline offline — no broken entries, no stale entries, no cited URL without a receipt, no citation whose recorded final address has drifted. The engine is native and dependency-free first; a specialist link checker can slot in later behind the same seam. "My release gate stays deterministic and my citations stay alive," said Kira, an open-source maintainer. "When a source needs human eyes, abcd hands me the exact list to click through and records that I did — not how I did it."
Press Release
Seeded from a quoted-text intent capture. Expand into the full press-release narrative before planning.
Why This Matters
Every citation abcd publishes is provably alive and honestly labelled — and the gate that enforces it never flakes. A cited reference page is only as trustworthy as its links, and links rot silently: pages retitle, URLs redirect, whole platforms announce their own shutdown. abcd splits citation validation across a deterministic gate and an explicit refresh. An offline lint family checks structure and source policy on every commit — footnote markers and definitions in bijection, URLs and DOIs well-formed, aggregator domains refused — with zero network in the gate. abcd docs cite refresh does the live fetching on demand and writes a committed baseline: per URL, the final resolved address, when it was last checked, and whether verification was automatic or manual — never how. Sources that block automated fetchers join a manual queue the maintainer clears link by link: printed as a checklist first, later as a generated, disposable checklist page that hands back a receipt file the verb ingests. The lint then enforces the baseline offline — no broken entries, no stale entries, no cited URL without a receipt, no citation whose recorded final address has drifted. The engine is native and dependency-free first; a specialist link checker can slot in later behind the same seam. "My release gate stays deterministic and my citations stay alive," said Kira, an open-source maintainer. "When a source needs human eyes, abcd hands me the exact list to click through and records that I did — not how I did it."
Scope Conditions
None stated.
Acceptance Criteria
- Given
abcd docs lintruns in the commit gate, when the citations family evaluates, then it uses zero network: footnote structure (marker-definition bijection, and every crosswalk table row carrying at least one footnote), URL/DOI syntax, and source-domain policy come from committed config and the committed baseline. - Given
abcd docs cite refreshruns, when it writes the baseline, then each URL entry records the final resolved address, when it was checked, and whether verification was automatic or manual (with its date) — never how. - Given a baseline entry older than 180 days, when docs lint runs, then it warns; given one older than 365 days, when the release gate runs, then it blocks; human-verified entries age on the same clock and re-enter the manual queue when stale.
- Given a source that blocks automated fetchers, when the maintainer clears the manual queue, then a printed checklist plus a confirm verb writes the dated receipt; the later generated checklist page hands back a receipt file the same verb ingests — one receipt schema for both rungs.
- Given a specialist link checker is adopted later, then it slots behind the refresh seam as an adapter without changing gate semantics — internal basic first, SOTA dependency later.
Open Questions
- The generated checklist page's receipt-file format details (settled only as: same schema as the confirm verb writes).
- Where the scheduled-CI refresh wrapper lands when it earns its own sign-off (explicitly out of this intent's scope, per the 2026-07-27 grill).
Grill Settlements (2026-07-27)
- Refresh is manual now, surfaced by ahoy status and release-preflight nagging; a scheduled-CI wrapper is a later, separately signed-off change.
- Staleness policy: warn at 180 days in docs lint; blocker at 365 days at the release gate only — commits are never calendar-blocked.
- The row-has-footnote structural rule deferred from spc-15 is homed here (dcn-2607270000000002): implemented in this intent or not at all.
Audit Notes
Fidelity review — receipt rcp-c9215c58f907 (verifier intent-auditor claude-fable-5-1).
Provenance: intent-auditor@claude-fable-5-1 · rubric_hash sha256:effa65b3e9e88ff29433b443ec2be159522a8b0b71cf1434526514aa61edb13e · prompt_hash sha256:52b26b83a679523966b7b9a13546b3b07444305929d5fce0529803864c76f38e Input attestations: diff:tree at de3ba5fa (spc-17 delivered; main after PR #661)@sha256:4e7430d38ef6b7b6bc533fdf0b8b32a6e08a3e2449d0566027d43316036b8178;
Acceptance rollup: MET 3 · MET_WITH_CONCERNS 2 · NOT_MET 0 · INCONCLUSIVE 0
Per-criterion verdicts:
- ac-1 — MET_WITH_CONCERNS: the citations lint family imports net/url only (no HTTP client): footnote bijection, crosswalk-row footnotes, URL/DOI shape and the configured refused-domain policy all read committed config and the committed baseline; the concern is where 'the commit gate' is — docs lint runs in make preflight and the pre-push hook, not in the pre-commit hook
evidence: internal/core/lint/citations.go:20 — ""net/url""
evidence: internal/core/lint/citations.go:347 — "checkCitationFootnotes enforces the marker/definition bijection."
evidence: internal/core/lint/citations.go:398 — "func checkCitationCrosswalkRows(rel string, lines []string, mask []bool, cfg RuleConfig) ([]Finding, error) {"
evidence: internal/core/lint/citations.go:217 — "doiShapeRe = regexp.MustCompile(
^10\.\d{4,9}/\S+$)" evidence: internal/core/lint/config.go:210 — "RefusedDomains is the citation_source_policy list of aggregator domains" evidence: Makefile:229 — "@go run ./cmd/abcd docs lint" evidence: .githooks/pre-push:64 — "make preflight" - ac-2 — MET: each baseline entry carries final_url, last_checked, verification (automatic|manual) and verified_on; a method/how/transcript key is refused by the loader and the receipt type is proved by reflection to carry no such field
evidence: internal/core/lint/baseline.go:98 — "FinalURL string
json:"final_url"" evidence: internal/core/lint/baseline.go:102 — "LastChecked stringjson:"last_checked"" evidence: internal/core/lint/baseline.go:107 — "Verification stringjson:"verification"" evidence: internal/core/lint/baseline.go:109 — "VerifiedOn stringjson:"verified_on"" evidence: internal/core/lint/baseline.go:141 — "a smuggled method/how/transcript key is a refusal" evidence: internal/core/cite/confirm_test.go:179 — "func TestReceiptHasNoMethodFieldByConstruction" - ac-3 — MET: the thresholds are 180 (warn) and 365 (block) days; the launch gate measures the baseline through the CLI and refuses on any overdue entry, docs lint --release-gate promotes the finding to a blocker, and a stale manual receipt is re-checked by refresh on the same clock evidence: internal/core/lint/citations.go:44 — "defaultCitationWarnDays = 180" evidence: internal/core/lint/citations.go:45 — "defaultCitationBlockDays = 365" evidence: internal/core/launch/citations.go:107 — "if pre.Overdue > 0 {" evidence: internal/surface/cli/cli.go:295 — "Citations: citationPreflight(cwd)," evidence: internal/surface/cli/cli.go:492 — "cfg = lint.ArmCitationOverdue(cfg)" evidence: internal/core/cite/refresh_test.go:212 — "func TestRefreshRechecksAStaleManualReceipt"
- ac-4 — MET_WITH_CONCERNS: refresh prints the blocked URLs as a manual checklist and
docs cite confirmwrites a dated manual receipt from URLs on the command line or from a --receipt file in the one Receipt schema; the concern is that the generated checklist page itself is not delivered — spc-17 defers it to a later rung and only its receipt schema is fixed evidence: internal/core/cite/refresh.go:95 — "Queue is the manual checklist: everything a human must clear." evidence: internal/surface/cli/cite.go:114 — "Use: "confirm [url...]"," evidence: internal/surface/cli/cite.go:164 — "cmd.Flags().StringVar(&receiptPath, "receipt", ""," evidence: internal/core/cite/confirm.go:55 — "Receipt is what a human — or the generated checklist page — hands back." evidence: internal/core/cite/confirm_test.go:15 — "func TestConfirmWritesADatedManualReceipt" evidence: .abcd/development/specs/closed/spc-17-every-citation-abcd-publishes-is.md:105 — "The generated checklist page itself may land as the later rung" - ac-5 — MET: the refresh takes a Checker interface with one method; HTTPChecker is the native implementation and the tests drive the refresh through a stub checker, so a specialist checker is an adapter and the gate reads the baseline only evidence: internal/core/cite/fetch.go:105 — "type Checker interface {" evidence: internal/core/cite/fetch.go:109 — "HTTPChecker is the native, dependency-free implementation of Checker." evidence: internal/core/cite/refresh_test.go:220 — "Refresh(RefreshRequest{RepoRoot: root, Config: testConfig(), Checker: checker, Now: now})"
Gap audit:
- honoured:
- an offline citations lint family with zero network in the gate evidence: internal/core/lint/citations.go:20 — ""net/url""
- a committed baseline recording final address, when checked, and automatic-vs-manual with its date — never how evidence: internal/core/lint/baseline.go:141 — "a smuggled method/how/transcript key is a refusal"
- 180-day warn in docs lint, 365-day blocker at the release gate, manual receipts ageing on the same clock evidence: internal/core/lint/citesummary.go:118 — "case age >= blockDays:" evidence: internal/core/launch/citations.go:107 — "if pre.Overdue > 0 {"
- a manual queue cleared by a confirm verb writing dated receipts, one schema evidence: internal/core/cite/confirm.go:55 — "Receipt is what a human — or the generated checklist page — hands back."
- a native engine behind a seam a specialist checker can slot into evidence: internal/core/cite/fetch.go:105 — "type Checker interface {"
- diverged:
- docs lint runs in the commit gate — delivered in the preflight/pre-push gate, not the pre-commit hook evidence: .githooks/pre-push:64 — "make preflight" evidence: Makefile:229 — "@go run ./cmd/abcd docs lint"
- missing:
- the generated, disposable checklist page that hands back a receipt file evidence: .abcd/development/specs/closed/spc-17-every-citation-abcd-publishes-is.md:105 — "The generated checklist page itself may land as the later rung" evidence: internal/surface/cli/cite.go:165 — "the format the generated checklist page emits"
Frontmatter
| id | itd-101 |
|---|---|
| type | intent |
| lifecycle | shipped |
| kind | standalone |
| severity | minor |
.abcd/development/intents/shipped/itd-101-every-citation-abcd-publishes-is.md
open on GitHub ↗ · commit history ↗
Referenced by2
- iss-2610262036322416itd-101 says the offline lint enforces no stale citation entries alongside no broken ones; the docs chapter says staleness only warns and never blocks an ordinary commitrelated
- spc-17every-citation-abcd-publishes-is-provably-alive-and-honestlyimplemented by
mentions16
- dcn-26072700000000022026-07-27 — DEFERRED the row-has-footnote structural docs-lint rule (spc-15 out-of-scope): no existing rule shape covers table-row-to-footnote structure, so it would need a bespoke check; the grill left it optional and the citation-gate intent (itd-101) is now its natural home — implement it there or not at all. Recorded per spc-15's deferral-is-recorded clause; surfaced by the itd-100 fidelity audit's gap check.
- dcn-26072700000000052026-07-27 — GRILLED itd-101/102/103/104 to settlement (six decisions, each now in its intent's Grill Settlements + acceptance criteria): itd-103 guard fails open loudly, blocker/warn tiers with committed-only overrides, shell-token-aware command-position matching with an itd-81-style TNR-floored corpus; itd-101 refresh is manual-with-nagging (scheduled CI later, own sign-off), staleness warns at 180d and blocks releases at 365d, human verifications age on the same clock; itd-102 identity lives in a parseable markdown block (config points at it), check is warn-tier and never rewrites; itd-104 ideate is an optional verb, never a pre-capture gate, with a fresh-context off-policy adversary. All four drafts are grill-settled and await intent plan.
- dcn-26072700000000062026-07-27: itd-101 spec minted as spc-16 collided with unmerged #156 (iss-80 class, both spc-N and iss-N allocators); renumbered to spc-17 by hand, duplicate capture folded into iss-80 — ids on this branch deliberately skip 16.
- dcn-26072700000000072026-07-27 — itd-101 part (a) settled four choices spc-17 left open. (1) The committed baseline lives at `.abcd/citations-baseline.json`, alongside docs-lint.json/record-lint.json/rules.json — it is config the gate reads every commit, not development record; rejected `.abcd/development/` (wrong tier) and `.abcd/work/` (not a session artefact). (2) A table is a CROSSWALK when its nearest preceding heading matches `(?i)crosswalk` (configurable) — the narrowest heuristic that selects docs/reference/terminology.md's table and leaves every ordinary directory-map/comparison table alone; rejected column-header and any-table-in-docs identification (both sweep up README.md and docs/README.md tables that carry no citations by design). (3) A page's CITATION CORPUS is its footnote definitions, including wrapped continuation lines — not its prose; a URL in a body paragraph stays links_resolve's business, which is what keeps the syntax and source-policy rules off ordinary text. (4) `refused_domains` ships EMPTY: the repo states its admission rule in prose ("no single-author coinages, no aggregators", docs/reference/terminology.md + ACKNOWLEDGEMENTS.md) but nowhere names a domain, and the gate must not invent an editorial blacklist the project never agreed. Also: staleness is measured from `last_checked` for automatic and manual entries alike (AC 3's "same clock"), and the 365-day threshold surfaces as a distinct rule id `citation_baseline_overdue` at warn — the commit gate never calendar-blocks, so promotion to blocker is the release gate's job in part (b).
- dcn-26072700000000082026-07-27 — itd-101 part (b) settled seven choices spc-17 left open, and consolidated one primitive. (1) The SSRF fetch guard moved from `internal/core/memory` to `internal/urlguard` rather than being copied for the second fetch path; its address predicate became a parameter so a fetch path can be exercised against an httptest server (which binds loopback) without the shipped policy ever being relaxed. (2) BLOCKED-FOR-AUTOMATION is classified by status code ONLY — 401, 403, 406, 429 — with no body sniffing for challenge-page markers: a heuristic over page text would be unreliable AND a reason to start reading content, and the challenge pages that matter answer with one of those codes anyway. Everything else non-2xx is broken. (3) One GET per URL, body never read and never retried: liveness is the status line, so a citation to a huge file costs a response header; a retry loop would make a run's duration a function of how many links are failing. (4) A blocked URL with NO prior entry writes NOTHING — the gate then reports it as unreceipted, which is exactly true; recording it broken would put a lie in a committed record the gate enforces. (5) A CURRENT manual receipt is preserved verbatim and not even re-requested; a STALE one is re-checked (AC 3's one clock) and, if the source still blocks, KEPT rather than deleted so the gate keeps warning honestly. Rejected: refetching every manual entry every run (downgrades a human's receipt to a robot's failure), and never refetching them (buys a permanent exemption from ageing). (6) `confirm` records ALIVE only — it is "I looked and it is there", never a channel for recording a link dead — and takes URLs positionally or a receipt file, both assembling ONE schema so the later generated checklist page is a different producer, not a second pathway. (7) `refresh` exits ZERO after recording broken links: it records, the gate decides; a verb that failed on a dead link could never write the record that reports it. Also: the release-gate promotion reuses `ArmReceiptGate`'s shape (`lint.ArmCitationOverdue`, armed by `abcd docs lint --release-gate`) with the FLAG as trust root, and the `abcd launch --dry-run` citation gate takes its measurement from the CLI as data because `core/lint` imports `core/launch` for its semver — the same shape the cobra-tree walk already uses.
- dcn-26072700000000092026-07-27 — itd-101 part (b) review round settled five more. (1) The committed `citation_baseline.baseline` config value is CONTAINED at one choke point (`lint.CitationPolicy`, which now returns an error): a `../../..` or absolute path is REFUSED, never silently normalised, because `SaveBaseline` MkdirAll's its parent and a contributor controls that file — this was a real arbitrary-file-write primitive found by the security review, reproduced against a built binary. Both writers and both readers resolve through the one check. (2) A refresh run in which NOTHING succeeded is REFUSED rather than committed, and only when a prior baseline existed: `Check` collapses DNS failure, refused connection and timeout into the same `broken` as a 404, so a run behind a captive portal would otherwise rewrite every entry as broken — stale human receipts included, since those are re-checked and so not covered by the blocked branch — and the operator would find the gate blocking every commit. A first run over genuinely dead citations has nothing to protect and still writes. (3) An unrecognised `Status` from a `Checker` is an ERROR, not a fall-through: the seam is exported for AC 5's adapter, and falling through would drop the URL from BOTH the baseline and the queue — the one outcome nothing downstream could detect. (4) The missing-entry lint message names BOTH verbs: the only state that produces a missing entry is a source refusing automated fetchers, so naming `refresh` alone sent the maintainer round a loop that cannot terminate — only `confirm` clears it. (5) A docs-lint config that arms the citation rule but fails to PARSE is reported to the release preflight as `Unreadable` and REFUSES, distinct from the nil "not armed" state — rendering a broken gate as an absent one would wave a release through on a false statement. Also consolidated: `daysBetween` is now the exported `lint.DaysBetween`, called by the verb and the gate alike, because two copies of the staleness boundary is two chances for the verb to call an entry current on the day the gate calls it overdue; and the CLI's ad-hoc `citeErrorDetail` was dropped for the canonical `scrubPaths`, which preserves the `*PathError` type the redactor needs (an absolute developer path was reaching machine output).
- dcn-26072800000000012026-07-28 — itd-101 part (b) second review round closed three holes the first round's fixes left open, all reproduced end-to-end by the reviewers. (1) The baseline-path containment check was purely LEXICAL, so a committed symlinked directory (`.abcd/evil -> /outside`) plus a lexically-innocent `"baseline": ".abcd/evil/x.json"` reopened the very arbitrary-file-write primitive the first fix claimed to close — `WriteFileAtomic` MkdirAll's *through* the link. Containment now also RESOLVES: `EvalSymlinks` on the deepest existing ancestor of the target (it usually does not exist yet on a first run), compared against an `EvalSymlinks`'d repo root, reusing the shape `internal/core/launch/bundle.go` already uses for symlinked bundle entries rather than adding a third copy. `CitationPolicy` now takes the repo root and returns a `CitationPolicySet` carrying both the repo-relative form (for messages, so no absolute path is ever rendered) and the absolute form (for I/O). (2) `cfg.Roots` had NO containment, and while reading outside the repo was inert for a reporting lint, this intent made the collector feed a live fetcher whose results are persisted into a baseline the workflow expects to be committed and pushed — `"roots": ["../private"]` therefore fetched and PUBLISHED every URL in a sibling directory. The collector (not the pre-existing lint walk) now refuses an escaping or symlinked root. (3) The wholesale-failure guard consulted `res.Preserved == 0`, but a preserved receipt was never fetched and so is no evidence the network worked: any repo that had ever run `confirm` — the designed steady state for robot-refusing sources — silently lost the protection entirely. The guard now reads a new `CheckOutcome.Answered` bit that the CHECKER sets when a host returned any status line at all. That is the bit `StatusBroken` was destroying (a DNS failure, a refused connection and a genuine 404 all landed there), and recovering it from a proxy was wrong in both directions — the old condition also made a sole genuine 404 permanently unrecordable, refusing forever with a false "check connectivity". RULE affirmed: when a guard needs a fact, carry the fact, never infer it downstream from something correlated.
- dcn-26072800000000022026-07-28 — itd-101 part (b) third review round closed the other half of the roots containment and recorded one accepted narrowing. (1) Containing the configured ROOT string is NOT enough: `WalkDir` yields a symlinked `.md` as an ordinary file and `os.ReadFile` follows it, so a committed `docs/leak.md -> ../private/notes.md` sits inside a perfectly contained root and still drags an outside file's citations into the live fetch and then into the committed, pushed baseline. Every collected FILE is now resolved-contained, not just its root; an in-repo symlink (the `CLAUDE.md -> AGENTS.md` bridge shape) still resolves, because containment is about where a path LANDS. RULE affirmed: a containment check on a directory says nothing about the files found under it. (2) ACCEPTED NARROWING in the refresh's wholesale-failure guard: keying it on `answered` (a host returned any status line) rather than on success means an intercepting proxy or DNS sinkhole that answers EVERY request with a non-2xx outside the blocked set — 503, 407, or a default-vhost 404 — no longer trips it, and a whole corpus would be rewritten `broken`. That is strictly narrower than the condition it replaced, but the replaced one was wrong in two commoner ways (any repo that had ever run `confirm` lost the protection entirely, and a sole genuine 404 could never be recorded). It ships because refresh is operator-initiated and its transcript prints the `broken:` count before anything is pushed; the guard covers failures that produce no status line at all, and nothing more. (3) A CHANGELOG entry must describe the tree AT ITS COMMIT, never the state it will reach once a human acts: rewording the citation bullet to the post-confirmation state asserted "every URL carries a receipt" while the repo's own gate printed the counter-evidence. Reverted to the true count.
- dcn-26072800000000032026-07-28 — itd-101 part (b) closed two robustness notes from the approving security review, and flagged two it left. (1) A page read is now BOUNDED and regular-file-checked (`fsutil.ReadGuarded`, 8 MiB), because containment answers "does this path land inside the repo" and says nothing about how big what it lands on is — and this collector's output is fetched over the network. It opens the RESOLVED path rather than the literal one: `O_NOFOLLOW` on the literal path refuses every symlink leaf, which would break the legitimate in-repo bridge (`CLAUDE.md -> AGENTS.md`) that containment has just approved. So `containedRealPath` returns the resolved path alongside its verdict, and the reader reads exactly the thing containment judged. (2) `StatusOK` and `StatusBlocked` now ENTAIL an answer in the wholesale-failure guard: a 2xx cannot exist without a host replying, and "blocked" is defined by a status code, so only `StatusBroken` is genuinely ambiguous. That is what those statuses MEAN, not inference from a proxy, and it removes a footgun where a third-party adapter omitting `Answered` would refuse a run in which every check succeeded. The `Checker` seam's doc comment now states both obligations an implementer owes. NOT DONE, deliberately: (a) `urlguard.BlockedIP` still omits CGNAT `100.64.0.0/10` and benchmark `198.18.0.0/15` — adding them would change `memory ingest` behaviour, and that extraction was landed as a behaviour-preserving port, so it belongs in its own change; (b) a narrow availability path remains where a repo whose entire baseline is current-manual plus one PR-added citation to an unroutable host refuses the whole refresh with a misleading "check connectivity" — the reviewer could not make it bite on a realistic corpus, and the guard's limits are already recorded above.
- dcn-26072800000000042026-07-28: itd-104 spec minted as spc-16 (third live iss-80 instance this run: 16 collided with #156, 17 with the itd-101 branch); renumbered to spc-18 by hand.
- iss-80Record id allocators (itd-N, spc-N, iss-N) are branch-local: parallel agents on separate branches each scan for max+1 and mint the SAME id. Two intents both claimed itd-82 and both merged to main (PRs #46, #47). The iss-N allocator hit the same class before (iss-77 collision, manually renumbered to iss-79; class recorded as iss-74). Resolving a collision forces a renumber, which breaks the record's stated 'ids are capture-stable, never renumbered' invariant -- so the minting scheme, not the renumber, is the defect. This capture is the MINTING half: a collision-free allocation scheme is needed (forge-minted / random-suffix / timestamp / reserve-registry -- SOTA under research). The DETECTION half is armed separately: intent_lifecycle now blocks duplicate intent ids.
- iss-2608261719070527docs/explanation/rationale.md rests its load-bearing audience definition on an external social-media URL. The page defines who a product thinker is by linking a third-party post — a link-rot-prone foundation for the record's most important audience claim. When the page is next edited (the adopted plan expands it with the ownership/movability/build-to-learn rationale), the definition should be restated in the page's own words with the link demoted to a credited source under citation health (itd-101's alive-links scope).
- iss-2609020721396212Intent and spec titles have no length ceiling, and several run to a full sentence that carries the description rather than a name (the longest today are well over a hundred characters), so a roster, a status board, a changelog line and the record export on the website all show a paragraph where a title belongs, and the id-plus-slug filename derived from the title is truncated at a fixed width that cuts mid-word. Two changes: a threshold on the title at mint time (intent new, spec new, capture promote), refused with the excess named and the description offered as the place for the rest, with a size stated in the record schema and enforced by record-lint for hand-written records; and the website's record export truncating an existing over-long title at the display layer with an ellipsis and the full text on hover or on the record page, so the records already in the corpus do not have to be rewritten to render. The ceiling itself is a decision (a fixed character count, or a word count); the site truncation is not.
- iss-2609230734017018itd-101 ac-4 promises that the later generated checklist page hands back a receipt file the confirm verb ingests; delivered reality: docs cite confirm --receipt ingests the one Receipt schema (internal/core/cite/confirm.go) and refresh prints the manual queue, but no generated checklist page exists in the tree — spc-17 records it as a rung that may land later, so the receipt-file half of the criterion has a consumer and no producer. Found by the itd-101 fidelity audit (rcp-c9215c58f907).
- iss-2609290448510918The predecessor-store qualifier sweep reaches past the six intents iss-2609261536147903 named: outside drafts/ and those six, 192 citation sites across about forty intents name a spc-N at or below spc-70 that is not the citing intent's own spec, with no '(predecessor store)' on the line. Some are live cross-references (the cold-reading family's intents cite each other's live specs), and some are the predecessor store's (itd-4, itd-6, itd-29, itd-47 and itd-49 describe pre-rebuild work in its terms), so each site needs the same reading against the live spec it collides with; the specs charter's Two spc-N Namespaces section is the rule. Found while sweeping the pattern of iss-2609261536147903 in lane drainDrift3; a census script over intents/{planned,shipped,disciplines} reproduces the count.
- spc-15alice-reads-one-page-and-knows-exactly-where-abcd-stands-in