Development record
2026-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).
2026-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).
Frontmatter
| id | dcn-2607270000000009 |
|---|---|
| type | decision |
| date | 2026-07-27 |
.abcd/work/decisions/dcn-2607270000000009-itd-101-part-b-review-round-settled-five.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."