Development record
links_resolve (internal/core/lint/lint.go checkLinks) strips the #fragment before resolving and skips same-file # links, so no gate validates heading anchors even though both record-lint and docs-lint declare the rule blocking and the Makefile advertises it as catching a broken relative link; ~18 broken anchors sit on a green tree. Proposed: extend the rule to slug the target file's ATX headings and validate the fragment, landing warn-first
links_resolve (internal/core/lint/lint.go checkLinks) strips the #fragment before resolving and skips same-file # links, so no gate validates heading anchors even though both record-lint and docs-lint declare the rule blocking and the Makefile advertises it as catching a broken relative link; ~18 broken anchors sit on a green tree. Proposed: extend the rule to slug the target file's ATX headings and validate the fragment, landing warn-first
Evidence
internal/core/lint/lint.gocheckLinksstrips the#…?fragment beforeos.Statandcontinues on same-file#links, so a heading anchor is never validated. Both.abcd/record-lint.jsonand.abcd/docs-lint.jsonmarklinks_resolveblocking, and the Makefile advertises docs-lint as catching "a broken relative link".- Consequence: ~18 broken heading anchors sit in
.abcd/developmenton a green tree (see iss-298), and the resolved iss-14 deep-link fix re-broke because nothing gates the class.
Adversarial review
CONFIRMED as a feature gap (nitpick, ledger capture — not a code defect: the rule matches its
file-level contract) by an independent refuter. Proposed: an anchor-validating extension to
links_resolve that GitHub-slugs the target's fenced ATX headings, landed warn-first given
the existing residue. A candidate acceptance-corpus entry for iss-46.
Grounds
- pursued: a fragment naming no heading of its target (or of the linking page) is reported at warn while a correct slug, a duplicate's -1 and an HTML anchor pass; a broken anchor on a green tree would show it wrong
Frontmatter
| id | iss-303 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | nitpick |
.abcd/work/issues/resolved/iss-303-links-resolve-internal-core-lint-lint-go.md
open on GitHub ↗ · commit history ↗
mentions5
- dcn-26081900000000032026-08-19 — bughunt round 1 (branch bughunt-b/round-1): captured iss-291..iss-304 and fixed
- iss-14stale deep links: 04-surfaces README and 01-agents.md point to the intent reviewer as 05-intent.md section 6, but that section now appears later.
- iss-46lint scope holes and gate parity: link-lint does not cover all committed markdown; the persona rule is absent from docs-lint; record-lint blocking semantics are inconsistent between local and CI and there is no warn-baseline ratchet; gofmt is missing from make preflight though attributed to it; repo-local hooks activation and its provisioning dependency are undocumented. Detector (per ratchet-not-big-bang): a lint scope matrix (which rule covers which tree, checked into the record) plus baseline-ratchet support in record-lint so new rules arm immediately against frozen violations. Acceptance corpus: the five holes above.
- iss-298The brief carries broken and stale intra-record cross-references invisible to links_resolve (which strips the #fragment before resolving): six deep links name headings that were renamed or renumbered (04-launch.md, 04-universal-patterns.md, 01-ahoy.md, 05-intent.md sections 5/6/7), ten anchors mis-encode an em dash, 00-meta.md cites a deleted disembark section-3 budget rule, and three live README lines cite the pre-split monolithic brief by section number
- iss-352three current-state records cite ADRs at development/research/adr/, a path that does not exist and a layout adr-30 explicitly rejected; all three are backticked code spans links_resolve never checks