Repository navigation
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
Conversation
… object X this caller may read" Records ruling 6097072172 on #22590 (letter A, ADR first): one non-authorable filter leaf the engine composes from canReadObject + getReadFilter and pushes down as a subquery inside the driver's tenant wall; driver-sql compiles it, the other drivers compile or refuse loudly; six in-tree consumers named; the withheld-update rule moves to a writer-stamped changed_fields column; three classes stay on the bounded fail-closed probe. ADR-0055 row (a) and ADR-0056's non-goal gain one status-line pointer each. Proposed; implements nothing. Claude-Session: https://claude.ai/code/session_01JfJfBUC3cQ6hhgm9MQK76T Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Inputs, and nothing else: card #22678 (body, claim ① Derived judgmentsWhat the diff implies. Three files, +277 / −1, all under Scope against ruling
Claims that do not hold as written — three, none moves a decision:
② Semver levelThe diff publishes nothing from any released package: three Markdown files under ③ Boundary flags
Why FAIL, and what clears it. D1–D6 are inside the ruling's scope, the quotes and measurements are exact, and every tree claim that bears on a decision holds. What fails is the record as text to be approved: one mechanism pointer names the wrong file and the gate cannot see it (a), one descriptor is stale (b), and the record's own acceptance criterion describes a pointer the diff does not carry (c). A governed record goes to the maintainer correct, not with known errors for them to spot. The fix is three edits on the dev's branch — re-anchor L178 as Implemented-by: VERDICT: FAIL Read at 2026-10-10T18:16Z — the card and its two comments, the ruling and the #22590 thread, PR #22707's body, files and net diff against |
(a) re-anchor isWithheldOnlyUpdate to activity-field-redaction.ts and spell the VALID_AST_OPERATORS, parseFilterAST and LIFECYCLE_DATASOURCE references as full path#symbol anchors so check-adr-symbol-anchors judges them; (b) replace "four-form" with the compiler's own description (closed pushdown form set, historically four, broader today); (c) the acceptance criterion and D6 name the two pointers as the diff carries them: ADR-0055's status line, ADR-0056's non-goal bullet. Claude-Session: https://claude.ai/code/session_01JfJfBUC3cQ6hhgm9MQK76T Co-authored-by: Claude <noreply@anthropic.com>
…s full path#symbol anchors A bare `#symbol` opening its line is skipped by the anchor grammar's continuation rule, so check-adr-symbol-anchors never judged these nine: canReadObject, getReadFilter (security-service.ts); parseFilterAST, assertListComparandShapes, FieldOperatorsSchema, VALID_AST_OPERATORS (D1); markFilterSubtreeProvenance (D2); applyFilterCondition, applyTenantScope (D3); computeParentRecordFilter (D4, E3/E5). Anchor spelling and re-wrapping only; no decision text changes. Claude-Session: https://claude.ai/code/session_01JfJfBUC3cQ6hhgm9MQK76T Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Re-review on the fixed head, after contract review ① Derived judgmentsWhat the diff implies. Three files, +287 / −1, all under The three items from
The two rounds changed nothing else. The
No claim in the record is found wrong on this head. ② Semver levelThe diff publishes nothing from any released package: three Markdown files under ③ Boundary flags
Why PASS. D1–D6 stay inside ruling Implemented-by: VERDICT: PASS Read at 2026-10-10T18:59Z — the card and its five comments, the ruling and the #22590 thread, PR #22707's body, comment, files and net diff against |
维护者速读(终稿)· PR #22707 · ADR-0139 · head
|
Fixes #22678
Clause-②: no
Tier H, draft only.
docs/adr/**is a governed surface (Prime Directive #14): this PR stays a draft and lands only on the maintainer's APPROVED review. ⛔ No seat readies, queues or arms auto-merge on it. #22590 remains open (it isBlocked-by:this card and objectui#12081).What this PR carries
One new record, ADR-0139 (
docs/adr/0139-engine-internal-semi-join-leaf-readable-parent-ids.md, Proposed), transcribing ruling6097072172on #22590 (batch #312 item 2, maintainer 「同意」, letter A as the end state with the ADR as its first deliverable), plus one status-line pointer each on ADR-0055 and ADR-0056. It declares and implements nothing: no code, no spec, no driver file. The execution cards are listed in the record and ⛔ not filed.What the record decides, in the ruling's own scope and nothing wider:
ReadableIds("the ids of object X this caller may read"), a branded comparand in the position a list of ids holds today ($inon the pointer field). No request can spell it: a JSONwherecannot carry the brand, and the unbranded shape is already refusedINVALID_FILTER/ 400 by the comparand door. Losing the brand fails closed, never silently widens.canReadObject+getReadFilter(both halves, fail closed, deny sentinel ⇒$in: []), lowers the scope the way the parent's own read is lowered, marks itpolicy, and leaves the tenant wall to the driver.driver-sqlcompiles it as a subquery insideapplyTenantScope; sqlite-wasm and local Turso inherit; the Turso remote transport anddriver-memoryimplement it;driver-mongodbrefuses loudly until a card measures a pipeline form. The refusal is one ADR-0112 envelope (500INTERNAL_ERROR, not an author error). ⛔ NoDriverCapabilitiesbit returns.changed_fieldscolumn with an idempotent backfill through the migration door.sys_activityon a deployment that registers the ADR-0057telemetrydatasource (recorded as a limit).Verification
Premise checked on
origin/maind8830c28by symbol, not by the card's line numbers:querySubqueriesandjoinsare retired keys inpackages/spec/src/data/driver.zod.ts;PARENT_GATE_SCAN_LIMIT = 2_000inparent-record-read-gate.ts;RELATION_FILTER_ID_CAP = 1000inpackages/objectql/src/relation-filter-lowering.ts(the card'sengine.tsattribution for the cap's definition is stale — the engine imports it); ADR-0055's row (a) and ADR-0056's non-goal read as the ruling quotes them. The six consumers were located at function level; only the activity stream was measured (report6095496633), the other five are source readings and the record says so per row.Gates at head
f87ef2345a(after two wording rounds answering contract review 6100682640), derived bynode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the branch's change set (19 commands, identical to the dispatch's list), each exit captured before any pipe, reconciled with--ran: 19 derived, 19 run, 0 NOT-MEASURED, 0 UNRUN.check:doc-formula-expressionsfirst exited 3 (PREREQUISITE NOT MET: no@objectstack/formula/@objectstack/lintdist) and was re-run afterturbo run build --filter=@objectstack/formula --filter=@objectstack/lintunder the verify lock (VERDICT command-exit 0); the re-run exited 0.check-adr-symbol-anchors: 2306 anchors across 142 records resolve, 0 line anchors (every reference this record makes is now a fullpath#symbolanchor the gate judges).check-adr-links: 725 destinations resolve. No package test or typecheck is owed (no package touched); no ablation (nothing built). Control-byte self-scan of the three files: none.Acceptance notes
main(no record, no branch, no history names it); the record takes max+1 so the registry stays monotone in time and cannot collide with whatever reserved the gap. The dispatch said "the next free number"; this is the deviation, declared..claude/skills/pm-dispatch/references/compile-surfaces.mdcitesdriver-memory/src/memory-matcher.ts(checkCondition), a file that no longer exists onmain(the evaluator is mingo inmemory-driver.ts) — a stale reference in an agent-read file, carrier: the next edit of that table.plugin-sharing'ssharing-service.tsreads record-share grants atlimit: 5000with no warning (source reading, from report6095496633; the record lists it as open item O4).维护者速读(草稿)
改了什么: 新增一份 ADR(0139,状态 Proposed),把你 10 月 10 日「同意」的 A 方案写成正式决策:引擎内部加一个不可编写、请求里永不接受的过滤叶子「这个调用者能读的 X 对象 id」,由 ObjectQL 组合权限范围后下推成对父表的子查询;driver-sql 实现,其余驱动实现或响亮拒绝;六个树内消费者(动态、审计台账、撤回更新规则、评论、表情、附件)改用它,撤回更新规则改为写入时盖一列
changed_fields并回填;委托上下文、自带插件读闸的父对象、跨数据源父对象三类保留今天的有界 fail-closed 探针。另外在 ADR-0055 与 ADR-0056 各加一行指针。不改任何代码、spec 或驱动;执行卡只列在 ADR 里,不立。为什么改: 实测一位普通成员应看到 1,808 条动态,系统只给 1,105 条且「总数」也显示 1,105,管理员恰好截在 2,000;原因是六处读闸都靠一个 2,000 行的预扫描窗口,多组织部署下所有组织的行挤同一个窗口。ADR-0055 当年明确拒绝过子查询,按第 13 条基本指令,反转一个已记录的决定本身需要一份新 ADR,所以代码之前先交这份文档。
风险与代价(含回滚): 这是一个真实的能力扩张,收窄为一个引擎内部叶子;工程量按裁决估计约 3–5k 行、6–10 个 PR、横跨三条车道。已点名的限制:driver-mongodb 在量过之前对这六类读会响亮报错(500)而不是悄悄少给;注册了
telemetry独立数据源的部署,动态表与父表不在同一驱动,这个叶子帮不上,仍靠过渡方案 C 的响亮 400;方言绑定参数上限只取了文档值,未实测。回滚:ADR 处于 Proposed,未批准即不生效;批准后任何一张执行卡都可单独不落地,文档改动本身可整体 revert。席位意见:(留空)
你要做的: 在本 PR 上给出 APPROVED review(或在评论里指出要改的决策点),批准后由
domain:engine席位按 ADR 列出的顺序立执行卡。Generated by Claude Code