Development record
2026-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.
2026-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.
Frontmatter
| id | dcn-2607280000000001 |
|---|---|
| type | decision |
| date | 2026-07-28 |
.abcd/work/decisions/dcn-2607280000000001-itd-101-part-b-second-review-round.md
open on GitHub ↗ · commit history ↗
mentions1
- itd-101**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."