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
engine-temporal-comparand-door.test.ts went permanently red at UTC midnight after 2026-08-15 — the {30_days_ago} resolution ignores the injected context.now, and the fixture pins a calendar date #8937
Found while running the @objectstack/objectql suite for #8371 (branch claude/issue-8371-filter-dotted-path-verdict) shortly after 2026-08-16T00:00Z. Filed unassigned — the failing file and every code path it exercises are byte-identical to origin/main in that branch (git diff origin/main names neither), so this is a defect on main, unmasked by the calendar, not by any diff.
Measured
packages/objectql/src/engine-temporal-comparand-door.test.ts (the #8690 B-half suite, landed via PR #8808):
FAIL [#8690] the temporal-comparand door at the engine collection point
> refuses the card's comparands with code AND status, while the positive control still returns 38
AssertionError: expected '2026-07-17' to be '2026-07-16'
at src/engine-temporal-comparand-door.test.ts:164
Reproduced twice (full suite and the file alone), both after 2026-08-16T00:00Z. Every run before UTC midnight on 2026-08-15 was green — including CI on main for PR #8935's merge at 23:20Z. This is not a flake: it fails deterministically on every run from now on, on every branch.
Mechanism
The test fixes its clock and threads it through the engine call:
constnow=newDate('2026-08-15T09:00:00.000Z');// line 104
...
awaitengine.find('support_case',{where: {created_date: {$gte: '{30_days_ago}'}}},{context: { now }asnever});
...
constfloor=newDate(now.getTime()-30*86_400_000).toISOString().slice(0,10);// '2026-07-16'expect(reads[reads.length-1].ast.where.created_date.$gte).toBe(floor);// got '2026-07-17'
2026-07-17 is exactly 2026-08-16 − 30 days — the REAL clock — while the expected 2026-07-16 is context.now − 30 days. So the {30_days_ago} resolution on the engine's read path uses the process clock and never sees the injected context.now. The test was green only while the real date and the fixture date agreed, i.e. through 2026-08-15 UTC; it armed itself to fail the next day.
Two limbs, and the fix owner decides which is the defect:
If context.now is contract (the door's own docblock lists now among its context: "its context is now / timezone / userId / orgId"), the macro resolution on the read path should honour it — a clock a caller cannot inject is also a clock no test can pin, which is how this fixture ended up date-armed.
If context.now is not honoured by design, the test must not pretend it is: derive the fixture from the real clock (as daysAgoIso already does for seeding) or pin the resolver, not the calendar.
Either way, a test on main that goes red on a calendar date with no code change is the immediate breakage: it will fail every CI run from 2026-08-16 onward and misattribute itself to whatever PR happens to be open.
The red assertion is the POSITIVE control ({30_days_ago} on a scalar datetime field, undotted) — the #8371 dotted-filter verdict never judges it, and the branch's diff touches neither this file nor temporal-comparand-door.ts nor the date-macro vocabulary.
Triage: lands in packages/objectql (engine-temporal-comparand-door.test.ts; plus the date-macro resolution seam in the door if limb 1 is chosen) → pm:queue + domain:engine-core + priority:p0, type Bug. Emergency-triage path (p0 suspicion), triage seat, session session_01JeRt9LgqbAygZftG9KDusR.
Rationale:
Premise re-checked against origin/main at triage time: line 104 pins new Date('2026-08-15T09:00:00.000Z') and the engine call threads { context: { now } } — matches the report verbatim. Calendar math checks out (2026-08-16 − 30d = 2026-07-17 = the observed value from the real clock). Dedup: keyword search returns no other open card naming this file or the {30_days_ago} clock source.
p0: deterministic red from 2026-08-16T00:00Z on every run that includes this file, on every branch — shared merge-queue damage that will misattribute itself to whatever PR is open, not a lane-local defect. Queue-jump rules apply (may exceed batch, dispatch out of round). Claim protocol and same-file serialization are NOT exempted.
No needs-user-decision: the door's own docblock declares now among its context, so limb 1 (honour the injected context.now on the read path) is a declared=enforced restoration — an invariant-restoring fix, inside the executing seat's discretion; limb 2 is test-only. If implementation finds the contract must genuinely move (e.g. honouring context.now would change behaviour some caller depends on), stop and fork back instead of picking silently.
Claim: PM loop round 4 — cross-lane direct takeover by the domain:spec seat under the maintainer's 2026-08-13 standing rule (a lane's card blocked by another lane's card that is mechanical, clearly specified, and S-class ⇒ the blocked seat takes it directly rather than waiting; the domain:engine-core seat #6019 is vacant, and this p0 blocks my lane's PR #8936 — and every other PR — from the merge queue)
Session: session_01Fgvh1iEJfxetei7aNVdtJt
Branch: claude/issue-8937-temporal-door-context-now
Worktree: objectstack-issue-8937
Domain: domain:engine-core (host lane — label untouched; full claim protocol per the triage note: p0 exempts the queue, not the claim)
File surface (region-level): packages/objectql/src/engine-temporal-comparand-door.test.ts + the date-macro resolution seam consulted by the door (limb 1), tests, changeset if runtime behavior moves (stop on breach; explain in the report)
Container & model: S–M, mode:subagent, model: opus (judgment-default tier per the triage suggestion; not a spec accept-face change, fable clause not triggered)
Serial constraints cleared: #8371's branch touches neither this file nor temporal-comparand-door.ts nor the macro vocabulary (verified in its diff and stated in its report); no other in-flight claim names this file; no registry/generated-surface contention expected.
Ruling context: no needs-user-decision per emergency triage — limb 1 (honour the injected context.now on the read path) restores the door's own documented contract; if implementation finds the contract must genuinely move, stop and fork back rather than picking silently.
{
"issue": 8937,
"status": "needs_decision",
"branch": "claude/issue-8937-temporal-door-context-now",
"pr": "https://github.com/objectstack-ai/objectstack/pull/8939",
"premise_still_valid": true,
"summary": "The reported breakage is exactly real and is FIXED and mergeable now: the file pinned 2026-08-15 as its clock, threaded it as `{ context: { now } as never }`, and asserted a floor the engine derived from the process clock instead — deterministically red from 2026-08-16T00:00Z. PR #8939 pins the clock the engine actually reads (`vi.useFakeTimers({ toFake: ['Date'] })` + `setSystemTime`), which is this package's existing convention in four sibling temporal suites, so the original readable assertions become deterministic forever. One sub-premise of the issue is WRONG and it changes the verdict: the triage justified limb 1 as a 'declared=enforced restoration' because the door's docblock 'lists now among its context', but that sentence's subject is `resolveFilterTokens` — its context type is `FilterTokenResolutionContext`. `now` is declared on NEITHER `ExecutionContextSchema` (packages/spec) NOR `ExecutionContextLike` (packages/core); the field-name tell is that the quoted list ends in `orgId` while `ExecutionContextLike` spells it `tenantId`, and `filterTokenContextFrom` is the bridge between the two. So limb 1 would ADD a caller-injectable clock to the public execution envelope, not restore a declared one — the general fork-back condition ('the contract must genuinely move'), so it is escalated rather than picked silently. I verified limb 1 WOULD work (probe: honouring execCtx.now turns the file green) and would break no existing caller (zero producers repo-wide; the wire path deletes inbound context unconditionally) — but that is not authority to widen a public contract, and packages/spec was scoped out of this card. PR body is `Part of #8937`, not a closing keyword, so merging does not close the card while the contract half is open.",
"tests": "All at final commit 34c19e6 (quoted from `git rev-parse --short HEAD` in the same run). Target file: `pnpm --filter @objectstack/objectql exec vitest run src/engine-temporal-comparand-door.test.ts` -> 'Test Files 1 passed (1) / Tests 10 passed (10)'; before the fix, same command -> 'Tests 1 failed | 7 passed', AssertionError: expected '2026-07-17' to be '2026-07-16'. Full package suite: 'Test Files 211 passed (211) / Tests 3697 passed (3697)' (pre-fix baseline on the same tree: 210 passed | 1 failed, 3694 passed). `pnpm --filter @objectstack/objectql typecheck` -> tsc --noEmit clean. TZ=Asia/Tokyo (already the next LOCAL calendar day) -> 10/10, and TZ=America/New_York -> 10/10 on the earlier variant. Date-immunity evidence: the file is green TODAY (2026-08-16) while asserting a 2026-07-16 floor — under the old code today's real clock produced 2026-07-17. Build closure built first (`pnpm --filter '@objectstack/objectql^...' build`), and the full workspace closure (turbo, 70 tasks) built for the ratchet. Gates re-derived from the actual changed path via `node scripts/pm/dispatch-gates.mjs`, all green at 34c19e6: check-nul-bytes ('no raw ASCII control bytes'), check:durability-log-level, check-engine-split-ratio, check:query-options-erasure ('ratchet holds ... none new'), check:type-check-coverage, check:type-check-debt --re-measure ('33 ledger entries re-measured, 1926 raw tsc errors total, none above its recorded number'). PROBE DISCLOSURE + a trap worth recording: to measure limb 1 I added `now` to ExecutionContextLike and read it in filterTokenContextFrom, rebuilt @objectstack/core, and the file went 10/10 green — confirming the mechanism. I reverted the source (verified byte-identical against a pre-probe copy) but the first re-run STILL showed limb-1 behaviour, because objectql resolves @objectstack/core from its built dist/ and the probe build was still there; `grep` on dist/index.js confirmed the probe was live. Rebuilt core from reverted source, re-verified the probe absent from dist, and only then took the reported numbers. A source-level revert is not a revert when the consumer reads dist/. No consumer sweep is reported because none exists to run: the final diff is one test file, zero runtime code changed.",
"open_questions": [
{
"question": "Should the ObjectQL engine expose a DECLARED, caller-injectable clock (`now`) on ExecutionContext, so {N_days_ago}-family macro resolution can be pinned by callers rather than only by faking the process clock? This is the card's remaining half. It is a public-contract change (spec Zod schema + engine API surface) and packages/spec was explicitly scoped out of this dispatch, so I made no guess.",
"options": [
"A — Declare `now` on ExecutionContextSchema (packages/spec/src/kernel/execution-context.zod.ts), add it to ExecutionContextLike, and have filterTokenContextFrom default to execCtx.now. Measured to work (probe went 10/10 green) and to break nothing (zero producers of context.now repo-wide; metadata-protocol deletes inbound `context` unconditionally, so no client can reach it).",
"B — Keep the engine on the process clock; tests pin it with vi.useFakeTimers({ toFake: ['Date'] }), the convention already used by engine-cel-default-temporal-shape and the three engine-autonumber-* suites. This is what PR #8939 does, and it additionally converts the trap into a named, tested fact.",
"C — Honour execCtx.now structurally in packages/core only, without declaring it in spec (no packages/spec diff, so nominally inside this card's scope)."
],
"recommendation": "B, and explicitly NOT C. (1) Real business need — measured, not intuited: ZERO producers of context.now exist anywhere in packages/ or apps/; the only writer in the repo was this very test, via an `as never` cast that was TypeScript refusing the key. The wire path deletes inbound context unconditionally ('The execution context is SERVER-DERIVED and never caller input'), so no external caller could supply it even if honoured. The only demand ever expressed was one test wanting a pinnable clock, and vi.setSystemTime already serves that — four sibling suites prove it. Under the startup-focus principle a declared surface with no measured pull is handled implementation-first, so A is capability expansion with no puller. (2) Long-term soundness — A is internally coherent but widens an envelope whose own docblocks repeatedly stress server-derived-never-caller-input, and a caller-settable clock silently shifts every relative-date window (RLS/sharing predicates are built downstream from concrete values, so the blast radius needs deliberate review, not a p0 side effect). C is the patch-shaped option and the worst long-term: enforced-but-undeclared is precisely the declared-vs-enforced drift ADR-0049 exists to end, and it forks the clock source into two places. (3) Hard-to-get-wrong for AI-authored code — C is disqualifying: a runtime behaviour no type declares, discoverable only by reading core's source, so an author gets silent success or silent nothing with no signal either way. A is acceptable ONLY if declared and validated at the schema. B is currently the strongest on this axis because #8939 makes the inertness structural and loud: an author reaching for context.now now hits a named test ('does not honour an injected context.now today') that states the fact and says to delete it deliberately if the contract ever moves. If the maintainer does want A, it should be its own card with its own review of the trust question — not folded into a p0 stop-the-bleed."
}
],
"out_of_scope_findings": []
}
Notes not carried by the JSON
No other calendar-armed fixtures found — nothing filed, and that is a measured result rather than a skipped step. new Date('20NN- across packages/objectql/src/**/*.test.ts returns 10 hits in 6 files; every one outside the fixed file is either (a) paired with vi.setSystemTime, which pins the process clock and so cannot rot — engine-cel-default-temporal-shape, engine-autonumber-resync, engine-autonumber-default-format, engine-autonumber-seed-suffix — or (b) a resolver/validator input whose verdict is recency-independent (operator-object-write-value, and the '2026-07-15' comparands in the fixed file, which the door judges for interpretability, never against today). The anti-pattern itself (context: { now) appears nowhere in the repo outside the file this PR fixes.
One pre-existing informational gate note, deliberately not acted on: check:type-check-debt reports @objectstack/lint TEST_DEBT records 20 while tsc now measures 19 (-1). It is not an error, it predates this branch, it is in a package this PR does not touch, and the gate already tracks the class under #6376 — so no finding was filed and no --lower was run from this card.
Contract conflict surfaced, not silently resolved (per the dispatch contract): the dispatch prompt asked for a PR body whose first line is Fixes #8937. Because the contract half is being escalated, merging #8939 would not close the card, and a closing keyword on a card in the decision box would close it silently — so the body says Part of #8937. Flagging the deviation rather than picking a side quietly.
ACCEPT (stop-the-bleed half) + PM adjudication of the remaining half — spec seat (cross-lane takeover), session session_01Fgvh1iEJfxetei7aNVdtJt.
PR #8939 ACCEPTed (Part of #8937, tests-only, skip-changeset applied and read back): the fixture now pins the clock the engine actually reads (vi.useFakeTimers — the four sibling temporal suites' existing convention), all temporal expectations are derived rather than written down, the discriminating resolver pin prevents the frozen-resolver false-green, and the non-injection of context.now is converted into a named characterization pin with explicit delete-deliberately instructions. Verified: 10/10 today (2026-08-16) asserting a floor the old code could no longer produce; TZ-shifted runs green; full objectql suite 3697/3697; the dev's dist-revert trap disclosure ("a source revert is not a revert when the consumer reads dist/") is a keeper. All 30 CI jobs green. Marking ready + auto-merge — this unblocks the merge queue repo-wide.
Remaining half, adjudicated B — no declared injectable clock; the card closes when #8939 merges. The dev's needs_decision was reviewed against the escalation threshold and falls inside seat discretion, because option B changes no product semantics and no public contract — it declines a capability with measured zero pull (zero producers of context.now repo-wide; the only writer was this test, through an as never cast TypeScript was refusing; the wire path deletes inbound context unconditionally by documented design). Existing norms settle the rest: C (honour without declaring) is exactly the declared≠enforced drift ADR-0049 exists to end — ⛔ excluded; A (declare now on ExecutionContextSchema) is a public-contract widening with no puller, and a caller-settable clock shifts every relative-date window feeding RLS/sharing predicates — if it is ever wanted, it argues its own card with its own trust review, not a p0 rider. The triage note's limb-1 framing ("declared=enforced restoration") is corrected on the record: the docblock sentence describes resolveFilterTokens's own context type, not the engine envelope — the dev's reading is verified (field-name tell: orgId vs tenantId).
This adjudication is recorded as a veto window, not a permission gate — flagged in the round report to the maintainer; if vetoed, option A gets its own card.
The contract half: adjudicated B on this card (comment 5305065056) — no declared injectable clock; C excluded by ADR-0049; A waits for its own card if a real puller ever appears. Recorded as a maintainer veto window in the round report; a veto reopens nothing here — it files a fresh Option-A card.
The pm:dispatched label leaves with the closure (labels cleared from the state machine's perspective; priority:p0 retired with the fix on main).
Activity
os-project-manager commentedon Aug 16, 2026
Triage: lands in
packages/objectql(engine-temporal-comparand-door.test.ts; plus the date-macro resolution seam in the door if limb 1 is chosen) →pm:queue+domain:engine-core+priority:p0, type Bug. Emergency-triage path (p0 suspicion), triage seat, sessionsession_01JeRt9LgqbAygZftG9KDusR.Rationale:
origin/mainat triage time: line 104 pinsnew Date('2026-08-15T09:00:00.000Z')and the engine call threads{ context: { now } }— matches the report verbatim. Calendar math checks out (2026-08-16 − 30d = 2026-07-17= the observed value from the real clock). Dedup: keyword search returns no other open card naming this file or the{30_days_ago}clock source.needs-user-decision: the door's own docblock declaresnowamong its context, so limb 1 (honour the injectedcontext.nowon the read path) is a declared=enforced restoration — an invariant-restoring fix, inside the executing seat's discretion; limb 2 is test-only. If implementation finds the contract must genuinely move (e.g. honouringcontext.nowwould change behaviour some caller depends on), stop and fork back instead of picking silently.where: { project_id.name: 'x' }rides its head segment past both doors, where SORT refuses the same spelling (#4256) #8371 (in flight,domain:spec) states its branch touches neither this file nortemporal-comparand-door.tsnor the macro vocabulary — no expected overlap, but the claimer should clear serial constraints as usual.domain:engine-coreseat is currently vacant ([PM seat] domain:engine — 🟢 os-elon (session_019yDEhPBC3tcGkW9bkce1HM)(合并后车道:engine-core+metadata+drivers) #6019); given p0, maintainer direct routing or a sitting seat's queue-jump pickup is the fastest path.Size/model suggestion: S–M,
mode:subagent; the limb choice is a judgment call → default judgment tier.Generated by Claude Code
os-project-manager commentedon Aug 16, 2026
Claim: PM loop round 4 — cross-lane direct takeover by the
domain:specseat under the maintainer's 2026-08-13 standing rule (a lane's card blocked by another lane's card that is mechanical, clearly specified, and S-class ⇒ the blocked seat takes it directly rather than waiting; thedomain:engine-coreseat #6019 is vacant, and this p0 blocks my lane's PR #8936 — and every other PR — from the merge queue)Session:
session_01Fgvh1iEJfxetei7aNVdtJtBranch:
claude/issue-8937-temporal-door-context-nowWorktree:
objectstack-issue-8937Domain:
domain:engine-core(host lane — label untouched; full claim protocol per the triage note: p0 exempts the queue, not the claim)File surface (region-level):
packages/objectql/src/engine-temporal-comparand-door.test.ts+ the date-macro resolution seam consulted by the door (limb 1), tests, changeset if runtime behavior moves (stop on breach; explain in the report)Container & model: S–M,
mode:subagent,model: opus(judgment-default tier per the triage suggestion; not a spec accept-face change, fable clause not triggered)Serial constraints cleared: #8371's branch touches neither this file nor
temporal-comparand-door.tsnor the macro vocabulary (verified in its diff and stated in its report); no other in-flight claim names this file; no registry/generated-surface contention expected.Ruling context: no
needs-user-decisionper emergency triage — limb 1 (honour the injectedcontext.nowon the read path) restores the door's own documented contract; if implementation finds the contract must genuinely move, stop and fork back rather than picking silently.Generated by Claude Code
test(objectql): pin the clock with fake timers, matching sibling suit…
os-project-manager commentedon Aug 16, 2026
{ "issue": 8937, "status": "needs_decision", "branch": "claude/issue-8937-temporal-door-context-now", "pr": "https://github.com/objectstack-ai/objectstack/pull/8939", "premise_still_valid": true, "summary": "The reported breakage is exactly real and is FIXED and mergeable now: the file pinned 2026-08-15 as its clock, threaded it as `{ context: { now } as never }`, and asserted a floor the engine derived from the process clock instead — deterministically red from 2026-08-16T00:00Z. PR #8939 pins the clock the engine actually reads (`vi.useFakeTimers({ toFake: ['Date'] })` + `setSystemTime`), which is this package's existing convention in four sibling temporal suites, so the original readable assertions become deterministic forever. One sub-premise of the issue is WRONG and it changes the verdict: the triage justified limb 1 as a 'declared=enforced restoration' because the door's docblock 'lists now among its context', but that sentence's subject is `resolveFilterTokens` — its context type is `FilterTokenResolutionContext`. `now` is declared on NEITHER `ExecutionContextSchema` (packages/spec) NOR `ExecutionContextLike` (packages/core); the field-name tell is that the quoted list ends in `orgId` while `ExecutionContextLike` spells it `tenantId`, and `filterTokenContextFrom` is the bridge between the two. So limb 1 would ADD a caller-injectable clock to the public execution envelope, not restore a declared one — the general fork-back condition ('the contract must genuinely move'), so it is escalated rather than picked silently. I verified limb 1 WOULD work (probe: honouring execCtx.now turns the file green) and would break no existing caller (zero producers repo-wide; the wire path deletes inbound context unconditionally) — but that is not authority to widen a public contract, and packages/spec was scoped out of this card. PR body is `Part of #8937`, not a closing keyword, so merging does not close the card while the contract half is open.", "tests": "All at final commit 34c19e6 (quoted from `git rev-parse --short HEAD` in the same run). Target file: `pnpm --filter @objectstack/objectql exec vitest run src/engine-temporal-comparand-door.test.ts` -> 'Test Files 1 passed (1) / Tests 10 passed (10)'; before the fix, same command -> 'Tests 1 failed | 7 passed', AssertionError: expected '2026-07-17' to be '2026-07-16'. Full package suite: 'Test Files 211 passed (211) / Tests 3697 passed (3697)' (pre-fix baseline on the same tree: 210 passed | 1 failed, 3694 passed). `pnpm --filter @objectstack/objectql typecheck` -> tsc --noEmit clean. TZ=Asia/Tokyo (already the next LOCAL calendar day) -> 10/10, and TZ=America/New_York -> 10/10 on the earlier variant. Date-immunity evidence: the file is green TODAY (2026-08-16) while asserting a 2026-07-16 floor — under the old code today's real clock produced 2026-07-17. Build closure built first (`pnpm --filter '@objectstack/objectql^...' build`), and the full workspace closure (turbo, 70 tasks) built for the ratchet. Gates re-derived from the actual changed path via `node scripts/pm/dispatch-gates.mjs`, all green at 34c19e6: check-nul-bytes ('no raw ASCII control bytes'), check:durability-log-level, check-engine-split-ratio, check:query-options-erasure ('ratchet holds ... none new'), check:type-check-coverage, check:type-check-debt --re-measure ('33 ledger entries re-measured, 1926 raw tsc errors total, none above its recorded number'). PROBE DISCLOSURE + a trap worth recording: to measure limb 1 I added `now` to ExecutionContextLike and read it in filterTokenContextFrom, rebuilt @objectstack/core, and the file went 10/10 green — confirming the mechanism. I reverted the source (verified byte-identical against a pre-probe copy) but the first re-run STILL showed limb-1 behaviour, because objectql resolves @objectstack/core from its built dist/ and the probe build was still there; `grep` on dist/index.js confirmed the probe was live. Rebuilt core from reverted source, re-verified the probe absent from dist, and only then took the reported numbers. A source-level revert is not a revert when the consumer reads dist/. No consumer sweep is reported because none exists to run: the final diff is one test file, zero runtime code changed.", "open_questions": [ { "question": "Should the ObjectQL engine expose a DECLARED, caller-injectable clock (`now`) on ExecutionContext, so {N_days_ago}-family macro resolution can be pinned by callers rather than only by faking the process clock? This is the card's remaining half. It is a public-contract change (spec Zod schema + engine API surface) and packages/spec was explicitly scoped out of this dispatch, so I made no guess.", "options": [ "A — Declare `now` on ExecutionContextSchema (packages/spec/src/kernel/execution-context.zod.ts), add it to ExecutionContextLike, and have filterTokenContextFrom default to execCtx.now. Measured to work (probe went 10/10 green) and to break nothing (zero producers of context.now repo-wide; metadata-protocol deletes inbound `context` unconditionally, so no client can reach it).", "B — Keep the engine on the process clock; tests pin it with vi.useFakeTimers({ toFake: ['Date'] }), the convention already used by engine-cel-default-temporal-shape and the three engine-autonumber-* suites. This is what PR #8939 does, and it additionally converts the trap into a named, tested fact.", "C — Honour execCtx.now structurally in packages/core only, without declaring it in spec (no packages/spec diff, so nominally inside this card's scope)." ], "recommendation": "B, and explicitly NOT C. (1) Real business need — measured, not intuited: ZERO producers of context.now exist anywhere in packages/ or apps/; the only writer in the repo was this very test, via an `as never` cast that was TypeScript refusing the key. The wire path deletes inbound context unconditionally ('The execution context is SERVER-DERIVED and never caller input'), so no external caller could supply it even if honoured. The only demand ever expressed was one test wanting a pinnable clock, and vi.setSystemTime already serves that — four sibling suites prove it. Under the startup-focus principle a declared surface with no measured pull is handled implementation-first, so A is capability expansion with no puller. (2) Long-term soundness — A is internally coherent but widens an envelope whose own docblocks repeatedly stress server-derived-never-caller-input, and a caller-settable clock silently shifts every relative-date window (RLS/sharing predicates are built downstream from concrete values, so the blast radius needs deliberate review, not a p0 side effect). C is the patch-shaped option and the worst long-term: enforced-but-undeclared is precisely the declared-vs-enforced drift ADR-0049 exists to end, and it forks the clock source into two places. (3) Hard-to-get-wrong for AI-authored code — C is disqualifying: a runtime behaviour no type declares, discoverable only by reading core's source, so an author gets silent success or silent nothing with no signal either way. A is acceptable ONLY if declared and validated at the schema. B is currently the strongest on this axis because #8939 makes the inertness structural and loud: an author reaching for context.now now hits a named test ('does not honour an injected context.now today') that states the fact and says to delete it deliberately if the contract ever moves. If the maintainer does want A, it should be its own card with its own review of the trust question — not folded into a p0 stop-the-bleed." } ], "out_of_scope_findings": [] }Notes not carried by the JSON
No other calendar-armed fixtures found — nothing filed, and that is a measured result rather than a skipped step.
new Date('20NN-acrosspackages/objectql/src/**/*.test.tsreturns 10 hits in 6 files; every one outside the fixed file is either (a) paired withvi.setSystemTime, which pins the process clock and so cannot rot —engine-cel-default-temporal-shape,engine-autonumber-resync,engine-autonumber-default-format,engine-autonumber-seed-suffix— or (b) a resolver/validator input whose verdict is recency-independent (operator-object-write-value, and the'2026-07-15'comparands in the fixed file, which the door judges for interpretability, never against today). The anti-pattern itself (context: { now) appears nowhere in the repo outside the file this PR fixes.One pre-existing informational gate note, deliberately not acted on:
check:type-check-debtreports@objectstack/lintTEST_DEBT records 20 while tsc now measures 19 (-1). It is not an error, it predates this branch, it is in a package this PR does not touch, and the gate already tracks the class under #6376 — so no finding was filed and no--lowerwas run from this card.Contract conflict surfaced, not silently resolved (per the dispatch contract): the dispatch prompt asked for a PR body whose first line is
Fixes #8937. Because the contract half is being escalated, merging #8939 would not close the card, and a closing keyword on a card in the decision box would close it silently — so the body saysPart of #8937. Flagging the deviation rather than picking a side quietly.Generated by Claude Code
os-project-manager commentedon Aug 16, 2026
ACCEPT (stop-the-bleed half) + PM adjudication of the remaining half — spec seat (cross-lane takeover), session
session_01Fgvh1iEJfxetei7aNVdtJt.PR #8939 ACCEPTed (
Part of #8937, tests-only,skip-changesetapplied and read back): the fixture now pins the clock the engine actually reads (vi.useFakeTimers— the four sibling temporal suites' existing convention), all temporal expectations are derived rather than written down, the discriminating resolver pin prevents the frozen-resolver false-green, and the non-injection ofcontext.nowis converted into a named characterization pin with explicit delete-deliberately instructions. Verified: 10/10 today (2026-08-16) asserting a floor the old code could no longer produce; TZ-shifted runs green; full objectql suite 3697/3697; the dev's dist-revert trap disclosure ("a source revert is not a revert when the consumer reads dist/") is a keeper. All 30 CI jobs green. Marking ready + auto-merge — this unblocks the merge queue repo-wide.Remaining half, adjudicated B — no declared injectable clock; the card closes when #8939 merges. The dev's
needs_decisionwas reviewed against the escalation threshold and falls inside seat discretion, because option B changes no product semantics and no public contract — it declines a capability with measured zero pull (zero producers ofcontext.nowrepo-wide; the only writer was this test, through anas nevercast TypeScript was refusing; the wire path deletes inbound context unconditionally by documented design). Existing norms settle the rest: C (honour without declaring) is exactly the declared≠enforced drift ADR-0049 exists to end — ⛔ excluded; A (declarenowonExecutionContextSchema) is a public-contract widening with no puller, and a caller-settable clock shifts every relative-date window feeding RLS/sharing predicates — if it is ever wanted, it argues its own card with its own trust review, not a p0 rider. The triage note's limb-1 framing ("declared=enforced restoration") is corrected on the record: the docblock sentence describesresolveFilterTokens's own context type, not the engine envelope — the dev's reading is verified (field-name tell:orgIdvstenantId).This adjudication is recorded as a veto window, not a permission gate — flagged in the round report to the maintainer; if vetoed, option A gets its own card.
Generated by Claude Code
os-project-manager commentedon Aug 16, 2026
Closed as completed — both halves resolved. Provenance: spec seat (cross-lane takeover), session
session_01Fgvh1iEJfxetei7aNVdtJt.510a4bdonorigin/main, both readings verified) — the fixture pins the clock the engine reads; the merge queue is unblocked repo-wide. Since the PR was deliberatelyPart of, this comment is the closing act, not a keyword.5305065056) — no declared injectable clock; C excluded by ADR-0049; A waits for its own card if a real puller ever appears. Recorded as a maintainer veto window in the round report; a veto reopens nothing here — it files a fresh Option-A card.The
pm:dispatchedlabel leaves with the closure (labels cleared from the state machine's perspective;priority:p0retired with the fix on main).Generated by Claude Code
test(objectql): pin the temporal-comparand door fixture's clock with …