Repository navigation
Description
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.
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