Repository navigation
fix(plugin-audit,service-storage): a delegated caller reads the parent-record gates through the ReadableIds leaf (ADR-0139 D5.1) - #25259
Conversation
…t-record gates through the ReadableIds leaf (ADR-0139 D5.1) The engine composes the leaf for an on-behalf-of caller since the D5.1 amendment, answering both halves with the delegator intersection (ADR-0090 D10). The activity, ledger, comment-thread and attachment read gates still sent that caller's whole read to the bounded probe up front, the residue the amended record names. Retire that routing: the plan reads nothing of the caller, D5.2 and D5.3 parents stay on the probe. Claude-Session: https://claude.ai/code/session_01RTeCSatTcP3SkMdpQumyfU Co-authored-by: Claude <noreply@anthropic.com>
…f and to parity with its probe (ADR-0139 D5.1) The unit stand-ins pin that a delegated caller is written the same leaves and the same restricted probe as any caller, with D5.2 / D5.3 parents still probed under the delegated envelope. The real-engine suites give the stand-in a delegator intersection (three DOC rows withheld from the delegator), then pin that the leaf serves a delegated caller exactly that intersection past the window with a true total, and that it agrees with the probe's own readability answer over every parent pair at rest. Claude-Session: https://claude.ai/code/session_01RTeCSatTcP3SkMdpQumyfU Co-authored-by: Claude <noreply@anthropic.com>
…t read item; patch changeset for the delegated leaf attachments-storage.read-inherits-parent-rls revision 7: knownGaps[2], acceptance[3] and both refs name ADR-0139 D5's two remaining classes now that a delegated caller reads through the leaf (D5.1, as amended). Claude-Session: https://claude.ai/code/session_01RTeCSatTcP3SkMdpQumyfU Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check10 anchor(s) derived from 2 changed package(s); no hand-written page names any of them. What this run could not see
Coarse fallback — 16 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 89576b03c362d5544ac2f4351bbeb815e6e1a42c && git checkout 89576b03c362d5544ac2f4351bbeb815e6e1a42c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6bc8cc6a7dc05644df759dc2a3e5c3e67fa0dcd5 b62709acb5c307b3298fa635d2f0c9ffbeb5d9be && git checkout -B drift-repro 6bc8cc6a7dc05644df759dc2a3e5c3e67fa0dcd5 && git merge --no-ff b62709acb5c307b3298fa635d2f0c9ffbeb5d9be
node scripts/docs-audit/affected-docs.mjs --json 6bc8cc6a7dc05644df759dc2a3e5c3e67fa0dcd5 |
席位核对 · ACCEPT · 2026-10-22T17:26Z
Generated by Claude Code |
Requested by Sales · project thread
Fixes #25034
Clause-②: no
Metadata-protocol: none
What changes
ADR-0139 D5.1, as amended by maintainer ruling
6303721609: the engine composes theReadableIdsleaf for a delegated caller from the delegator intersection (ADR-0090 D10, landed in #25009). So a delegated (on-behalf-of) caller is no longer a probe class in the parent-record read gates.@objectstack/plugin-audit.parent-record-read-gate.tsdrives the activity, ledger and comment-thread gates.planParentReadsno longer reads the caller: itscontextparameter,isDelegatedCallerand the'delegated-caller'member ofParentProbeClass/ParentReadPlanare gone. A delegated caller's read is written the same leaves as any caller's.@objectstack/service-storage.attachment-access-hooks.tsgets the same change to the attachment gate:planAttachmentParentReads(engine, objectAdmission), andWholeReadProbeis reduced to the two whole-read states.engine-cannot-classify,no-object-admission) are untouched. ⛔ The gates read no delegation link themselves; the intersection is the engine's and the security service's.activity-read-visibility.ts,audit-log-read-visibility.tsandcomment-access-hooks.tsnow name two classes.total.Pins: delegated parity with the probe
Unit stand-ins.
comment-thread-leaf.test.ts,activity-read-visibility.test.tsandattachment-read-leaf.test.tspin that a delegated caller is written the same leaves and the same restricted probe as a plain caller. A D5.2 parent is still probed, and its probe read carriesonBehalfOfand no__readScope.Real-engine suites.
parent-record-read-leaf.integration.test.ts(sys_activity and sys_audit_log),comment-parent-pair.integration.test.tsandattachment-read-leaf.integration.test.tsgive the security stand-in a real delegator intersection: three DOC records are withheld from the delegator. Each suite then pins two things:countagrees. The difference from the principal's own read is exactly the rows on the withheld records, so the leaf is the intersection, never the principal's leg alone.resolveReadableParentIdsis the probe's own readability function. Asked as the delegated caller over every parent pair at rest (so no window cuts it), it admits exactly the set the leaf serves.Ablation (services lane)
Each new pin was run against the behavior it forbids, then restored.
parent-record-read-gate.tsandattachment-access-hooks.tswere checked out frome58bd0e3, which brings backisDelegatedCaller→'delegated-caller'. All 10 new pins went red:activity-read-visibility.test.ts(expected [ null ] to deeply equal [ 'crm_case', 'crm_deal', null ]), thecomment-thread-leaf.test.tspin (expected [] to deeply equal [ 'crm_case', 'crm_deal' ]), and 2 + 2 integration pins. The leaf-set assertions failed withexpected [] to deeply equal ArrayContaining ["e5_doc", "e5_vault"]. The parity pins failed on the truncated window: 1764 or 1771 rows served against 2299 admitted.expected [] to deeply equal [ 'att_case', 'att_secret' ]), and the leaf and parity pins, 1758 rows served against 2299.ObjectQL#readableIdsScopeOfwas handed{ ...chain.context, onBehalfOf: undefined }. All 6 intersection and parity pins went red. The withheld rows leaked: 2302 against 2299 for activity and attachments, and 2303 against 2299 for comments, since four comments sit on the withheld threads.HEADand from a byte copy of the engine'sdist. The full suites are green afterwards.Checklist
docs/qa/platform-checklist/areas/attachments-storage.jsonis adomain:devxpath, declared in the claim. Inattachments-storage.read-inherits-parent-rls, at revision 7,knownGaps[2],acceptance[3],automated.refandsourcenamed a delegated caller among D5's three classes. They now name the two remaining classes, and earlier history entries are unchanged.pnpm check:platform-checklistis green.Verification
node scripts/pm/dispatch-gates.mjs --commandson this diff derived 72 commands. All 72 were run, and every one exits 0.--ranreconciles them as "72 derived, 72 run, 0 NOT-MEASURED, 0 UNRUN". Three first answered exit 3 on a prerequisite:check-plugin-teardown-shape --self-testneeded its pinned fixture commit, which a shallow clone lacks, andcheck:dual-build-cjs-loadsandcheck:i18nneeded the whole workspace built. Each was re-run to 0 aftergit fetch --depth=1or a fullpnpm build, and the fourdist-reading gates that overlapped that build were re-run after it.No dogfood battery: the title carries no
!, andClause-②carries no(narrowing)arm.pnpm --filter @objectstack/plugin-audit test: 60 files, 985 passed.pnpm --filter @objectstack/service-storage test: 62 files, 1131 passed.typecheckpassed for both packages, as didbuildfor both, includingcheck-dts-emitted.eslint --no-inline-configover the changed.tsfiles: clean.Notes
claude/project-thread-982vgc, notclaude/issue-25034-…, so the Duplicate Fix Guard's branch-name hint will not match. The claim on ADR-0139 D5.1 follow-up: once the ReadableIds leaf composes for a delegated caller, retire each consumer's 'delegated-caller' whole-read probe routing (plugin-audit gates, service-storage attachments) #25034 is the identity record.🤖 Generated with Claude Code
https://claude.ai/code/session_01RTeCSatTcP3SkMdpQumyfU