Skip to content

spec(ui): subtract the unenforced context key from ActionEngineFacade.find's query envelope - #19315

Queued
os-litant wants to merge 3 commits into
mainfrom
claude/issue-19237-facade-find-context-declared-unenforced
Queued

os-litant wants to merge 3 commits into
mainfrom
claude/issue-19237-facade-find-context-declared-unenforced

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes #19237

Clause-②: no

⚠️ Notation: TypeScript angle brackets are written with PARENTHESES throughout this body — Omit(EngineQueryOptions, 'context') means the Omit utility type. The platform rewrites tag-shaped fragments in a body, and a fence does not protect them, so the real spelling lives in the diff.

The action facade's find accepted a caller-written context that type-checked and the runtime did not honour — ADR-0049's declared-but-unenforced shape on the one key that carries identity and tenant. This takes the remove arm, at the declaration layer only: the parameter becomes Omit(EngineQueryOptions, 'context'). No runtime behaviour changes.

The premise, measured FIRST — it HOLDS

The dispatch made the ruling conditional on a census: no call site writes a context on a facade query and relies on it to narrow identity or tenant. Measured before a line of fix was written.

Instrument (census3.mjs, three arms, run against the tree at 1739f71879f):

Arm What it matches Why it exists
A RECV.engine.VERB( where RECV is an action-ctx name the canonical handler spelling
B bare engine.VERB( in a file that destructures engine out of a ctx examples/app-todo writes it this way
C V.VERB( where V is assigned from buildActionEngineFacade(...) closes arm A/B's blind spot: a facade held in a local variable

Each call's second argument is extracted by balanced-paren scan, not a line regex, so a multi-line envelope is read whole.

Radius: 8292 tracked text files — the whole repository, not the importers of ActionEngineFacade. That denominator is deliberate, and it is the one PR #19223 warned about: the facade is reached through ActionHandlerContext.engine, so an importer count of the facade type is the wrong population.

Readings, exit codes captured before any pipe:

  • facade call sites 123 (armA 86, armB 10, armC 27); of these 47 are find
  • sites writing a context key: 11
  • find sites writing a context key: 1

That one is packages/runtime/src/action-engine-facade-find-envelope.test.ts:126the pin that asserts the key is NOT honoured, added by #19223. It is the instrument's firing control: arm C demonstrably sees a real facade find carrying a context.

The other 10 are not facade sites, and each was classified by reading the file rather than by name:

  • 7 in packages/objectql/src/internal-fields.test.tsctx there is Awaited(ReturnType(typeof buildEngine)), a real ObjectQL engine; sibling calls to findOne and aggregate are members ActionEngineFacade does not declare.
  • 3 in action-engine-facade-find-envelope.test.ts:209-211 — a different engine, built by the file's own makeRealEngine(); they pass a third argument, and the facade's insert takes two.

Dark control: the same instrument with a member and a builder that cannot exist (.engineZZZQ, buildActionEngineFacadeZZZQ) — exit 1, FACADE_SITES total=0 on all three arms.

Sibling radius: objectui at dda8f3815dfgit grep for ActionEngineFacade, ActionHandlerContext and ctx.engine. exits 1 / 0 hits, with a firing control in the same tree (a token that certainly exists) exiting 0.

Zero live call sites. The p0 upgrade trigger does not fire. priority:p1 stands.

Mechanism: OVERRIDE, not drop — traced to a named line

At origin/main = 1739f71879f, read 2026-09-20T08:42Z:

packages/runtime/src/action-execution.ts:1620

const rows = await ql.find(object, { ...(query ?? {}), context } as any);

context is spread last, after the caller's envelope, so the facade's own elevated ExecutionContext (minted at :1560 by buildActionExecutionContext(ec)) replaces whatever the caller put under that key. The key reaches the engine; the caller's value does not. PR #19223's body claim holds on today's tree, and it is override rather than drop.

The third card fact: the sibling arms do NOT share the shape

ActionEngineFacade declares exactly four members, and only one takes an options bag:

insert(object, data)            update(object, id, data)
delete(object, idOrIds)         find(object, query)   ← the only bag

There is no findOne and no count on this facade. The write doors have nowhere to carry a context at the type level, so there is nothing to price and nothing to widen this diff onto. Reported as measured, per the order.

What changed

The pin is TYPE-level, and that is deliberate

FindQueryCarriesNoContextKey asserts the key is absent from the declared slot; the two @ts-expect-error directives red if a literal carrying context starts compiling. A runtime pin would assert a refusal that does not exist and must not: adding one makes the facade throw on an identity key, which is a runtime permission change no ruling covers. The runtime's own pin is untouched and still green.

The file is inside the checked zone — check:test-typecheck reports packages/spec/tsconfig.test.json compiling 54 files — so these are not phantom directives.

Reverse verification

Fix committed first, then the declaration alone reverted to EngineQueryOptions:

  • on-disk proof — narrowed spelling 1 → 0, widened 0 → 1, blob 3f73de3ae0f58f5dc6b90e; a no-op edit would have been caught here and the reading voided.
  • ablated pnpm --filter @objectstack/spec typecheckexit 1, src/ui/action-params.test.ts: 4 type error(s) — the two asserts plus the two now-unused @ts-expect-error directives.
  • restored with git checkout HEAD -- PATH (never a bare checkout, which reads the polluted index): git diff HEAD empty and git hash-object back to 3f73de3ae0f, byte-identical. A trap on EXIT/INT/TERM carried the restore, with an absolute repo root.

Direction predicted before the run and observed: red.

Verification — per consumer package, on the merged head d55c3d9e772

Package Reading
@objectstack/spec 500 files / 14644 tests passed · typecheck exit 0
@objectstack/runtime 268 files / 3705 passed, 1 skipped · typecheck exit 0
@objectstack/objectql 300 files / 5009 passed · typecheck exit 0
@objectstack/example-todo 7 files / 238 passed · typecheck exit 0

@objectstack/objectql is not on the dispatched floor list: the census found it, at packages/objectql/src/engine-write-not-found-gate.test.ts, which builds a real facade through buildActionEngineFacade. Run because it is a consumer, and said so.

⚠️ One reading was thrown away rather than reported: the first runtime run answered 242 test files failed / 7 tests failed, which was Cannot find package on an unbuilt dependency closure — PREREQUISITE NOT MET, not a red. Re-run after pnpm --filter '@objectstack/example-todo^...' build and reported above.

Gates. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, derived from this tree, re-derived after the merge (same 107, no families added or dropped): 107 of 107 green, each exit code redirected to its own file and read back before any pipe, then reconciled with --ran carrying the codes — 107 run, 0 NOT-MEASURED (a DERIVED zero).

Two needed a second run, and both were prerequisite misses rather than reds: check:skill-examples (exit 1, packages/client-react/dist unbuilt) and check:dual-build-cjs-loads (exit 3, its own PREREQUISITE NOT MET — ⛔ This is NOT a pass). Both green after building the missing packages.

check:pm-widening-tells is green — the T1 tell that card #19099 records against this shape did not fire, so the Clause-②: no declaration needed no over-declaring to get past a gate.

Lint, repo-wide rather than narrowed: eslint . --no-inline-config over all 6916 files eslint's own config judges — 0 errors, 0 warnings, exit 0, at d55c3d9e772. The file count is read from eslint's own --format json output, not estimated. No type-aware linting is configured (eslint.config.mjs states it carries no parserOptions.project and no typed rules), so nothing in this diff can move an untouched file's verdict.

Declaration

Clause-②: no — this puts no new key on a published payload; it removes one from a parameter type. The lane charter's line that a narrowing does not trigger clause ② is the criterion, and check:pm-widening-tells agrees with it mechanically. The changeset separately carries Clause-②: no (narrowing), which is signal (4) to check-adr-0087-registration: an accept-set narrowing on a published type is exactly what #16421 built that signal for, so it is declared rather than left to prose, with an already-registered disposition naming action-engine-facade-find-query-envelope — the entry #19223 landed, which already tells an upgrader that a caller-supplied context is ignored. That gate is green.

Acceptance notes

Noted, not filed — the asymmetry this leaves, stated so nobody reads it as an oversight. After this diff the facade's find arm refuses (at runtime) every top-level key the envelope does not carry, accepts-and-honours the ones it does, and accepts-and-overrides exactly one: context, for untyped callers only. Closing that last cell means a runtime refusal on an identity key — the maintainer's floor, not a dev's and not a seat's, and the dispatch prohibited taking it here. It is recorded on both halves of the contract (the spec member doc and the runtime arm's docblock, the latter with an explicit "do not finish the job here without a ruling"). Carrier: whoever holds the next ruling on this surface — there is no PR or person this file is waiting on today, so it is written down where the next editor of either half will read it, rather than filed as a card nobody is dispatched to.

⚠️ Not a finding, but worth one line for the next census on this surface: a receiver-name heuristic over .engine. is not sound here — 10 of the 11 context writers it flags are the data engine, which honours the key. Only a type or construction anchor (buildActionEngineFacade, or the findOne/aggregate members the facade lacks) separates the two populations.


Generated by Claude Code

…envelope

The facade is trusted and mints its own elevated ExecutionContext, which the
runtime spreads last — so a caller-supplied `context` was overridden, never
honoured, while the parameter type went on declaring it. That is ADR-0049's
declared-but-unenforced shape on the one key that carries identity and tenant.

Take the remove arm, at the declaration layer only: the parameter is now
`Omit<EngineQueryOptions, 'context'>`. No runtime behaviour changes — the
facade arm still accepts the key from the untyped channel and still overrides
it, because refusing an identity key there is a runtime permission change no
ruling covers. The asymmetry is recorded on both halves rather than closed.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvwGppdonww4zGLWZo5rho
…d slot

One shard, one semantic hunk: `find(object, query: EngineQueryOptions)` becomes
`find(object, query: Omit<EngineQueryOptions, 'context'>)`, plus the member doc
that states why. No declaration-emit ORDER churn in the other seven shards —
this diff adds no import, so the d.ts chunking does not move.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvwGppdonww4zGLWZo5rho
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation protocol:ui tests tooling labels Sep 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/runtime, @objectstack/spec, touching 2 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/spec/api-surface-declarations/ui.txt), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/ui/actions.mdx (via ActionEngineFacade (symbol, a top-level interface))
What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/api-surface-declarations/ui.txt) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 141 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json e3b3cdd2df3bda349ef7a41b0de39c8de4fddc87packageMentionDocs.

Which tree this was computed on

This run read content/docs from 69a5322b5601432be75b19417d00c63193c15ab6 — the merge of head d55c3d9e77279677b81cf3beb5177d3e88229582 into base e3b3cdd2df3bda349ef7a41b0de39c8de4fddc87, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 69a5322b5601432be75b19417d00c63193c15ab6 && git checkout 69a5322b5601432be75b19417d00c63193c15ab6
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e3b3cdd2df3bda349ef7a41b0de39c8de4fddc87 d55c3d9e77279677b81cf3beb5177d3e88229582 && git checkout -B drift-repro e3b3cdd2df3bda349ef7a41b0de39c8de4fddc87 && git merge --no-ff d55c3d9e77279677b81cf3beb5177d3e88229582

node scripts/docs-audit/affected-docs.mjs --json e3b3cdd2df3bda349ef7a41b0de39c8de4fddc87

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs e3b3cdd2df3bda349ef7a41b0de39c8de4fddc87 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d55c3d9e77279677b81cf3beb5177d3e88229582

Isolated review for the domain:spec lane, PR #19315 against card #19237. Every reading below was taken in this act, in a detached worktree at the head sha, with origin/main fetched at 2026-09-20T10:57Z = e3b3cdd2df3. Nothing is inherited from the PR body or the dev report; where a dev number is echoed it is because my own instrument reproduced it. Notation: TypeScript generics are written with parentheses — Omit(EngineQueryOptions, 'context') — because the platform rewrites tag-shaped fragments.

① Derived judgments

1. The narrowing is real at the type level and it bites — measured, not read off the body.

  • tsc -p packages/spec/tsconfig.test.json --listFilesOnly (11:03Z): 1837 files in the program; packages/spec/src/ui/action-params.test.ts is in it (count 1); a fabricated sibling name counts 0. The directives are inside a program a script actually runs: pnpm --filter @objectstack/spec check:test-typecheck exit 0 (11:05Z), and packages/spec/test-typecheck-debt.json does not name action-params.test.ts (grep exit 1; lit control conversation.test.ts exit 0), so no ledger entry could absorb a red from that file.
  • Ablation, direction predicted red, observed red. With only the declaration reverted to find(object, query: EngineQueryOptions) (blob 3f73de3ae0f to 58f5dc6b90e, on-disk grep 1 to 0 / 0 to 1 before any result was read), tsc -p tsconfig.test.json reports exactly 4 errors in action-params.test.ts: TS2344 at :430 and :448 (the two type asserts) and TS2578 unused @ts-expect-error at :525 and :527. Restored with git checkout HEAD -- path; blob back to 3f73de3ae0f, git diff HEAD empty (11:06Z).
  • vitest on src/ui/action-params.test.ts under the local project: 34 of 34 pass (11:06Z).

2. Narrowing, not widening — the accept set re-derived by a compiled probe, not by reading the diff. A probe file compiled under the same test tsconfig held all four assertions: the key set removed from EngineQueryOptions on the facade slot is exactly 'context'; the key set added is never; no string index signature leaked in (the classic Omit-over-index-signature collapse did not happen, because EngineQueryOptionsSchema at data-engine.zod.ts:98 is a plain object extend with no passthrough or catchall); and the slot is identical to Pick of the engine type over its other keys, so every surviving key keeps the engine's property type by reference. The compiler printed the surviving union: where, fields, orderBy, limit, offset, top, cursor, search, searchFields, expand, distinct (11 keys) versus the engine's 12. check-widening-tells --declaration no over the diff: 0 tells (1 file judged, 5 not measurable because they are not contract sources). ⇒ Clause-②: no with the (narrowing) arm is the honest declaration; nothing in this diff widens anything.

3. Mechanism and the runtime half, re-traced on head. packages/runtime/src/action-execution.ts:1636 is ql.find(object, { ...(query ?? {}), context } as any) — the facade's own context (minted at :1560) is spread last, so a caller value is overridden, not dropped. findEnvelopeKeys() at :1495-1498 reads its legal set off EngineQueryOptionsSchema.shape, which still carries context from BaseEngineOptionsSchema (:73), so the untyped channel is accepted and overridden rather than refused. The runtime hunk is 24 changed lines and every one is a comment line (a grep for a non-comment changed line exits 1) — zero behaviour change is a measured fact here, not a claim. The interface at head declares exactly four members and only find takes a bag (read off the interface body), so there is no sibling arm this narrowing should have reached. The runtime pin ran here too, after building the dependency closure in this worktree: packages/runtime/src/action-engine-facade-find-envelope.test.ts 9 of 9 pass (11:12Z), including stamps the facade's OWN elevated context, and a caller-supplied context does not displace it — the accept-and-override behaviour the new docblock describes is what the runtime does at head.

4. Published surface. packages/spec/package.json files[] ships src/**/*.zod.ts and api-surface-declarations, so both action-params.zod.ts and the regenerated ui.txt are tarball sentences. The new sentences are true on today's tree: the override line, the schema-derived legal set, and the four-member shape are each the code I read above. No copy of the old claim survives: a grep over packages/spec and content/docs for the three retired sentences (the "by identity" clause, the "caller's to pass" heading, the "reads as authorization" line) exits 1, with the replacement sentence as lit control (exit 0, found in the zod file and in ui.txt) and a fabricated sentence as dark control (exit 1). Only the ui.txt shard moved in the declarations directory. Regeneration is byte-exact: a full @objectstack/spec build with declarations (exit 0, 11:11Z) followed by pnpm --filter @objectstack/spec check:api-surface-declarations reports declaration text unchanged ✓ (17 entry points, 5364 declarations), exit 0, and git status is empty afterwards — the committed ui.txt is what the build emits, not a hand edit. CI's Type Check · consumer gates job, which runs the same check, is green on this head.

5. Changeset and ADR-0087 signal (4), re-derived. The changeset bumps only @objectstack/spec at minor, carries the line-initial Clause-②: no (narrowing), exactly one adr-0087: marker (not-required (already-registered action-engine-facade-find-query-envelope)), and a FROM → TO migration table. I ran node scripts/check-adr-0087-registration.mjs twice — --base e3b3cdd2df3 (current origin/main) and --base adf4b18777d (this head's actual merge-base) — exit 0 both times, classifying the changeset [clause-②-narrowing], i.e. signal (4) fired as designed and the disposition was validated against facts: the named entry resolves at head and already exists at both bases (registry.ts grep count 1 at adf4b18 and at e3b3cdd2). check-changeset-no-major exit 0 at both bases. The disposition is honest on the semantics too: the registered entry already tells an upgrader the envelope shape and that a caller-supplied context is ignored, the only consumer-side act this diff adds is deleting a key that entry already declares inert, and the changeset body itself ships the one-line fix into CHANGELOG.md. @objectstack/runtime owes no changeset because its diff is comment-only (judgment 3).

6. The census the premise rests on — re-taken with my own instrument. Receiver-chain regex plus a balanced-paren scan of the second argument plus a top-level context key test, over 6912 code files (ts/tsx/js/mjs/cjs/jsx/mts/cts) of 9035 tracked at head. Readings: 421 find(...) sites write a top-level context; by receiver they are ql 139, this.engine 125, bare engine 124, this 10, ctx.ql 5, data 5, the rest at most 2 each; the receivers ctx.engine and context.engine carry 0 such sites (22 ctx.engine.find( sites exist and none writes the key). Of the bare-engine rows (83 file-and-receiver groups), exactly one file binds engine from buildActionEngineFacade: packages/runtime/src/action-engine-facade-find-envelope.test.ts:126, the pin that asserts the key is NOT honoured — my lit control, and the same single site the dev found. Every other bare engine binds a data engine (new ObjectQL(), deps.getDataEngine(), kernel.getService('objectql'), makeEngine(...), a service-class field, or an engine-typed parameter), classified by reading each binding. Indirect handles: outside the objectql engine-rig tests and the memory driver, every ctx.engine use is a direct member call — the facade is never assigned to a variable or passed as an argument, so no helper writes the key on its behalf. Dark control: the same instrument with a fabricated member (findZZZQ) returns 0 sites; a second instrument with a fabricated member and builder returns 0 on every arm, exit 1. Sibling radius: objectui at the pinned .objectui-sha 53ded82bf7a, read-only git grep -q for ActionEngineFacade, ActionHandlerContext, ctx.engine. exits 1; lit control ObjectStack exits 0; dark control exits 1. ⇒ the premise holds: zero live call sites write a context on a facade query; triage's p0 trigger does not fire; priority:p1 stands.

7. Head, base and collisions — one correction to the brief I was handed. The PR API reports base.sha = e3b3cdd2df3 = current origin/main, mergeable: true, mergeable_state: blocked. But the head's merge-base with origin/main is adf4b18777d: main is 6 commits / 21 files ahead of this head, so the head is not a descendant of current main and the landing tree will be the queue's merge of the two. I diffed those 6 commits against this PR's surface: nothing under packages/spec, packages/runtime or content/docs/ui moved; the only overlap is four unrelated new changesets. The ADR-0087 gate is green at both bases (judgment 5). Across all 36 open PRs, none touches action-params.zod.ts, action-params.test.ts, action-execution.ts or data-engine.zod.ts; the generated api-surface-declarations/ui.txt shard is also regenerated by #19090 (draft) and deleted wholesale by #19024 (open) — a regeneration collision, not a source one.

8. Hygiene. Draft PR; first body line Fixes #19237; line-initial Clause-②: no; no model identifier in title, body, changeset, diff or commit trailers (model-free pair on both commits); no governed-surface path in the six-file diff; check-clause2-carriers --pair 19315 exit 4 at 11:04Z for the one reason this comment exists (C6, no record of record on this head yet).

② Semver level

minor on @objectstack/spec is the correct grading. The declaration arm (narrowing) is BREAKING by AGENTS.md's own line, and the launch-window guard (check-changeset-no-major.mjs, in force at head and green on this diff) forbids major and ships breaking as minor — so minor is not an under-declaration, it is the level the guard prescribes. @objectstack/spec is published (no private, files[] populated), so the unpublished escape was neither available nor claimed. No second package bump is owed.

③ Boundary flags

  • For the seat — CI at posting time. Check runs on d55c3d9e772, latest per name, read at 2026-09-20T11:19:33Z: 35 distinct names, 31 success, 4 skipped (Auto Label, Check PR Size, Console Pin Gate, Packed-tarball smoke (opt-in) — all skipped by their own path or opt-in conditions, none a failure), 0 failed, 0 in progress — Lint & Repo Gates was the last to finish, at 11:19:08Z. Nothing was still running when this record was posted.
  • For the seat — landing tree. This head does not contain the 6 newest origin/main commits (judgment 7). Nothing on main since adf4b18777d touches this PR's files, so a merge-queue landing is safe as measured; if you want the tree you tested to be byte-identical to the tree that lands, re-merge origin/main first.
  • For the seat — generated shard collision. packages/spec/api-surface-declarations/ui.txt is also moved by spec(ui): BulkActionParamSchema is strict and declares dependsOn #19090 and by revert(spec): take back the declaration-text snapshot, restore the 27 signature hashes #19024. Whichever lands second must regenerate through scripts/pm/os-regen-merge.sh, never resolve textually — exactly the dispatch's own instruction.
  • For the seat, optional and non-blocking. content/docs/ui/actions.mdx:185 still opens the paragraph with "The parameter is typed EngineQueryOptions" before the new paragraph subtracts the key. The docs page is not in files[], so it is not a tarball sentence; one clause could say "minus context".
  • Not routed anywhere — recorded, agreed. The asymmetry the dev names (typed callers get a compile error, untyped callers still have the key overridden silently) is a runtime refusal on an identity key, the maintainer's floor by the dispatch's own prohibition. It is written on both halves of the contract at head; I see nothing for this lane to file.

Implemented-by: claude/issue-19237-facade-find-context-declared-unenforced
Reviewed-by: session_01LvwGppdonww4zGLWZo5rho

VERDICT: PASS


Generated by Claude Code

@os-litant
os-litant marked this pull request as ready for review September 20, 2026 11:25
@os-litant
os-litant added this pull request to the merge queue Sep 20, 2026
Any commits made after this event will not be merged.
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Sep 20, 2026
@os-litant
os-litant added this pull request to the merge queue Sep 20, 2026
Any commits made after this event will not be merged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/m tests tooling

Projects

None yet

2 participants