Context
Post-merge hardening of the guard shipped by PR #17253 (closing #17240 / #17251). Raised by @neo-opus-grace as three non-blocking review challenges; her approval and the merge both landed before the disposition, so they need their own lane rather than a comment on a closed PR.
The Problem
A — the observer inherits the blind spot of the thing it observes. #17240's defect #1 was an .npmignore rule pinned to apps/devindex/resources/*.json, which silently stopped matching when the corpus moved into data/ and grew a .jsonl. The gate written to catch that class is itself pinned to apps/devindex/resources/data/.
So the identical move — data/ → corpus/ — makes the ignore rule and its observer go vacuous together, and check-package-contents prints OK over a 26.5 MiB leak. That is worse than no gate: a green check is now evidence, and it would be false.
The sibling .neo-ai-data/ rule is already immune, prefix-plus-allowlist, which is what makes this an inconsistency rather than an unknown.
B — a boundary that reads as an omission. FORBIDDEN_PREFIXES names three directories. .npmignore also excludes two generated files (/apps/portal/sitemap.xml, /apps/portal/llms.txt, 3.22 MiB). That asymmetry is deliberate — the prefixes name trees whose leak is a disclosure, while the portal files are already public on neomjs.com so shipping them is waste — but nothing in the file says so, and the next reader sees a gap.
C — parsePackOutput cannot find a payload at offset 0. It matches '\n[\n', requiring a preceding newline. The moment the prepare lifecycle stops writing to stdout the payload begins the string and the helper throws no JSON array found over output that has one. The direction is safe — it reds the gate and can never false-pass — but a guard that breaks on a cleaner environment is one people learn to route around. The docstring also says "the last top-level array" while the code takes the first.
The Fix
- A: re-anchor on
apps/devindex/resources/ with apps/devindex/resources/images/ allowed, matching the .neo-ai-data/ shape. resources/ holds exactly two children today — images/ (one 4 KB SVG) and data/ (26.5 MiB) — so a subtree that does not exist yet is excluded by default and only a deliberate allowlist edit widens it.
- B: state the exposure-vs-bloat tier in the docstring, and assert it, so a later file-shaped rule has to change a test and say why.
- C: accept offset 0; make the doc and the code agree on first.
Acceptance Criteria
Out of Scope
The package.json files-allowlist migration. .npmignore is a deny-list gate over 7,388 entries with every rule load-bearing and none observed; @neo-opus-grace recorded that as the real long-term item on the PR #17253 review. It outlives this hardening and is not a rider on it.
Avoided Traps
- Treating a merged approval as covering later commits. The fold-in landed after #17253 merged; it gets its own review rather than riding a closed PR's badge.
- Fixing A by enumerating today's subdirectory names. That is the same shape as the defect, one rename later.
Related
#17240 / #17251 (closed by PR #17253 — the guard this hardens) · PR #17253 review by @neo-opus-grace
Live latest-open sweep: open issues checked 2026-08-17T07:4xZ; no equivalent — #17240 and #17251 are both CLOSED.
Origin Session ID: 80b326bf-b37a-4efd-8313-1a9eae09e9c4
Context
Post-merge hardening of the guard shipped by PR #17253 (closing #17240 / #17251). Raised by @neo-opus-grace as three non-blocking review challenges; her approval and the merge both landed before the disposition, so they need their own lane rather than a comment on a closed PR.
The Problem
A — the observer inherits the blind spot of the thing it observes. #17240's defect #1 was an
.npmignorerule pinned toapps/devindex/resources/*.json, which silently stopped matching when the corpus moved intodata/and grew a.jsonl. The gate written to catch that class is itself pinned toapps/devindex/resources/data/.So the identical move —
data/→corpus/— makes the ignore rule and its observer go vacuous together, andcheck-package-contentsprintsOKover a 26.5 MiB leak. That is worse than no gate: a green check is now evidence, and it would be false.The sibling
.neo-ai-data/rule is already immune, prefix-plus-allowlist, which is what makes this an inconsistency rather than an unknown.B — a boundary that reads as an omission.
FORBIDDEN_PREFIXESnames three directories..npmignorealso excludes two generated files (/apps/portal/sitemap.xml,/apps/portal/llms.txt, 3.22 MiB). That asymmetry is deliberate — the prefixes name trees whose leak is a disclosure, while the portal files are already public on neomjs.com so shipping them is waste — but nothing in the file says so, and the next reader sees a gap.C —
parsePackOutputcannot find a payload at offset 0. It matches'\n[\n', requiring a preceding newline. The moment thepreparelifecycle stops writing to stdout the payload begins the string and the helper throwsno JSON array foundover output that has one. The direction is safe — it reds the gate and can never false-pass — but a guard that breaks on a cleaner environment is one people learn to route around. The docstring also says "the last top-level array" while the code takes the first.The Fix
apps/devindex/resources/withapps/devindex/resources/images/allowed, matching the.neo-ai-data/shape.resources/holds exactly two children today —images/(one 4 KB SVG) anddata/(26.5 MiB) — so a subtree that does not exist yet is excluded by default and only a deliberate allowlist edit widens it.Acceptance Criteria
apps/devindex/resources/<any-new-name>/is a finding.startsWithon the allow entry must hold at any depth).parsePackOutputparses a payload beginning at offset 0 and one preceded by lifecycle stdout.npm pack— the only thing that settles what ships.Out of Scope
The
package.jsonfiles-allowlist migration..npmignoreis a deny-list gate over 7,388 entries with every rule load-bearing and none observed; @neo-opus-grace recorded that as the real long-term item on the PR #17253 review. It outlives this hardening and is not a rider on it.Avoided Traps
Related
#17240 / #17251 (closed by PR #17253 — the guard this hardens) · PR #17253 review by @neo-opus-grace
Live latest-open sweep: open issues checked 2026-08-17T07:4xZ; no equivalent — #17240 and #17251 are both CLOSED.
Origin Session ID: 80b326bf-b37a-4efd-8313-1a9eae09e9c4