Skip to content

Seam: IObjectQLEngine gains an optional judge-only filter-admission method, run by the engine's own admission pipeline without executing (objectstack#19995 ruling C) #20157

Description

@objectstack-fleet

Seam: spec IObjectQLEngine (one optional judge-only member) → runtime packages/objectql admission pipeline; consumers service-analytics ObjectQLStrategy.withReadScope / resolveFkAttr (#19995) and plugin-security policy admission (the second consumer card filed with this ruling)

Filed by the director seat from the maintainer's ruling on #19995 (batch #225 item 3, letter C, 「同意」). Reader who acts: the domain:spec seat, dispatched vertically (the contract member in packages/spec, the implementation in packages/objectql). area:* is left for triage. Consumers wait on this card with Blocked-by:: #19995 (the analytics ObjectQL face pre-judges the read scope) and the authoring-time admission card filed beside this one. Dedupe: REST list of open cards in this repository read for judge-only, pre-judge, filter admission method in titles → none; #19995's own dedupe (42 semantic hits, none on the engine face) stands.

What the ruling settles

The engine becomes the single judge of 「can this filter run against this object」 for callers that must know before composing a policy scope into a query. Today the engine's admission doors (text-operator-declared-type-door.ts, temporal-comparand-door.ts, the FILTER_TOKEN_UNKNOWN resolver, the virtual-field and lookup-path refusals) run only inside execution; their walks are not reachable through the package exports (. and ./core only: git grep -c -E "findTextOperatorOverNonTextField|findUninterpretableTemporalComparand|assertFilterIsMaterializable" origin/main -- packages/objectql/src/index.ts packages/objectql/src/core.ts → 0, control export .*ObjectQL → 5); @objectstack/service-analytics depends on the engine only optionally (src/plugin.ts:278 optionalDependencies) and only at dev time (package.json).

Work

  1. packages/spec/src/contracts/objectql-engine.ts: one OPTIONAL member on IObjectQLEngine that judges a where (a FilterCondition) against a named object and returns either ok or the same diagnostic the engine would raise at execution (code and message), without executing anything. Name and exact signature are the seat's and the contract review's to settle; the docblock states these semantics.
  2. packages/objectql: the implementation runs the engine's own admission pipeline (every door execution runs, in the same order) and stops before any driver call. ⛔ Not a second copy of the walks: the doors are factored so that execution and judgement call the same functions. Premise to verify first: the admission pipeline can run without a driver or data; if a door needs either, stop and report the fork.
  3. Pins: for each class security: the analytics ObjectQL execute face answers a row-level read scope it cannot run with INVALID_FILTER / 400 whose message echoes the policy's field name and comparands — the disclosure #5367 closed for the native / echo faces #19995 lists (a text operator over a non-text field, an uninterpretable temporal comparand, an unknown filter token, a filter on a virtual field, a dotted path through a lookup) the judge returns the door's diagnostic and execution raises the same one; a runnable filter returns ok; nothing is executed (a driver spy sees no call).
  4. Changeset minor for @objectstack/spec (a new optional contract member) and @objectstack/objectql. Clause-②: yes — a contract review before enqueue.

Governing text: the #5367 ruling as recorded in packages/services/service-analytics/src/read-scope-sql.ts (a read-scope refusal is never a 4xx; the policy's fields and comparands never reach an error body); ADR-0058 D2 (a compile-surface predicate the compiler cannot lower is an authoring-time compile error); ADR-0021 D-C (the analytics read scope is enforced by the engine); the domain:engine decision on #20020 (comment 5823452098 on #19995: the doors keep their diagnostics for CRUD callers; the analytics face pre-judges the scope alone).

Mainstream shape this follows: PostgreSQL validates a policy at CREATE POLICY and evaluates security quals before non-leakproof user quals; SQL Server binds security predicates at policy creation; Oracle VPD answers a broken predicate with a generic error and writes the detail to the trace; Hasura validates row permissions when metadata is applied. A judge-only entry point is the platform's PREPARE / EXPLAIN for filter admission.

Dedupe words: engine judge-only filter admission method · IObjectQLEngine optional member pre-judge where · read scope pre-judge withReadScope 19995

Director seat · session_01AsCNgFBs8HCjwhyHQsFbx3 · filed from the ruling on #19995


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Serial note from domain:spec seat 4 (session_01CiCTczDo7tGhafXjf61dUJ, seat post #18917), 2026-09-27T04:17Z. ⛔ Not a claim; the state is unchanged (pm:queue).

    Reached in this seat's round 1 take order (a contract-face card) and passed over because of a hot region.

    Readings: git grep on origin/main 2bbebf5 — the door helpers are imported at engine.ts:45 and called at :980, :1074 and, in the aggregation loop, :16137. The #20148 claim's file surface is its own Claim: comment.

  2. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01CiCTczDo7tGhafXjf61dUJ
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-20157-engine-judge-filter-admission
    Worktree: objectstack-issue-20157
    Domain: domain:spec
    Seat: domain:spec#4 (seat post #18917)
    File surface: the contract member in packages/spec/src/contracts/objectql-engine.ts (one OPTIONAL judge-only member on IObjectQLEngine, plus its docblock) and its tests; the implementation in packages/objectql/src/ — the where admission doors refactored so that execution and the judge call the same functions (engine.ts in its find / where-admission path and the module-level door functions; filter-comparand-shape.ts, temporal-comparand-door.ts and the text-operator door file only where the refactor must touch them), with their tests; the generated artefacts that follow (api-surface, export-origins), regenerated and never hand-edited; .changeset/. Cross-lane (packages/objectql is domain:engine): declared here because this is a Seam: card that goes vertically to the spec seat. ⛔ Not ObjectQL.aggregate's per-aggregation filter loop, which the live domain:engine claim on #20176 holds. (stop on breach; explain in the report)
    Container & model: M/L, mode:subagent, model: default judgment tier (the default slot is taken: a new public contract member plus a refactor that must keep execution byte-identical). The review of a widened contract runs at CONTRACT_REVIEW_TIER before enqueue.
    Clause-②: yes
    Thread-read: 5852563458
    Serial constraints cleared: read at 2026-09-27T07:25Z. The serial predecessor #20148 landed as cfe2387a3 (PR #20174: engine.ts +29 lines, having-filter.ts +284). It added no shared "run every where door" function, so this card builds one; it does not reuse one. Open-PR census (15 open PRs besides the release PR, 303 file rows, lit control 158 packages/ rows): none touches packages/objectql/src/engine.ts, the door files or contracts/objectql-engine.ts. In-flight claims: domain:engine #20176 holds the per-aggregation loop of engine.ts, a different region. Downstream: #19995 and #20158 carry Blocked-by: #20157.

    Ruling carried: #19995's ruling C (batch #225 item 3, 「同意」), as the card body records it. The engine becomes the single judge of 「can this filter run against this object」 for callers that must know before composing a policy scope. Its Governing text is also in the body.

  3. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20157,
    "status": "done",
    "branch": "claude/issue-20157-engine-judge-filter-admission",
    "pr": "#20213",
    "session": "session_01CiCTczDo7tGhafXjf61dUJ — the harness-stamped id in this run's commit trailers (Claude-Session line); a subagent run carries the parent's",
    "premise_still_valid": true,
    "summary": "IObjectQLEngine gains one OPTIONAL member, judgeFilter(objectName, where, { operation?, context? }), which is synchronous and returns { ok: true } | { ok: false, code, status, message }. ObjectQL implements it through judgeWhereAdmission. That function calls the two stage functions every where-taking verb already calls, in the same order: lowerWhereFilterArray (shape gate, list-comparand shape, materializable dotted then virtual, text operator, temporal, comparand type; array form through parseFilterAST) and then resolveWhereFilterTokens. resolveWhereFilterTokens is now the single spelling behind ObjectQL.resolveWhereTokens and ObjectQL.withResolvedWhere. The judge stops before getDriver and makes no driver, hook or middleware call. Premise 1 held door by door: each door reads only the where value, the registry field map and, for placeholders, the context. PM assumption 2 held: the where sequence is identical on all six verbs, and what differs by verb (getDriver position, option folding, orderBy/projection, per-aggregation/having) is not a where door. The aggregate per-aggregation loop is untouched. Assumption 3, placeholder semantics: the judge expands placeholders against the supplied context. Evidence: #19995's consumer already calls assertReadScopePlaceholdersResolvable(scope, objectName, ctx.context), which runs the engine resolver against the context it forwards to executeAggregate. An unanswerable placeholder answers FILTER_TOKEN_UNRESOLVED/400 and is never read as null (pinned). Assumption 4 held: objectql exports are unchanged ('.' and './core'). The judge is reached through the engine instance; spec/contracts gains two type exports (EngineFilterJudgement, EngineFilterJudgementOptions), with api-surface and export-origins regenerated. Consumers are not wired. The changeset is minor for spec and objectql, with Clause-②: yes in the changeset and on its own line in the PR body.",
    "tests": "Final head c797375. New pins: objectql src/engine-judge-filter.test.ts 43/43 (5 classes x 6 verbs; judge and execution agree on code+status+full message; ok path; driver spy zero calls, getDriver not called, hook+middleware not run, each with a positive control; two-defect order; placeholder context; unregistered object). Spec src/contracts/objectql-engine.test.ts 12/12 (5 new type pins). Full suites at 30dadfb (only delta to c797375 is one docblock's wording): objectql 317 files/5671 passed, with existing door tests unmodified; spec 541/15901 passed, 2 todo. Consumers (downstream importers of IObjectQLEngine) at 30dadfb: service-analytics 128/3017; plugin-security 136/2740; metadata-protocol 189 passed+3 skipped files/2700 passed+19 skipped; core 53/1358; rest 197/3339+1 skipped; runtime 279/3906+1 skipped; platform-objects 55/911; plugin-approvals 51/791; plugin-pinyin-search 2/21; plugin-sharing 37/913; trigger-record-change 10/101; service-datasource 34/693; plugin-hono-server 27/324; plugin-auth 114/2440; cloud-connection 30/397; cli --project unit 225/3192 (integration tier declared to CI); dogfood typecheck green plus its 5 IObjectQLEngine importers 5/38 (full dogfood declared to CI). Typecheck green: spec, objectql, service-analytics, plugin-security, metadata-protocol, core, rest, runtime. Ablation via scripts/ablation-replace.mjs from committed state, mutation and restore both proven on disk (anchor 1→0, blob changed; restore blob==HEAD, git diff HEAD empty). Deleting the stage-2 call: 7 failed/36 passed, as predicted (unknown-placeholder on 6 verbs plus the unresolved-context pin). Replacing stage 1 with { where }: 30 failed/13 passed. Reverse type verification: operation 'insert' gave TS2322 against the rebuilt spec dist; control leg 0 errors in both new test files under tsconfig.test.json. Lint, narrowed and proven: eslint --format json over the 4 changed .ts files gave 4 files, 0 errors, 0 warnings; --print-config returns a config for all 4 (none ignored); no parserOptions.project, so not type-aware, and the diff cannot move untouched files' verdicts.",
    "mcp_calls": "0 — no MCP GitHub tool was called",
    "api_writes": "3 REST writes, all through scripts/pm tools over the fleet-write relay (each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft, #20213); (2) label-write --assign os-sales → POST /repos//issues/20213/assignees; (3) this os-dev-report → POST /repos//issues/20157/comments. git push is not REST (7 pushes of the one branch, the first an empty-branch probe).",
    "open_questions": [
    {
    "question": "For #20158 (authoring-time admission): the judge expands placeholders against the supplied context, so a policy that contains a context placeholder such as {current_user_id}, judged with no context at save time, answers FILTER_TOKEN_UNRESOLVED. Keep that, or add a mode that refuses only unknown placeholders?",
    "options": [
    "A keep today's semantics: #20158 passes a representative context, or treats FILTER_TOKEN_UNRESOLVED at save time as its own verdict",
    "B add an option (e.g. placeholders: 'classify') that refuses FILTER_TOKEN_UNKNOWN but admits known context placeholders without a value"
    ],
    "recommendation": "A. RLS policies reach #20158 as CEL lowered to a FilterCondition with concrete values, so no measured policy carries a placeholder today. B widens a just-published contract with no call site behind it (startup-stage narrowness), and A is what execution answers. This is not blocking; the contract review may settle it."
    }
    ],
    "out_of_scope_findings": [
    "carrier: domain:engine seat (the #20148 lane, which measured it in cfe2387's own table) · noted, not filed: where's { $field } declared-referent and addDays class rule are enforced only by driver-sql (driver-memory answers a count), while the per-aggregation filter now refuses them at the engine. The judge is bounded by the engine's own admission, so it answers ok for these; this is stated in the contract docblock and the PR's Acceptance notes. It is a read of a landed measurement, not a new reproduction by this run."
    ],
    "gates": {
    "head": "c797375ab",
    "derived": 89,
    "ran": 89,
    "not_measured": 0,
    "unrun": 0,
    "reconcile": "node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack → exit 0 (89 run, 0 NOT-MEASURED, 0 UNRUN)",
    "commands": [
    "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
    "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
    "node scripts/check-changeset-no-major.mjs --self-test :: exit 0",
    "node scripts/check-ci-filter-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-corpus.mjs :: exit 0",
    "node scripts/check-dev-prereqs.mjs --self-test :: exit 0",
    "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
    "node scripts/check-empty-changeset.mjs --self-test :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --days 90 :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --self-test :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0",
    "node scripts/check-registry-log-declared.mjs :: exit 0",
    "node scripts/check-registry-log-declared.mjs --self-test :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0",
    "node scripts/check-spec-docblock-symbol-anchors.mjs :: exit 0",
    "node scripts/check-spec-docblock-symbol-anchors.mjs --self-test :: exit 0",
    "node scripts/check-system-context-census.mjs :: exit 0",
    "node scripts/check-system-context-census.mjs --self-test :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0",
    "node scripts/docs-audit/check-affected-docs.mjs :: exit 0",
    "node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
    "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
    "pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0",
    "pnpm --filter @objectstack/spec run check:api-surface :: exit 0",
    "pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0",
    "pnpm --filter @objectstack/spec run check:browser-reachable-entries :: exit 0",
    "pnpm --filter @objectstack/spec run check:docs :: exit 0",
    "pnpm --filter @objectstack/spec run check:dual-source-exports :: exit 0",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
    "pnpm --filter @objectstack/spec run check:empty-state :: exit 0",
    "pnpm --filter @objectstack/spec run check:entry-nameability :: exit 0",
    "pnpm --filter @objectstack/spec run check:export-origins :: exit 0",
    "pnpm --filter @objectstack/spec run check:exported-any :: exit 0",
    "pnpm --filter @objectstack/spec run check:generated :: exit 0",
    "pnpm --filter @objectstack/spec run check:liveness :: exit 0",
    "pnpm --filter @objectstack/spec run check:llms-txt :: exit 0",
    "pnpm --filter @objectstack/spec run check:objectui-pin-citations :: exit 0",
    "pnpm --filter @objectstack/spec run check:skill-refs :: exit 0",
    "pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0",
    "pnpm --filter @objectstack/spec run check:variant-docs :: exit 0",
    "pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0",
    "pnpm check:changeset-gate-self-tests :: exit 0",
    "pnpm check:cross-package-test-inputs :: exit 0",
    "pnpm check:dispatcher-error-vocabulary :: exit 0",
    "pnpm check:doc-authoring :: exit 0",
    "pnpm check:driver-memory-census :: exit 0",
    "pnpm check:dts-closure :: exit 0",
    "pnpm check:dual-build-cjs-loads :: exit 0",
    "pnpm check:durability-log-level :: exit 0",
    "pnpm check:engine-double-contract :: exit 0",
    "pnpm check:gitlink-declared :: exit 0",
    "pnpm check:issue-citations :: exit 0",
    "pnpm check:lean-entry-closure :: exit 0",
    "pnpm check:logger-receiver-detach :: exit 0",
    "pnpm check:merge-driver :: exit 0",
    "pnpm check:nul-bytes :: exit 0",
    "pnpm check:objectql-double-limit :: exit 0",
    "pnpm check:objectui-changeset :: exit 0",
    "pnpm check:org-identifier :: exit 0",
    "pnpm check:page-declaration-shape :: exit 0",
    "pnpm check:pm-changeset-deadline-census :: exit 0",
    "pnpm check:pm-prior-rulings :: exit 0",
    "pnpm check:pm-widening-tells :: exit 0",
    "pnpm check:published-files :: exit 0",
    "pnpm check:query-options-erasure :: exit 0",
    "pnpm check:refd-timer-probe :: exit 0",
    "pnpm check:slot-lookup :: exit 0",
    "pnpm check:sourcemap-no-sources-content :: exit 0",
    "pnpm check:spec-parsed-alias :: exit 0",
    "pnpm check:stack-collection-maps :: exit 0",
    "pnpm check:swallow-census-controls :: exit 0",
    "pnpm check:test-source-alias :: exit 0",
    "pnpm check:tier-file-adoption :: exit 0",
    "pnpm check:type-check-coverage :: exit 0",
    "pnpm check:type-check-debt :: exit 0",
    "pnpm check:watch-hint-literal :: exit 0",
    "pnpm check:where-matcher :: exit 0"
    ]
    },
    "line_budget": "n/a: no skills/** or ledgered governed file touched; diff +626/-3 over 7 files, under the 5000-line human-merge threshold",
    "files_changed": [
    ".changeset/20157-engine-judge-filter.md",
    "packages/objectql/src/engine-judge-filter.test.ts",
    "packages/objectql/src/engine.ts",
    "packages/spec/api-surface/contracts.json",
    "packages/spec/export-origins/contracts.json",
    "packages/spec/src/contracts/objectql-engine.test.ts",
    "packages/spec/src/contracts/objectql-engine.ts"
    ],
    "ci": "in_progress at report time (32 check runs on c797375: 12 success, 3 skipped, 17 in_progress, none failed); not awaited, per contract",
    "deviations": [
    "check:type-check-debt's first run rebuilds the whole package closure itself, outside the verify lock, and my runner's 280 s timeout killed it partway. That left driver-mongodb dist without .d.ts, so the second run exited 3 PREREQUISITE NOT MET. I rebuilt the closure under the lock and re-ran the gate under the lock: exit 0, 4 entries at their numbers. ran.list records that exit 0.",
    "Two test suites were chained in one call (service-analytics, plugin-security). The call hit the 600 s tool cap and the harness moved it to the background. I waited in the foreground with tail --pid on the lock-holder pid and read both verdicts (green) before going on.",
    "The consumer suites were run at 30dadfb, not the final c797375. The only delta is the wording of one docblock in objectql-engine.ts. The gate union and the new pins were re-run at c797375.",
    "origin/main was not merged into the branch. It is behind by commits disjoint from this diff's files, and CI's merge ref tests the combination.",
    "Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Per AGENTS.md (the repo's instruction, which the reminder defers to), commits carry the model-free pair, and the PR body ends with the session-URL footer.",
    "Header conflict, surfaced rather than chosen silently: IObjectQLEngine's header said members beyond IDataEngine are REQUIRED, and its evidence bar asks for an existing cross-package call site. The ruling orders an OPTIONAL member ahead of its consumers. The ruling wins; the header is amended to name this one exception and why."
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #20213 (2026-09-27T10:33Z)

    domain:spec seat 4 (session_01CiCTczDo7tGhafXjf61dUJ). This is the review of record for the round claimed in 5853787627; the dev report is 5854899027.

    Checklist, read on GitHub:

    • PR form: draft, base main, first line Fixes #20157, no other closing keyword. The bare line Clause-②: yes matches the diff. Assignee os-sales.
    • Scope: 7 files (+626 / −3).
      • Source changes: packages/spec/src/contracts/objectql-engine.ts (one optional member, two types, a header paragraph naming the one exception) and packages/objectql/src/engine.ts (+127 / −2).
      • Also: two test files, the regenerated api-surface and export-origins for contracts, and a changeset (minor for @objectstack/spec and @objectstack/objectql).
      • No consumer is wired, and the objectql entry points are unchanged, as the claim required.
    • At-tier contract review: PASS, record 5855050723 on the PR, at head c797375ab2.
    • CI at c797375ab2: 32 success, 3 skipped (Build Docs, Console Pin Gate, the opt-in tarball smoke; all path-filtered or opt-in). No failures.
    • Merge: mergeable_state: clean. A no-driver merge-tree onto today's main (585c9af587) exits 0.
    • Governed surface: 0 of 7 paths; 629 changed lines.
    • Dev evidence: 89 of 89 derived gates exit 0. Two ablations failed exactly the predicted pins (stage 2 removed: 7 failed; stage 1 replaced: 30 failed). Consumer suites in 16 importing packages are green.

    The dev's open question (placeholder mode for #20158): A, keep today's semantics. No change to this PR.

    Review record, non-blocking items (6), each disposed:

    Downstream: #20158 carries Blocked-by: #20157 and unlocks when this card closes. It belongs to domain:services, so this seat does not dispatch it. #19995's analytics consumer is that card's own work.

    Next: ready → auto-merge through the relay → merge queue. This card closes on the merge through Fixes.

  5. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed — PR #20213 → 4df101c383 (2026-09-27T11:01Z)

    domain:spec seat 4 (session_01CiCTczDo7tGhafXjf61dUJ). PR #20213 merged through the merge queue on 2026-09-27T10:57:18Z, and this card closed completed through its Fixes line. The readings that confirm the landing:

    • 4df101c383 has one parent (3875ae6773), is an ancestor of origin/main, and the queue branch for the PR is gone.
    • Its git patch-id --stable equals the reviewed diff's (763bd5d68551 on both; 7 files, +626 / −3).
    • By content: judgeFilter has 3 hits in packages/objectql/src/engine.ts and 5 in packages/spec/src/contracts/objectql-engine.ts, and 0 in both on the parent.

    pm:dispatched and the assignee come off in the same act.

    Downstream: #20158 (domain:services) carries Blocked-by: #20157 and is released by the unlock scan; the placeholder-semantics pointer for its dispatcher is 5855081099. #19995's analytics consumer is that card's own work.

  6. added 2 commits that reference this issue on Sep 28, 2026
    4df101c
    ab82001
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions