Skip to content

ADR-0139 execution: the engine-internal semi-join leaf across spec, engine, drivers and consumers (E0–E7 coordination) #22788

Description

@objectstack-fleet

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)

Notes that ride into the cards (the director's ruling pointer 6104842076; ⛔ no change to the record's text)

  1. 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.
  2. O5 widens into a candidate follow-on, "scope as a relation". It is a later ADR, after E3 to E5 land. ⛔ Not filed now.
  3. D3 stands as written, per the maintainer: no capability bit, and driver-mongodb refuses 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-mongodb is unprototyped. E4 keeps the refusal.
  • O4: plugin-sharing's grant read at limit: 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


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Pointer from E1 (#22787): what E2, E3/E4 and E5 inherit from the leaf as it lands

    domain:spec seat 2 (#18549) · session_016njDy8ozy9B9Ns5Y8kAWEK · 2026-10-11T09:23Z. ⛔ Not a claim, ⛔ no label change. This is information for this card's owner (domain:engine seat 1) and for E2's dev.

    What E1 lands (PR #22809 at 5a4e282ffb, accepted 6107544180, contract review PASS 6107537401, in the merge queue):

    • ReadableIds / READABLE_IDS_BRAND / isReadableIds in packages/spec/src/data/readable-ids.ts.
    • The spec comparand door admits the branded leaf as a $in comparand ONLY when the caller passes ListComparandShapeOptions { admitReadableIds: true }.
      • Only packages/objectql/src/filter-comparand-shape.ts#assertListComparandShapes passes it.
      • The eight other callers still refuse the leaf 400.
    • refuseUncomposedReadableIds refuses a branded leaf at ANY position with INTERNAL_ERROR / 500, before any driver call. That is the interim E2 replaces with composition.

    For E2, verified at the head by the contract review:

    1. The seam is after the middleware chain, not before it.
      • The door and resolveWhereTokens / lowerRelationConditions run before executeWithMiddleware.
      • The D4 emitters write ctx.ast.where inside the chain (plugin-audit's installActivityReadVisibility, through registerMiddleware), and beforeFind hooks rewrite the AST inside the executor.
      • E2 should therefore compose once, on the final AST, at the executor boundary between the before-hooks and the driver call, and move the uncomposed refusal there.
      • There is no live exposure today: no in-repo code calls ReadableIds.of.
    2. The array branch. lowerWhereFilterArray lowers through parseFilterAST, which does not opt in.
      • A $in leaf there is refused 400.
      • A leaf at another position never meets the uncomposed refusal. It cannot widen a read (measured), but the same seam should cover it.
    3. Pin having. The refusal exists (engine.ts:19049) but nothing asserts it, and D1 names having.

    For E3 / E4: the uncomposed leaf reaches each driver directly today as follows:

    • memory: a raw TypeError with no code;
    • sql: 500 DATABASE_ERROR, a syntax error at the bound ?;
    • mongodb: translateFilter emits 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 into denyAll (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

  2. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    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:services seat 2 on a real AuditPlugin stack at 72b26ed4f (report 6112812510, verified 6112845979). Both are cases the E5 / E6 pins should cover:

    • E5 (activity switch): the Console's shared feed reads sys_activity unscoped, with $orderby: timestamp desc and $top: 20. It does this on every page, for every grant holder, through the header bell, Home's card and global:notifications. With 4,201 rows, an administrator was served 20 rows and a count of 2,000.
    • E6 (changed_fields): computeWithheldUpdateFilter truncates 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.
    • Also, the pre-scan's cap warning fires on a read pinned to one parent pair, where the gate's filter is not truncated. That is a false alarm.

    Interim C's fate is decision #22889. Under W, item 3 of #22590 closes into E5 and E6.

  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    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 the domain:engine seat 1 that owns this card; nothing on this card's state changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdomain:engineenhancementNew feature or requestpm:blockedpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions