Repository navigation
ADR-0139 execution: the engine-internal semi-join leaf across spec, engine, drivers and consumers (E0–E7 coordination) #22788
Copy link
Copy link
Open
Labels
area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdomain:engineenhancementNew feature or requestNew feature or requestpm:queuepriority:p2Medium: important, M3Medium: important, M3
Description
Filing gate: ④ a coordination node. This is the cross-layer parent of ADR-0139's execution cards (spec, engine, drivers and the plugin consumers). ADR-0139 was accepted through PR #22707 → a2e94c2a05 (card #22678, landing record 6106332690). Filed by domain:engine seat 1 (#6367) · session_01JfJfBUC3cQ6hhgm9MQK76T. ⛔ Classes, positions and functions only.
Blocked-by: #22861
Reader who acts: domain:engine seat 1, which owns this card, cuts each execution card when its predecessor lands, and ticks this list. The record's plan names domain:engine with domain:spec. E5 to E7 land in domain:services packages and are declared cross-lane when they are cut. This card does no work of its own. It closes when E7 lands.
Checklist (the record's "Execution plan" table; order as the record gives it)
- E0: ADR-0139's status line reads "Accepted (2026-10-11), accepted by the merge that landed it on
main(docs(adr): ADR-0139 — one engine-internal semi-join leaf, "the ids of object X this caller may read" (ruling A on #22590 item 3) #22707)". Landed with ADR-0139 E2: the engine composes theReadableIdsleaf once per parent object, fail closed, refuses it on write verbs and for D5's three classes, and marks the scope'policy'(D2, D5) #22861's record half, PR docs(adr): ADR-0139 reads Accepted, and D2 names the executor boundary as the composition seam (record half of the ruling on #22861) #23035 (2db2f8daea), approved byos-zhuang, a governed approver (Tier H). - E1, the leaf (D1): feat(spec): ADR-0139 E1 — the
ReadableIdsbranded comparand leaf, declared in spec and unspellable by a request #22787 (domain:spec, Clause-②), landed as PR feat(spec,objectql): ReadableIds, the branded $in comparand leaf no request can spell, refused by the engine until composed (ADR-0139 D1, E1) #22809 (9814035c01). Its pointer for E2 onward is 6107554336. - E2, composition (D2, D5): the engine seam composes the leaf, refuses it on write verbs and for D5's three classes, and marks the scope
'policy'; plus the conformance case-set. After E1. Cut as ADR-0139 E2: the engine composes theReadableIdsleaf once per parent object, fail closed, refuses it on write verbs and for D5's three classes, and marks the scope'policy'(D2, D5) #22861, held bydomain:engineseat 2. The seam position is ruled A (6121741984): the executor boundary, and D2's text is amended (PR docs(adr): ADR-0139 reads Accepted, and D2 names the executor boundary as the composition seam (record half of the ruling on #22861) #23035). Landed as PR feat(objectql,core): the engine composes the ReadableIds leaf at its executor boundary, fail closed, and refuses it by name where it cannot (ADR-0139 E2) #23301 →87e902dcbb(6153053208); ADR-0139 E2: the engine composes theReadableIdsleaf once per parent object, fail closed, refuses it on write verbs and for D5's three classes, and marks the scope'policy'(D2, D5) #22861 is closed. - E3, the SQL family (D3):
driver-sqlcompiles the leaf inapplyTenantScope; wasm and local Turso inherit; the remote transport compiles it. After E2. Cut with E4 as ADR-0139 E3 + E4: the five drivers compile the composed ReadableIds leaf or refuse it with D3's envelope, and the conformance case-set lands with their suites (D3) #23639 (one card, one PR, per spec: declare the RLS deny sentinel once in@objectstack/spec, imported byplugin-securityandobjectql(ADR-0139 D2 step 2; #22861 sub-question 2 ruled (i)) #23009's ruling 6137585321), dispatched by seat 1 on 2026-10-15T08:31Z. - E4, memory and mongodb (D3): memory implements it; mongodb refuses with the envelope. With E3. Cut with E3 as ADR-0139 E3 + E4: the five drivers compile the composed ReadableIds leaf or refuse it with D3's envelope, and the conformance case-set lands with their suites (D3) #23639. E3 and E4 landed as PR feat(drivers): ADR-0139 E3 + E4 — the five drivers compile the composed ReadableIds leaf or refuse it with D3's envelope, with the conformance case-set #23656 →
462dff36f1(contract review 6190904969 PASS; conformance ledger 55 covered / 0 DEBT). - E5, the activity and ledger switch (D4, D5):
plugin-audit'scomputeParentRecordFilteremits leaves and does no pre-scan; D5's classes keep the probe. After E3. Cut as ADR-0139 E5: plugin-audit's parent-record read gate emits one ReadableIds leaf per parent object and does no pre-scan; D5's three classes keep the probe (D4, D5) #23673 (aplugin-auditcard; nodomain:*under the split rule, triage routes it). - E6,
changed_fields(D4): the column, the writer stamp, the backfill migration, and the rule as a predicate. After E5. - E7, comments, reactions and attachments (D4): the three gates switched. After E5.
Notes that ride into the cards (the director's ruling pointer 6104842076; ⛔ no change to the record's text)
- E5 measures the branch count.
- D4 emits one subquery branch per registered parent object.
- E5 records branch count against query time on the measured scenario (1,808 of 5,042 rows) before the activity gate switches.
- O5 widens into a candidate follow-on, "scope as a relation". It is a later ADR, after E3 to E5 land. ⛔ Not filed now.
- D3 stands as written, per the maintainer: no capability bit, and
driver-mongodbrefuses loudly until O3 measures a pipeline form.
Open items (from the record; each becomes a reading on its card)
- O1: the bound-parameter ceilings of SQLite, Postgres and MySQL are documented values, not measured. E3 reads them.
- O2: consumers 4 to 6 are source readings. E6 and E7 measure them.
- O3: the cost of a pipeline form in
driver-mongodbis unprototyped. E4 keeps the refusal. - O4:
plugin-sharing's grant read atlimit: 5000. The record calls this a separate finding, not its own, and it is not filed here. - O5: whether
controlled_by_parent's id set becomes a seventh consumer. See note 2.
Duplicate check
- Population: 4,502 issues, closed included, ADR-0048: Semantic-reference metadata embeds in package docs (flow:// / view:// / dashboard:// / object://) #1795 to security(plugin-audit): a fired milestone's activity row is served with its
typeandsummaryto a reader withheld the field the milestone watches — the #21081 text-provenance declaration names the summary's tokens, not the watched field #22786 (the same instrument as feat(spec): ADR-0139 E1 — theReadableIdsbranded comparand leaf, declared in spec and unspellable by a request #22787). - Queries:
ReadableIds0;ADR-01391 (the seat post); "semi-join" 2 (ADR (ruling A on #22590 item 3): one engine-internal semi-join leaf, "the ids of object X this caller may read"; ADR-0055 alternatives row (a) revisited for this one leaf #22678 and the seat post). - Control:
ADR-005510.
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdomain:engineenhancementNew feature or requestNew feature or requestpm:queuepriority:p2Medium: important, M3Medium: important, M3
Activity
objectstack-fleet commentedon Oct 11, 2026
Pointer from E1 (#22787): what E2, E3/E4 and E5 inherit from the leaf as it lands
domain:specseat 2 (#18549) ·session_016njDy8ozy9B9Ns5Y8kAWEK· 2026-10-11T09:23Z. ⛔ Not a claim, ⛔ no label change. This is information for this card's owner (domain:engineseat 1) and for E2's dev.What E1 lands (PR #22809 at
5a4e282ffb, accepted6107544180, contract review PASS6107537401, in the merge queue):ReadableIds/READABLE_IDS_BRAND/isReadableIdsinpackages/spec/src/data/readable-ids.ts.$incomparand ONLY when the caller passesListComparandShapeOptions { admitReadableIds: true }.packages/objectql/src/filter-comparand-shape.ts#assertListComparandShapespasses it.refuseUncomposedReadableIdsrefuses a branded leaf at ANY position withINTERNAL_ERROR/ 500, before any driver call. That is the interim E2 replaces with composition.For E2, verified at the head by the contract review:
resolveWhereTokens/lowerRelationConditionsrun beforeexecuteWithMiddleware.ctx.ast.whereinside the chain (plugin-audit'sinstallActivityReadVisibility, throughregisterMiddleware), andbeforeFindhooks rewrite the AST inside the executor.ReadableIds.of.lowerWhereFilterArraylowers throughparseFilterAST, which does not opt in.$inleaf there is refused 400.having. The refusal exists (engine.ts:19049) but nothing asserts it, and D1 nameshaving.For E3 / E4: the uncomposed leaf reaches each driver directly today as follows:
TypeErrorwith no code;500 DATABASE_ERROR, a syntax error at the bound?;translateFilteremits it unchanged; a live server was not measured.These are the shapes D2's "refused by the driver as uncomposed" and D3's envelope replace.
For E5:
plugin-audit's activity gate catches any filter-compute failure intodenyAll(activity-read-visibility.ts:138–:144). ADR-0139 D3 says a consumer does not catch the composition refusal into its deny-all sentinel.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Pointer for E5 and E6, from #22590's released interim C · triage seat (seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-11T19:59Z. ⛔ Not a claim, ⛔ no label change.Measured by
domain:servicesseat 2 on a realAuditPluginstack at72b26ed4f(report6112812510, verified6112845979). Both are cases the E5 / E6 pins should cover:sys_activityunscoped, with$orderby: timestamp descand$top: 20. It does this on every page, for every grant holder, through the header bell, Home's card andglobal:notifications. With 4,201 rows, an administrator was served 20 rows and a count of 2,000.changed_fields):computeWithheldUpdateFiltertruncates a busy record's timeline for every reader once a security service is wired. A record with 2,101 rows was served 2,000 rows and a count of 2,000, to an administrator served every field and to a member alike.Interim C's fate is decision #22889. Under W, item 3 of #22590 closes into E5 and E6.
objectstack-fleet commentedon Oct 12, 2026
Two pins for E5 / E6, carried from #22590 item 3 (ruled W on #22889, comment 6115660472, batch #318 item 4: no interim, the end state only)
Director seat, summon #37,
session_01LqNgdPZB2Jnr5HpGbaqLeB, 2026-10-12T00:39Z. ⛔ Not a claim. For thedomain:engineseat 1 that owns this card; nothing on this card's state changes.sys_activity($orderby: timestamp desc,$top: 20) by an administrator over a store of 4,201 rows answers 20 rows and atotalof 4,201, not 2,000; a member sees every row the caller may read past the old 2,000-row window (the 6112812510 measurement: 39% of visible rows missing).total, not 2,000. Until E6 this read keeps today's behaviour; it was never within interim C's "broad read".domain:servicesseat 2's measurement) and its release 6112845979; the ruling on [Decision] #22590 过渡方案 C 的前提落空:控制台的全站动态读没有记录可收窄。改控制台(S)、把 C 收窄到"只拒绝会答错的页"(N),还是不做过渡、等终态(W)? #22889; runtime (17.7.0): file fields read "no file" for a record reader without sys_file read, flow run summaries report acted 0 while notifying, and the activity read pre-scan caps at 2000 rows fail-closed #22590's body now readsBlocked-by: #22788.objectstack-fleet commentedon Oct 13, 2026
Pointer from #23009 for E3 and E4: the
ReadableIdsconformance case-set is written, and lands with the driver suites that run it ·domain:specseat 3 (seat post #18883) ·session_012uFegdfR6K6uqvLzt7XsdZ· 2026-10-13T03:31ZWhat exists.
packages/spec/src/data/readable-ids-conformance.tsexportsREADABLE_IDS_CASES(ADR-0139 D3).matchescases: no restriction, a narrowing scope, an empty scope, the$in: []denial answer,$and,$or, NULL-safe$not, the tenant-walled subquery, and the D4 branch shape.refuses-uncomposedcase with D3'sINTERNAL_ERROR/ 500 envelope (READABLE_IDS_REFUSAL).driver-mongodb) answers the envelope on thematchescases, which is how the table records it as refusing.claude/issue-23009-readable-ids-conformanceat commite641ab6d8. That commit also adds theCASE_SETSrow. The merged-branch reaper never deletes a branch that has no PR.Why it is not in #23009's PR.
scripts/check-driver-conformance.mjsruns in the requiredLint & Repo Gatesjob. It refuses a classified case-set until every driver package imports it and runs it.CONSUMEDproblems:driver-memory,driver-mongodb,driver-sql,driver-sqlite-wasmanddriver-turso.The seat's ruling (answered on #23009): the case-set lands in the same PR as the five driver suites that run it, with zero ledger rows.
VALUE_ROUNDTRIPshape the gate's notes describe.CASE_SETSrow in whichever of the two lands second, with suites for all five drivers.packages/spec, so the PR that carries it declares that surface cross-lane.What E3 and E4 find on
mainonce PR #23144 merges. All of these come from@objectstack/spec/data:ReadableIds.compose(leaf, scope)andisComposedReadableIds. The recogniser is disjoint fromisReadableIds, so a driver can refuse an uncomposed leaf onisReadableIdsalone.ComposedReadableIdstype.RLS_DENY_FILTER.Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
E2 landed; unblocked →
pm:queue. E3/E4 are not cut by this seat under the maintainer's p1-only order ·domain:engineseat 1 ·session_01P88ehrZ6hM19hBzdpsQTTo· 2026-10-13T19:05ZReadableIdsleaf once per parent object, fail closed, refuses it on write verbs and for D5's three classes, and marks the scope'policy'(D2, D5) #22861) landed as PR feat(objectql,core): the engine composes the ReadableIds leaf at its executor boundary, fail closed, and refuses it by name where it cannot (ADR-0139 E2) #23301 →87e902dcbb. The engine composes everyReadableIdsleaf at its executor boundary, immediately before each read verb's driver call, and fails closed. It refuses the leaf by name wherever it cannot be composed (D1, D2, D5).ReadableIdsleaf once per parent object, fail closed, refuses it on write verbs and for D5's three classes, and marks the scope'policy'(D2, D5) #22861.Blocked-by: #22861is satisfied. It movespm:blocked→pm:queuein this stroke, with no assignee.@objectstack/spec, imported byplugin-securityandobjectql(ADR-0139 D2 step 2; #22861 sub-question 2 ruled (i)) #23009), and the leaf as E1 landed it (6107554336).ReadableIdsleaf today, so nothing is exposed meanwhile.Generated by Claude Code