Development record
A memory page FILENAME is never judged by the store redactor, so a secret-shaped slug reaches the committed tree as a filename, in index.md and log.md, and now also as the registry back-link. slugRe admits [A-Za-z0-9_-] and pageNameRe admits <type>_<domain>_<slug>.md, so a host distiller returning slug ghp_<40 chars> writes topic_auth_ghp_....md verbatim; redactLeaves judged only leaf VALUES and KEYS, and excluding the registry back-links (the pruneOrphans data-loss fix) removed the accidental partial coverage the registry rewrite gave. Evidence: validatePageFilename in internal/core/memory/writer.go and DistilledPage.Filename in schema.go; reproduced on this branch (filename, index.md and .sources_index.json all carry the token). The fix must judge the filename at the write boundary and REFUSE rather than rewrite, as judgeKey does for a map key. It needs a decision first: storeRedactor.residue uses BlockingResidual, which treats a warn-severity network span as blocking, and an ordinary slug such as [redacted-hostname] matches net_device_hostname — so the filename rule must run at a narrower bar (hard_fail secrets only) or an ordinary page would be refused.
A memory page FILENAME is never judged by the store redactor, so a secret-shaped slug reaches the committed tree as a filename, in index.md and log.md, and now also as the registry back-link. slugRe admits [A-Za-z0-9_-] and pageNameRe admits <type><domain><slug>.md, so a host distiller returning slug ghp_<40 chars> writes topic_auth_ghp_....md verbatim; redactLeaves judged only leaf VALUES and KEYS, and excluding the registry back-links (the pruneOrphans data-loss fix) removed the accidental partial coverage the registry rewrite gave. Evidence: validatePageFilename in internal/core/memory/writer.go and DistilledPage.Filename in schema.go; reproduced on this branch (filename, index.md and .sources_index.json all carry the token). The fix must judge the filename at the write boundary and REFUSE rather than rewrite, as judgeKey does for a map key. It needs a decision first: storeRedactor.residue uses BlockingResidual, which treats a warn-severity network span as blocking, and an ordinary slug such as [redacted-hostname] matches net_device_hostname — so the filename rule must run at a narrower bar (hard_fail secrets only) or an ordinary page would be refused.
Grounds
- pursued: judging the filename in WritePages before renderWrites and before the store lock closes all four landing places at once, because the page file and the log event derive from the rendered write, index.md is reconciled from the files on disk, and the registry back-link is merged inside the lock — none reached once the judge returns an error; and the bar is scanner.SeverityHardFail alone rather than BlockingResidual, because a page name is prose-shaped and a warn-severity hostname match would refuse ordinary pages. It would be shown wrong by an ordinary slug being refused, or by a page filename reaching the store through a path that does not go through WritePages.
Frontmatter
| id | iss-2609020321100138 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | major |
.abcd/work/issues/resolved/iss-2609020321100138-a-memory-page-filename-is-never-judged.md
open on GitHub ↗ · commit history ↗
mentions1
- iss-2609090642035097The write boundary now refuses a memory page whose filename carries a hard-fail secret, but a store written before that change is not repaired and the read side cannot report it. The MR001 lint scans stored text and the registry bytes, and a token embedded in a page name such as topic_auth_ghp_ is hidden from it by the same missing word boundary the write-side fix had to work around: underscore is a word character, so an anchored token pattern finds no boundary after the type and domain prefix and the span never matches. A legacy dirty filename therefore sits in the committed tree, in index.md, in log.md and in the registry back-link, and no instrument reports it. The write-side fix deliberately left this alone to keep its commit to one record. Fix: give the read-side scan the same component-wise treatment the write side uses, splitting a page name into its type, domain and slug parts before matching rather than relying on a boundary the naming grammar cannot provide. Detector: a store seeded with a page whose name embeds a token must be reported by the read-side lint, and an ordinary store must stay clean. Surfaced by the fix for iss-2609020321100138.