You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Under OS_EAGER_SCHEMAS=1, entering a deep spec leaf module first dies on a strict-object ↔ field.zod TDZ #6267
Observation-class finding, measured while working #4415 on origin/main @ 8e2bbba24. Nothing a user hits today — filing so it is recorded rather than rediscovered.
What happens
Under OS_EAGER_SCHEMAS=1 (the documented lazySchema rollback switch, which gen:schema / check:authorable-surface set), importing a deep leaf schema module as the process entry point throws during module evaluation:
$ OS_EAGER_SCHEMAS=1 node --import tsx --input-type=module \
-e "import './packages/spec/src/automation/control-flow.zod.ts'; console.log('ok');"
/packages/spec/src/shared/strict-object.ts:255
DECLARATIONS.push({ options, shape });
^
ReferenceError: Cannot access 'DECLARATIONS' before initialization
at strictObject (packages/spec/src/shared/strict-object.ts:255:3)
at (packages/spec/src/data/field.zod.ts:113:52)
at lazySchema (packages/spec/src/shared/lazy-schema.ts:23:12)
at (packages/spec/src/data/field.zod.ts:113:35)
at Object. (packages/spec/src/data/field.zod.ts:1076:1)
Why
DECLARATIONS is a module-level const declared after the strictObject function in strict-object.ts. Eager mode makes lazySchema(factory) run its factory at module-evaluation time, so when the import graph re-enters strictObject() while strict-object.ts is itself still evaluating, the const is still in its temporal dead zone.
Whether that re-entry happens is decided purely by which module the process enters first — it is an ordering property of the graph, not of any one file.
Why it is dormant
Every real entry point goes through a barrel (src/index.ts, src/automation/index.ts), which establishes an order in which strict-object.ts finishes evaluating before anything calls into it. Both eager-mode gates use those barrels, so CI never reaches the bad order. Verified green on the same commit:
$ OS_EAGER_SCHEMAS=1 node ... -e "await import('./packages/spec/src/automation/index.ts')" # ok
Reproduces on origin/main, not caused by any in-flight branch
Measured by checking out the pristine origin/main copies of the two files I was editing and re-running — identical failure, so #4415's changes are not involved.
Possible fix
Hoist DECLARATIONS above strictObject (a one-line move), which removes the TDZ regardless of evaluation order. Worth a quick check for the same shape elsewhere in packages/spec/src/shared/ — alias-table-registry has a similar registry pattern.
No pm:queue: dormant, no user-visible symptom, and the fix is cheap enough to ride along with any future strict-object.ts work.
Findings sweep (maintainer-authorized one-off, 2026-08-07 — registered on #6015): hold confirmed. The TDZ only fires when a process enters via a deep leaf module under the rollback switch — no tool does that today (gen:schema / check:authorable-surface enter via the full graph). Restart: any tool needing leaf-entry eager import, or a strict-object registration refactor touching DECLARATIONS.
Activity
os-project-manager commentedon Aug 8, 2026
Findings sweep (maintainer-authorized one-off, 2026-08-07 — registered on #6015): hold confirmed. The TDZ only fires when a process enters via a deep leaf module under the rollback switch — no tool does that today (
gen:schema/check:authorable-surfaceenter via the full graph). Restart: any tool needing leaf-entry eager import, or a strict-object registration refactor touchingDECLARATIONS.Generated by Claude Code