Filed by the #13217 dev (branch claude/issue-13217-page-walk-cycle-guard, session session_01CPrUz21stTFhJRUirdc4yw) while measuring that card's blast-radius claim. Out of scope there: #13217's fence is "add the cycle guard to walkPageComponents, change nothing else", and this is a different function with a different shape. Ungraded and unrouted — domain:*, type and priority are triage's to produce.
Dedupe run before filing, positive control first: a control query for the #13217 anchor returned 2 hits (#13217, #13218 — pool live), then the subject query returned 18 hits with no open duplicate (#12138 is a different recursion, in check:durability-log-level; #11255 is this auditor's origin card, not a cycle report).
Measured
packages/lint/src/page-envelope-audit.ts — collectBare (line 169) is a lockstep raw/parsed value walker: it recurses through every key of the authored value and its parsed counterpart in parallel, collecting positions where an authored string became an expression envelope. It carries no cycle guard.
It is reached from auditPageExpressionEnvelopes at Door 1 (line 264), which walks the WHOLE page:
line 261 // Door 1 -- the whole page through PageSchema
line 264 collectBare(page, parsedPage.data, '', pageLabel, 'PageSchema', raw);
line 269 // Doors 2 and 3 -- every component the page walk reaches
line 276 const walked = walkPageComponents(page, '');
⚠️Door 1 runs BEFORE the shared walk. So on a page whose properties.children contains itself, page-envelope-audit never reaches walkPageComponents at all — it dies at line 264 first.
Measured on this branch, with #13217's cycle guard already landed in walkPageComponents:
RangeError: Maximum call stack size exceeded
at collectBare (packages/lint/src/page-envelope-audit.ts:169:17)
at collectBare (packages/lint/src/page-envelope-audit.ts:186:7)
at collectBare (packages/lint/src/page-envelope-audit.ts:210:5)
...
Input: an ordinary page carrying A -> B -> A through properties.children, components otherwise valid. properties.children is z.array(z.unknown()), so this is legal authored input, not a malformed document.
Why this matters for #13217's card body
#13217 lists page-envelope-audit among the six rules its crash takes down. That membership is real — the rule does die on a cyclic page. But the cause is NOT the missing walk guard, and fixing walkPageComponents does not fix it. The other five named rules and the CLI object-sections pass were measured green on the same input after #13217's guard; page-envelope-audit alone still dies, here.
⇒ #13217 is not a partial fix of its own stated scope — it fully fixes the walk. This is a second, independent defect of the same class that the card's blast-radius list happened to cover by name.
⚠️ What is NOT asserted
Re-check
git grep -n "collectBare" -- packages/lint/src/page-envelope-audit.ts
git grep -n "seen\|ancestor\|cycle\|WeakSet" -- packages/lint/src/page-envelope-audit.ts
⛔ Reverse-check the zero against a term known present in the same file: collectBare IS present there, and the cycle-guard terms are present in packages/lint/src/page-walk.ts after #13217 — so "absent here, present there" is the reading, not an instrument failure.
Refs
Generated by Claude Code
Filed by the #13217 dev (branch
claude/issue-13217-page-walk-cycle-guard, sessionsession_01CPrUz21stTFhJRUirdc4yw) while measuring that card's blast-radius claim. Out of scope there: #13217's fence is "add the cycle guard towalkPageComponents, change nothing else", and this is a different function with a different shape. Ungraded and unrouted —domain:*, type and priority are triage's to produce.Dedupe run before filing, positive control first: a control query for the #13217 anchor returned 2 hits (#13217, #13218 — pool live), then the subject query returned 18 hits with no open duplicate (#12138 is a different recursion, in
check:durability-log-level; #11255 is this auditor's origin card, not a cycle report).Measured
packages/lint/src/page-envelope-audit.ts—collectBare(line 169) is a lockstep raw/parsed value walker: it recurses through every key of the authored value and its parsed counterpart in parallel, collecting positions where an authored string became an expression envelope. It carries no cycle guard.It is reached from
auditPageExpressionEnvelopesat Door 1 (line 264), which walks the WHOLE page:properties.childrencontains itself,page-envelope-auditnever reacheswalkPageComponentsat all — it dies at line 264 first.Measured on this branch, with #13217's cycle guard already landed in
walkPageComponents:Input: an ordinary page carrying
A -> B -> Athroughproperties.children, components otherwise valid.properties.childrenisz.array(z.unknown()), so this is legal authored input, not a malformed document.Why this matters for #13217's card body
#13217 lists
page-envelope-auditamong the six rules its crash takes down. That membership is real — the rule does die on a cyclic page. But the cause is NOT the missing walk guard, and fixingwalkPageComponentsdoes not fix it. The other five named rules and the CLI object-sections pass were measured green on the same input after #13217's guard;page-envelope-auditalone still dies, here.⇒ #13217 is not a partial fix of its own stated scope — it fully fixes the walk. This is a second, independent defect of the same class that the card's blast-radius list happened to cover by name.
collectBareis NOT the same instrument as the two component walks, sowalkPageComponentshas no cycle guard — a self-referentialproperties.childrenrecurses until the stack dies, taking six lint rules and the i18n object-sections pass with it #13217's ancestor-set is a starting point, not a drop-in:rawandparsed), so "which side does the ancestor set track" is a real decision;walkPageComponentshas no cycle guard — a self-referentialproperties.childrenrecurses until the stack dies, taking six lint rules and the i18n object-sections pass with it #13217's dispatch reserved.Re-check
⛔ Reverse-check the zero against a term known present in the same file:
collectBareIS present there, and the cycle-guard terms are present inpackages/lint/src/page-walk.tsafter #13217 — so "absent here, present there" is the reading, not an instrument failure.Refs
walkPageComponentshas no cycle guard — a self-referentialproperties.childrenrecurses until the stack dies, taking six lint rules and the i18n object-sections pass with it #13217 — the shared-walk cycle guard; where this was measuredtranslatePage's addressed-component walk is not exported, so the CLI extractor hand-mirrors its depth cap, cycle guard and collision arbitration — the copy hazard the key list closed, left open for the walk #13218 — the other walk-copy card; ⛔ this is a THIRD walk, not covered by that card's unify scopeGenerated by Claude Code