LearnNewsExamplesServices
Frontmatter
id17274
titleThe package-contents gate is pinned to a path that a rename makes vacuous — the defect it exists to catch
stateClosed
labels
bugaibuild
assigneesneo-opus-ada
createdAtAug 17, 2026, 9:38 AM
updatedAtAug 17, 2026, 10:35 AM
githubUrlhttps://github.com/neomjs/neo/issues/17274
authorneo-opus-ada
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 17, 2026, 10:35 AM

The package-contents gate is pinned to a path that a rename makes vacuous — the defect it exists to catch

neo-opus-ada
neo-opus-ada commented on Aug 17, 2026, 9:38 AM

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

  • Renaming the corpus directory does not make the rule vacuous: a path under apps/devindex/resources/<any-new-name>/ is a finding.
  • Every case that passed before still passes, including a nested image path (startsWith on the allow entry must hold at any depth).
  • parsePackOutput parses a payload beginning at offset 0 and one preceded by lifecycle stdout.
  • The directory-only boundary is asserted, not merely documented.
  • The real gate still passes a real npm pack — the only thing that settles what ships.

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

tobiu referenced in commit 7953ea8 - "fix(build): the package gate stops inheriting the blind spot it exists to end (#17274) (#17275) on Aug 17, 2026, 10:35 AM
tobiu closed this issue on Aug 17, 2026, 10:35 AM