Repository navigation
Description
Problem
script/check-proto-reads.ts:31 scans exactly one tree:
export const SCAN_ROOT = "packages/core/src"The gate is the regression net for the prototype-chain dictionary-read class (#865, follow-up to the #833 audit): a bare record[key] read walks the prototype chain, so an externally supplied key like "constructor" resolves to an inherited member and a ?? fallback never fires. Two extensions are already tracked — #912 (packages/ai, PR #919) and #1361 (packages/plugin-github) — and #912 explicitly scopes every other package out. Every other production tree remains unscanned, and the class has already bitten in unscanned trees: latex (#937), web (#851), console (#1323).
Evidence (main 6eb5339, verified this run)
Replicating the gate's exact three patterns (P-A / P-C / P-D) over the remaining packages/*/src trees (plus the console/stats subtrees; services/* and server/sdk/plugin/web/function return 0) yields 194 hits across 17 trees, none dispositioned — the allowlist has zero entries for any of them:
| tree | hits | tree | hits |
|---|---|---|---|
| packages/merman/src | 77 | packages/stats/app/src | 6 |
| packages/tui/src | 25 | packages/desktop/src | 5 |
| packages/client/src | 24 | packages/latex/src | 5 |
| packages/gui-extensions/src | 16 | packages/cli/src | 4 |
| packages/app/src | 11 | packages/console/app/src | 4 |
| packages/stats/core/src | 9 | packages/codemode/src, packages/theme/src | 2 each |
| packages/httpapi-codegen/src, packages/plugin-browser/src, packages/ui/src, packages/util/src | 1 each |
Control: the same replication over packages/core/src returns 45 hits, all allowlisted — the replication matches the gate.
Spot-reads of the dangerous shape (externally influenced key, ?? fallback that can never fire):
packages/stats/core/src/domain/model-normalization.ts:50—MODEL_NAME_ALIASES[resolved.toLowerCase()] ?? resolved; model names are provider-supplied, so a model namedconstructorreturns the Object constructor instead of its name — the exact shape of fix(core): AISDK toolNames reads through the prototype chain — a provider tool id of "constructor" yields the Object function as the tool name #1085.packages/stats/core/src/domain/home.ts:1142—aliases[slug] ?? slug;:1087—known[normalized] ?? ….packages/latex/src/parser.ts:609—negated[value] ?? …over parsed document input; fix(latex): parser command tables read through the prototype chain — "\constructor{x}" becomes an accent node holding the Object function #937 already fixed this same class in this package's parser command tables, and this table sits outside the net.packages/merman/src/core/geometry.ts:135/139/143/147—DIRECTION_AXIS[direction],DIRECTION_SIGN[direction],DIRECTION_SIDE[direction],OPPOSITE_SIDE[side], keyed by direction strings parsed from user-authored diagram text.packages/tui/src/mini/theme.ts:315—custom[name] ?? allThemes()[name] ?? …, wherenamecomes from user theme config.
Many hits are plainly dispositionable (numeric-index reads; dot-prefixed extension keys like packages/tui/src/component/prompt/local-attachment.ts:22; server-generated session IDs in packages/client/src/solid/data.ts) — but today none of that is recorded, so the next bare read in any of these trees lands silently.
Why it matters
The fleet has fixed this bug class at least nine times (#792, #851, #906, #907, #908, #916, #937, #1085, #1319, #1323). The net that prevents recurrence covers one tree, with two more in flight. Until the remaining production trees are scanned and dispositioned, each new table read in them is an unguarded recurrence risk — including in packages that parse untrusted input (latex, merman) or consume provider-supplied strings (stats).
Acceptance criteria
script/check-proto-reads.tsscans every productionpackages/*/srctree (including the console and stats subtrees) in addition to its existing root(s), coordinated with fix(ci): check:proto-reads scans only packages/core/src — packages/ai, where the class keeps biting, has no regression net #912's multi-root conversion and fix(ci): check:proto-reads does not scan packages/plugin-github — GitHub API / Copilot table reads escape the regression net (#1319's class) #1361 so the three efforts compose instead of colliding; gate unit tests updated and green.- Every current hit in the newly scanned trees is dispositioned: guarded at the site (e.g.
ownValue/ownOrfrompackages/core/src/util/record.tsorObject.hasOwn), or allowlisted with a specific per-entry reason per existing conventions. - Any hit that is a live bug (externally influenced key reaching a table read with behavioral effect) is filed as its own issue and cross-linked, not allowlisted away.
bun run check:proto-readspasses on the resulting tree.- No behavior change to any hit dispositioned as safe/internal.
Scope notes
- Out of scope: packages/ai (fix(ci): check:proto-reads scans only packages/core/src — packages/ai, where the class keeps biting, has no regression net #912) and packages/plugin-github (fix(ci): check:proto-reads does not scan packages/plugin-github — GitHub API / Copilot table reads escape the regression net (#1319's class) #1361) — this issue covers the trees neither of those touches; landing order should follow fix(ci): check:proto-reads scans only packages/core/src — packages/ai, where the class keeps biting, has no regression net #912's SCAN_ROOTS conversion.
- Cross-references: audit(core): shared own-property guard + regression net for prototype-chain dictionary reads (#833 follow-up) #865, audit(core): prototype-chain dictionary lookups — systematic sweep, shared guard, regression net #833, fix(ci): check:proto-reads scans only packages/core/src — packages/ai, where the class keeps biting, has no regression net #912, fix(ci): check:proto-reads does not scan packages/plugin-github — GitHub API / Copilot table reads escape the regression net (#1319's class) #1361, fix(core): AISDK toolNames reads through the prototype chain — a provider tool id of "constructor" yields the Object function as the tool name #1085, fix(latex): parser command tables read through the prototype chain — "\constructor{x}" becomes an accent node holding the Object function #937.
Activity
dezren39 commentedon Nov 2, 2026
🤖 Agent note · filed
script/check-proto-reads.ts:31SCAN_ROOT is the singularpackages/core/src, so the remaining production trees have no prototype-chain regression net even though the class has already bitten in unscanned trees (fix(latex): parser command tables read through the prototype chain — "\constructor{x}" becomes an accent node holding the Object function #937 latex, fix(web): docs locale lookups read through the prototype chain — "constructor" and "__proto__" become garbage redirects #851 web, fix(console): locale resolution reads DOCS_LOCALE through the prototype chain and throws URIError on a malformed oc_locale cookie #1323 console). Gate-pattern replication on main 6eb5339: 194 undispositioned hits across 17 trees (merman 77, tui 25, client 24, gui-extensions 16, app 11, stats/core 9, stats/app 6, desktop 5, latex 5, cli 4, console/app 4, codemode 2, theme 2, httpapi-codegen/plugin-browser/ui/util 1 each); allowlist has 0 entries for them; core control replication = 45 hits, all allowlisted. Spot-reads include provider-supplied model names (stats/core model-normalization.ts:50), parsed diagram text (merman geometry.ts:135-147), and parsed document input (latex parser.ts:609).bun run check:proto-readsis green with no behavior change to safe/internal hits.dezren39 commentedon Nov 2, 2026
Triage — CONFIRMED (task 6117)
Verified on fresh main
6eb53396b58967b7896788d055e24b77a5a92bae(gh api, 2026-11-02):script/check-proto-reads.ts:31still exports the singularexport const SCAN_ROOT = "packages/core/src"— the gate scans onlypackages/core/src; no multi-root conversion has landed.script/check-proto-reads.allowlist.txthas 46 entries, allpackages/core/src, and 0 entries for any of the 17 remaining trees — none of the 194 filed hits is dispositioned.packages/stats/core/src/domain/model-normalization.ts—MODEL_NAME_ALIASES[resolved.toLowerCase()] ?? resolvedover provider-supplied model names (the fix(core): AISDK toolNames reads through the prototype chain — a provider tool id of "constructor" yields the Object function as the tool name #1085 shape).packages/latex/src/parser.ts—negated[value] ?? …over parsed document input.Sequencing gate (fresh check): PR #919 (#912, packages/ai) is still OPEN (head
bb538bf95a, branchqueue/3577-912-proto-reads-ai) and convertsSCAN_ROOT→SCAN_ROOTS = [core, ai], touching the same four files (script/check-proto-reads.ts,script/check-proto-reads.test.ts,script/check-proto-reads.allowlist.txt,.github/workflows/test.yml). Fix task 6078 (#1361, plugin-github as third root) is parked on the same gate. No competing conversion may be created.Routing: one fix task enqueued — task 6121 (
packet-opencode-1369-fix.json, small_fix, effort/m scope): extendSCAN_ROOTSto every remaining production tree on top of PR #919's merged shape, disposition all 194 hits (site guard or specific allowlist reason; file any live bug separately), keepbun run check:proto-readsgreen. The fix task parks naming PR #919 if it is still open when claimed.No hard-stop labels present on #1369 at claim; labels synced: triage claimed → triage complete, issue now
queue/queuedfor task 6121,status/needs-triageremoved.dezren39 commentedon Nov 2, 2026
Fix task 6121 — PARKED on sequencing gate PR #919
Claimed by Lane A (
repo-worker-opencode, task 6121) on 2026-11-02 and revalidated fresh:mergedAt=null, headbb538bf95a31c71581c8e047b2825d4a37ae7e00— unchanged.SCAN_ROOT→SCAN_ROOTSand touches the same four files this fix must build on (script/check-proto-reads.ts,script/check-proto-reads.test.ts,script/check-proto-reads.allowlist.txt,.github/workflows/test.yml).Resume condition: PR #919 merged. Then build on the merged
SCAN_ROOTSshape (composing with #1361 / task 6078's plugin-github root if landed), extend the gate to the remaining 17 production trees, and disposition all 194 hits. Parked 24h.Labels synced:
queue/parked+status/parked+work/assigned.24 remaining items
dezren39 commentedon Nov 4, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 4, 2026
🤖 Agent note · parked
fix(ci): extend check:proto-reads gate to every production src tree (#…
dezren39 commentedon Nov 4, 2026
🤖 Agent note · done