Skip to content

plugin-security: the raw-SQL read-scope provider (getReadFilter) does not apply the delegated organization-membership rule PR #25101 enforces at the operation prologue; measure reach first (detail withheld) #25106

Closed

Description

@objectstack-fleet

Filing gate ①, the security exception ("may expose data": measure reach first). The source is the isolated contract review of PR #25101 (#25063), boundary flag 1 of 6313542596, which escalated this to the seat as a data path, not probe parity. It is a source reading; reach is not measured. Filed by domain:services seat 2 (seat post #21118, os-support-ai, session session_01UmqzD97e14iws6hmVhgZ5y). ⛔ Not a claim. ⛔ Ungraded and unrouted: the grade and lane are triage's.

Disclosure: the maintainer's ruling recorded on #9387 (5323310017) applies. This card records only:

  • that the reading exists, and where it lives;
  • the governing text.

⛔ No probe, context shape, request or served value goes on this card, its PR or any comment.

Reader (who acts): triage grades the card. Then the lane that takes it measures reach FIRST, and fixes only if reach is shown.

Where it lives (origin/main at filing)

Governing text

  • ADR-0090 D10: a delegated operation is bounded by the delegator's scope.
  • ADR-0021 D-C: the raw-SQL read scope is the find path's scope.
  • The provider's own lock-step doc.

Dedupe

Searched (semantic): getReadFilter computeDelegatedReadFilter delegated organization membership raw SQL read scope analytics. Hits: #20733, #24164, #21177, #21417, #21080, #20933, #20001, #5815, all closed. None is this reading. #5815 (getReadFilter missing the controlled_by_parent half) is the nearest: same provider, different rule.

Dedupe words: getReadFilter delegated organization not backed · raw SQL read scope on-behalf-of vetOrganizationClaim · computeDelegatedReadFilter prologue parity.

Activity

  1. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Serial after #24932 · domain:services seat 2 (seat post #21118) · session_01UmqzD97e14iws6hmVhgZ5y · 2026-10-21T13:55Z. ⛔ Not a claim, no label change.

  2. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (re-seated term) · 2026-10-21T14:53Z · p2, domain:services, reach-first under the disclosure ruling (#9387 5323310017)
    Session: session_01UmqzD97e14iws6hmVhgZ5y (the dispatching seat; the dev is a mode:subagent run of this session, told apart by its branch)
    Account: os-support-ai (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-25106-read-scope-org-vet
    Worktree: objectstack-issue-25106
    Domain: domain:services
    Seat: domain:services#2
    File surface: measure reach first. Only if reach is shown: packages/plugins/plugin-security/src/security-plugin.ts, the delegated prologue of getReadFilter / computeDelegatedReadFilter (:5969 / :6092 at edcc8ceae) and nothing else in that file, plus the plugin's tests and .changeset/. ⛔ Not the engine middleware's prologue (resolveOperationPrincipals, which PR #25101 already changed). ⛔ Not service-analytics.
    Container & model: M, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates --tier on this surface: "no path-derived mandate")
    Clause-②: no — expected: if reach is shown, the provider answers the deny sentinel where the operation prologue now refuses. That is a narrowing of a runtime read scope, not a published accept set. If the fix lands, it owes a review at CONTRACT_REVIEW_TIER before the queue, as #25063's did.
    Responsibility: plugin-security's computeDelegatedReadFilter (this lane's code) mirrors the middleware's layers but not the delegated prologue PR #25101 added | the operation prologue resolveOperationPrincipals → vetOrganizationClaim already refuses on the find path; the raw-SQL provider is the one door that does not mirror it | reach not measured: the review called it in-process only, with no door that builds the shape; the dev measures it first
    Thread-read: 6317847384
    Serial constraints cleared: supersedes this seat's note 6317847384. #24932 is no longer in flight: it is in needs-user-decision (6318800595), with no branch commits. So this card goes first in getReadFilter / computeDelegatedReadFilter. #24932's switch, when it is re-dispatched, merges main and reads this change (its dev already priced it: 6318648840 deferred_card_repricing). In flight in this lane: #25096 / PR #25109 (plugin-auth), which is disjoint. Seat 1's queued #25095 is a different region (the detail write gate). No open PR touches security-plugin.ts.

  3. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    pm:dispatched → pm:queue, released before any measurement · domain:services seat 2 (seat post #21118) · session_01UmqzD97e14iws6hmVhgZ5y · 2026-10-21T14:59Z · Thread-read: 6319041191

    Release: session_01UmqzD97e14iws6hmVhgZ5y · Cause: the maintainer's word in this session's chat, verbatim: 「你可以下班了」 and then 「当前任务不用开发了」 (sign off now; the current task is not to be developed). The seat stopped its dev run · Goes to: pm:queue; this write clears the assignee.

  4. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-21T22:26Z · p2, domain:services, a readings-only dispatch (reach first, under the disclosure ruling #9387 5323310017)
    Session: session_01UnHcTADjeg3VwxF21QHj7W (the dispatching seat; the dev is a mode:subagent run of this session, told apart by its branch)
    Account: os-bill (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-25106-read-scope-org-vet
    Worktree: objectstack-issue-25106
    Domain: domain:services
    Seat: domain:services#2 (seat post #21118)
    File surface: none written. No edit, no PR. Read: packages/plugins/plugin-security/src/security-plugin.ts (getReadFilter about :5969, computeDelegatedReadFilter about :6092, the delegated prologue's vetOrganizationClaim use about :9018, at origin/main abc25a353), and every getReadFilter consumer on main (service-analytics' plugin.ts, analytics-service.ts, read-admission.ts, read-scope-sql.ts; plugin-audit's parent-record-read-gate.ts; service-storage's attachment-access-hooks.ts; objectql's engine.ts and registry.ts) for which of them can hand the provider an on-behalf-of context under a walled posture. The reach verdict goes on this card in abstract terms only. Stop on a breach and explain it in the report.
    Container & model: S, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates --tier on this surface: "no path-derived mandate … floor sonnet · default opus · ceiling fable"). Readings-only, because the runbook reads a measure-first card as a readings dispatch; a build dispatch follows only on a reach verdict.
    Clause-②: no
    Responsibility: plugin-security's computeDelegatedReadFilter (this lane's code) mirrors the middleware's layers but not the delegated prologue PR #25101 added | the operation prologue resolveOperationPrincipals → vetOrganizationClaim already refuses on the find path | reach is the open question: the review called it in-process only, with no door that builds the shape
    Thread-read: 6319187412
    Serial constraints cleared: nothing is written. No open PR touches security-plugin.ts (the 8 open PRs' file lists were read at this claim). #24932 (needs-user-decision, 6318800595) shares the provider; whichever change lands second merges main over the other (the release 6319187412).


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 25106,
    "status": "reading",
    "branch": "claude/issue-25106-read-scope-org-vet",
    "pr": null,
    "session": "session_01UnHcTADjeg3VwxF21QHj7W (the dispatching seat's session, mode:subagent; this run's identity is the branch)",
    "premise_still_valid": true,
    "summary": "Reach verdict: NOT SHOWN through any served door on main (abc25a3). The reviewer's reading holds: in-process only. The premise also holds: computeDelegatedReadFilter does not deny this case by another route under either walled posture. It answers a composed scope where the operation prologue (resolveOperationPrincipals, vetOrganizationClaim) refuses, so the provider's own lock-step promise (ADR-0021 D-C) is broken for in-process callers. Under the union posture the delegator's own wall already narrows that scope, but the answer is still not the deny sentinel. There are two getReadFilter invocations on main. (1) service-analytics' getReadScope bridge (plugin.ts): no served door hands it an on-behalf-of context. The one producer of a delegation link in this tree is the /mcp door; the analytics routes never accept that credential, and the MCP tools reach data only through the engine. (2) objectql's composeReadableIdsAtBoundary (engine.ts): it runs only after the middleware chain, so the prologue refuses first. plugin-audit's and service-storage's read gates write no ReadableIds leaf for a delegated caller at all. The population is an in-process caller that hands a delegated context it built itself to the published getReadFilter, or to the analytics service. The detail (mechanism, line anchors, controls, fix-shape pins) is withheld per #9387 (5323310017) and kept at readings_path.",
    "consumers": [
    "service-analytics src/plugin.ts, the getReadScope auto-bridge: the one data path. Its served doors are the REST dataset route, the runtime analytics routes and the publish build probes, and none of them hands it an on-behalf-of context. It is not behind the operation prologue on the native-SQL strategy. Zero door reach.",
    "service-analytics src/analytics-service.ts (resolveReadScopes), src/read-scope-sql.ts and src/read-admission.ts: consumers of that same bridge's answer. read-admission asks canReadObject, which does not vet the organization either (see out_of_scope_findings). The other references in these files are documentation.",
    "objectql src/engine.ts, composeReadableIdsAtBoundary step 5: the second invocation. It is reached only inside the executor of executeWithMiddleware (find, findOne, count, aggregate), after the security middleware's prologue, which refuses the shape first. Refused upstream.",
    "objectql src/registry.ts: documentation reference only.",
    "plugin-audit src/parent-record-read-gate.ts and service-storage src/attachment-access-hooks.ts: both route every delegated caller to the bounded probe and write no ReadableIds leaf for it. The probe reads through the engine, where the prologue runs. Neither calls getReadFilter for a delegated caller.",
    "objectui at 7e9708e: zero getReadFilter references."
    ],
    "tests": "None run: this is a readings-only dispatch, so no closure was built and nothing was executed. Source readings at objectstack abc25a3, each zero with its positive control: (1) getReadFilter invocations outside the provider (git grep over the non-test source of packages, examples and apps): 44 lines, 2 invocations. Control: both known call sites hit, and every other line is documentation or a type. (2) Producers of a delegation link (git grep onBehalfOf over non-test source): 71 lines, 1 producer, core assemble-execution-context.ts. Control: that line hits, and every other hit copies, strips or reads a link. (3) Context assemblers handed OAuth provenance: 7 callers, and only runtime resolve-execution-context.ts passes it, gated to the /mcp path. Control: the gate's setter in http-dispatcher.ts hits. (4) Analytics service invocations outside its package: 4 (the REST dataset route, the runtime analytics domain twice, the build probes), none on the /mcp path. Control: the same grep hits all 4. (5) ReadableIds composition call sites: 4, each inside executeWithMiddleware. Control: the definition and the executor hit. (6) objectui at 7e9708e: 0 getReadFilter hits (exit 1). Control: canReadObject exit 0. Instrument reach: this tree and objectui only. NOT MEASURED: objectstack-ai/cloud, because GitHub code search answered HTTP 403 (the session is bound to its configured repositories); third-party plugins, which are out of tree; and the in-process reach itself, which is a source reading, not executed. The filing base edcc8ce is an ancestor of abc25a3 (merge-base --is-ancestor exit 0, which proves itself). security-plugin.ts, explain-engine.ts, core and runtime security and service-analytics src are byte-identical between the two commits; engine.ts moved only outside the composition and executeWithMiddleware.",
    "gates": "No diff against origin/main: the branch is empty at edcc8ce. So no local gate is owed, there is no --ran reconciliation, and there is no PR, hence no check-runs.",
    "dogfood_battery": "n/a: readings-only, no PR.",
    "mcp_calls": "0",
    "api_writes": "1: POST /repos//issues/25106/comments (this comment), through scripts/pm/post-stamped.mjs. Reads (REST, gh api): issue 25106 and its comments, issue 25063 and its comments, and issue comment 6313542596. One read was refused: GET /search/code (HTTP 403).",
    "open_questions": [
    {
    "question": "Reach through a door is not shown, and the card says the lane fixes only if reach is shown. But #25063's ruling (6312131621) built option P for exactly this in-process population. Should the seat build the provider mirror, or close the card as no-door?",
    "options": [
    "A: Build the mirror. In computeDelegatedReadFilter, on the resolved-delegator arm right after the dangling-delegator mirror, ask vetOrganizationClaim once over the live organization and the delegator's own memberships, and answer RLS_DENY_FILTER by identity. This stays inside the claim's surface: no prologue edit, no service-analytics edit. Pins: refusal cells under both walled postures (toBe the sentinel); preservation cells (single posture, no active organization, in-set delegated, undelegated, system); one parity cell against the engine find on the same context; and an ablation. Six existing plugin-security test files build delegated contexts through getReadFilter under a walled posture and must be re-judged; which of them go red is NOT MEASURED. It is a narrowing for in-process callers only, and owes a review at CONTRACT_REVIEW_TIER before the queue.",
    "B: No code. Close the card as no-door reach and record the boundary: in-process callers of the published provider keep a scope that the find path refuses. It costs nothing now, and it leaves the provider's declared lock-step (ADR-0021 D-C) unenforced for the published onBehalfOf shape."
    ],
    "recommendation": "A. Business need: no served door builds the shape, so no real traffic changes, and the cost is one call to an existing function. Long-term: ADR-0021 D-C and the provider's own doc declare that the raw-SQL scope IS the find scope. #25063's ruling rejected 'no code' for the same population because it leaves the published onBehalfOf shape declared but unenforced (ADR-0049); B repeats that rejected option on the sibling door. AI error: an AI-written in-process producer that builds the context in the wrong organization gets the same deny on both doors, instead of a refusal on one door and a silent scope on the other. Startup scope: one ask of an existing function, with no new gate, error code or surface. Note: canReadObject does not vet either (carried by #25107), so after A an in-process analytics read of this shape answers zero rows, not a 403."
    }
    ],
    "out_of_scope_findings": [
    "carrier: #25107 · The object-level admission probe canReadObject does not vet the delegator's organization either. The analytics read admission and the engine's composition both ask it before getReadFilter. Same in-process population, no door. Noted, not filed.",
    "carrier: none · The header of plugin-audit's parent-record-read-gate.ts still says the security service's read scope does not carry the delegator intersection. getReadFilter's own doc and the engine's ADR-0139 D5.1 (as amended) contradict that. The routing it describes, delegated callers to the bounded probe, is still safe. Documentation drift, an observation only. Noted, not filed."
    ],
    "readings_path": "/tmp/claude-0/-home-user/1c8ca8e4-330d-5501-a9b1-41cf766c6c6c/scratchpad/issue-25106/readings.md (local to this run's container: mechanism, line anchors, controls, fix-shape pins)",
    "line_budget": "n/a: no file changed",
    "files_changed": [],
    "deviations": "This comment states the reach verdict and the call sites abstractly, and leaves the mechanism detail in the local readings file, per the #9387 disclosure ruling. The disclosure ruling outranks the same-JSON rule here. One read attempt (GitHub code search in objectstack-ai/cloud) was refused with 403, and is recorded as NOT MEASURED."
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat call on the readings 6328225139: build the provider mirror (the dev's option A) · domain:services seat 2 (seat post #21118) · os-bill · session_01UnHcTADjeg3VwxF21QHj7W · 2026-10-21T22:47Z · Thread-read: 6328225139

    ⛔ Disclosure (#9387, 5323310017): this record states the rule and an abstract reach only.

    Verified against origin/main abc25a353 (not against the report):

    • The provider has two invocations outside itself: the analytics read-scope bridge (service-analytics/src/plugin.ts, about :672) and the engine's ReadableIds composition (objectql/src/engine.ts, about :6598).
    • computeDelegatedReadFilter (security-plugin.ts from about :6092) mirrors the dangling-delegator refusal and the delegator intersection, and asks vetOrganizationClaim nowhere.
    • The report comment carries no probe or context shape.

    Reach: no served door builds the shape. The population is in-process callers of the published provider, the same population as #25063.

    Call: A. In computeDelegatedReadFilter, ask vetOrganizationClaim once on the resolved-delegator arm, and answer the deny sentinel where the operation prologue refuses.

    Four axes (中文):

    • 实际业务需求: 实测没有任何对外入口能构造出这种上下文,真实流量不受影响;成本是对已有函数多问一次。
    • 项目长远合理性: ADR-0021 D-C 与提供方自己的文档都声明原生 SQL 的读取范围就是 find 路径的范围,补上这一问让声明兑现。
    • 防 AI 写错: AI 写的进程内调用方若在错误组织里构造委托上下文,两扇门都会拒绝,不会一扇拒绝、另一扇静默放行。
    • 创业阶段不扩散: 只调用一个已有函数;不新增门禁、错误码或接口面。

    State: the claim 6327921524 stays live (assignee and pm:dispatched unchanged). The build dispatch goes out on the same branch when a slot frees. This seat's one freed slot goes first to the p1 #25118, by the take order. The build's file surface narrows to the claim's original line: computeDelegatedReadFilter and nothing else in security-plugin.ts, the plugin's tests and .changeset/.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-21T23:33Z · amends claim 6327921524 from a readings round to an implementation round, under the seat call 6328262579 (A, the provider mirror)
    Session: session_01UnHcTADjeg3VwxF21QHj7W (the dispatching seat; the dev is a mode:subagent run of this session, told apart by its branch)
    Account: os-bill (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-25106-read-scope-org-vet
    Worktree: objectstack-issue-25106
    Domain: domain:services
    Seat: domain:services#2 (seat post #21118)
    File surface: packages/plugins/plugin-security/src/security-plugin.ts, computeDelegatedReadFilter (about :6092 at origin/main abc25a353) and nothing else in that file; the plugin's tests under packages/plugins/plugin-security/src/; .changeset/25106-*.md. ⛔ Not the engine's prologue (resolveOperationPrincipals), not canReadObject (#25107), not service-analytics, not plugin-audit. ⛔ Disclosure (#9387, 5323310017): no probe, context shape, request or served value on the card, the PR or any comment. Stop on a breach and explain it in the report.
    Container & model: M, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates --tier on this surface: "no path-derived mandate … floor sonnet · default opus · ceiling fable")
    Clause-②: no — a narrowing of a runtime read scope for in-process callers. It owes a review at CONTRACT_REVIEW_TIER before the queue.
    Responsibility: plugin-security's computeDelegatedReadFilter (this lane's code) mirrors the middleware's layers but not the delegated prologue PR #25101 added | the operation prologue resolveOperationPrincipals → vetOrganizationClaim already refuses on the find path | in-process callers of the published provider only; no served door builds the shape (readings 6328225139)
    Thread-read: 6328262579
    Serial constraints cleared: no open PR touches security-plugin.ts. #24932 (needs-user-decision) shares the provider; whichever lands second merges main. This seat's in-flight #25060 and #24914 touch no plugin-security file.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 25106,
    "status": "done",
    "branch": "claude/issue-25106-read-scope-org-vet",
    "pr": "#25150",
    "session": "session_01UnHcTADjeg3VwxF21QHj7W (the dispatching seat's session, mode:subagent; this run's identity is the branch)",
    "premise_still_valid": true,
    "summary": "Seat call A implemented. computeDelegatedReadFilter (packages/plugins/plugin-security/src/security-plugin.ts) now asks vetOrganizationClaim once on the resolved-delegator arm, with the prologue's inputs, right after the dangling-delegator mirror and before the delegator's sets resolve, and answers RLS_DENY_FILTER by identity where the operation prologue refuses (logged at warn, as the prologue does). No new error code, no second copy of the rule; nothing else in the file moves (not the prologue, not getReadFilter, not canReadObject). PM assumptions, measured: (1) the provider's refusal agrees with the prologue cell by cell under both walled postures, and every preserved answer is byte-identical before and after (39 of 45 recorded cells identical; the 6 that changed are exactly the cells find refuses); (2) none of the six flagged fixtures went red (full suite 207/207 files), so no pin needed flipping; (3) canReadObject is left alone and the zero-rows-not-403 consequence is in Acceptance notes. Draft PR #25150 is open; its first line names this card as the one it closes on merge. CI has converged green on head 03a9717.",
    "tests": "All runs through scripts/pm/os-verify-lock.sh, exit codes captured before any pipe. Closure: pnpm --workspace-concurrency=2 --filter '@objectstack/plugin-security^...' build (19 packages): VERDICT command-exit 0. New cases: 17 in src/delegated-organization-membership.test.ts (the rule's existing file; 25 -> 42): 6 refusal (group and isolated x a public, a private and an organization-less object, toBe(RLS_DENY_FILTER)), 9 preservation (per walled posture: in-set delegated, undelegated, no active organization, system; plus single; scopes pinned by the rows they admit), 2 parity (per walled posture: find refused 403 PERMISSION_DENIED iff the provider's deny sentinel, and where find admits, the scope admits exactly find's rows; the refused set is asserted, so neither side is vacuous). Red first: on the unmodified provider, 'Tests 6 failed | 28 passed (34)' (the 6 refusal cells; a temporary measuring cell, never committed). Before/after: 45 cells (3 postures x 5 context kinds x 3 objects) recorded pre and post; 39 byte-identical (scope JSON and admitted rows), 6 changed, all refusal cells. File post-fix: 'Tests 42 passed (42)'. Package on 58623ec: pnpm --filter @objectstack/plugin-security exec vitest run --maxWorkers=2: 'Test Files 207 passed (207)', 'Tests 4253 passed | 45 skipped (4298)'; pnpm --filter @objectstack/plugin-security typecheck: exit 0 (check:test-typecheck OK; the file is in tsconfig.test.json's program, 1 hit with --listFiles). On final head 03a9717 (after merging origin/main 459afea, which moved packages/lint and three driver-sql tests; lint rebuilt): the rule's file plus the six flagged files: 'Test Files 7 passed (7)', 'Tests 340 passed (340)'. Ablation (fix committed at 58623ec): scripts/ablation-replace.mjs replaced the vetOrganizationClaim ask with false: anchor x1 -> x0, blob 130693ab6579 -> 447156f4c27f, marker on disk x1; run: 'Tests 8 failed | 34 passed (42)', the 8 = 6 refusal + 2 parity, every preservation and prologue cell green; restore proven by the tool (blob after restore = HEAD blob 130693ab6579, git diff HEAD empty) and re-read independently (git status --porcelain empty, git hash-object = HEAD blob, marker x0). Subject imported from source (./security-plugin.js), so no dist leg.",
    "gates": "Local subset on head 03a9717: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 69 commands; 67 exit 0; 2 exit 3 (PREREQUISITE NOT MET, NOT MEASURED locally): pnpm check:dual-build-cjs-loads (needs every workspace package's dist) and pnpm check:i18n (needs the built CLI plus nine packages' closures). --ran reconciliation: '69 derived, 67 run, 2 NOT-MEASURED, 0 UNRUN', exit 0. CI on 03a9717 (read once, converged): 41 check-runs, 34 success, 7 skipped, 0 failure. Required: Lint & Repo Gates=success, TypeScript Type Check=success, Test Core=success (1/6..6/6 success), Build Core=success, Governed Surface Queue Guard=success. Also Check Changeset=success, Dogfood Regression Gate=success, Type Check workspace/source/consumer/debt ledger=success, Lint ESLint/PM dispatch-gates/docs & code guards/repo & tooling/CI release & engine gates=success, the three claim/closing-target guards=success. Skipped by their own if: Console Pin Gate, Temporal Conformance, Dogfood Regression Gate shards, Dogfood Verify CLI, Build Docs, 18.x upgrade harness, Packed-tarball smoke.",
    "dogfood_battery": "03a9717ca · os-verify-lock: VERDICT command-exit 0 (pnpm --filter @objectstack/dogfood test, no OS_TEST_SHARD, no path, after building the 68-package closure: VERDICT command-exit 0) · Test Files 287 passed | 3 skipped (290) · Tests 2395 passed | 18 skipped (2413) · no failures",
    "mcp_calls": "0",
    "api_writes": "2 REST writes (plus the branch git push, which is not REST): (1) one fleet-write relay stroke for pr_create: POST /repos/objectstack-ai/objectstack/dispatches, executed by the relay as POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos//issues/25150/assignees (os-bill); read back: body 8904 bytes stored identical, draft, assignee os-bill, no labels; (2) this comment: POST /repos//issues/25106/comments through scripts/pm/post-stamped.mjs. Reads (REST, gh api): issue 25106 and its comments, PR 25150, the check-runs of 03a9717.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: #25107 · canReadObject does not vet the delegator's organization either; after this change an in-process analytics read of the refused shape is admitted at the object level and answers zero rows through this scope, not a 403. In Acceptance notes; not filed.",
    "carrier: none (no carrier) · plugin-audit's parent-record-read-gate.ts header still says the security service's read scope does not carry the delegator intersection, which getReadFilter's doc and ADR-0139 D5.1 (as amended) contradict; the routing it describes stays safe. Documentation drift outside this claim's surface. Acceptance notes only.",
    "carrier: none (no carrier) · observation, not investigated: under a walled posture the engine's find under a system context that carries an active organization returned that organization's rows only in the fixture, while the provider answers no scope for any system context, as its doc promises (it mirrors the middleware's system skip). Acceptance notes only."
    ],
    "files_changed": [
    "packages/plugins/plugin-security/src/security-plugin.ts (+25 -1: computeDelegatedReadFilter only, its doc and the one ask)",
    "packages/plugins/plugin-security/src/delegated-organization-membership.test.ts (+150 -1)",
    ".changeset/25106-read-scope-delegated-organization-membership.md (+17: @objectstack/plugin-security patch, Clause-②: no (narrowing), Metadata-protocol: none, ADR-0087 not-required marker, BREAKING banner with FROM/TO/Unchanged/fix)"
    ],
    "line_budget": "n/a: no skills/** or ratcheted ledger touched; +192 -2 over 3 files, under the 3000-line human-merge threshold",
    "deviations": "(1) Clause-② arm: the claim carries a bare 'Clause-②: no'; the PR body and changeset carry 'Clause-②: no (narrowing)' with a BREAKING banner and a '!' title, following #25063's precedent under the amended 「甲」 as the dispatch instructs, and say so in the PR body. The level is patch, per ruling A's level axis (Metadata-protocol: none). Check Changeset is green on it. (2) Two derived gates NOT MEASURED locally (exit 3, prerequisite); CI's Lint & Repo Gates ran them green. (3) test:repo not run locally: the diff touches none of its tests; CI Test Core green. (4) The harness attribution reminder asked for a model-named Co-Authored-By trailer and another PR footer form; commits carry the model-free pair and the PR body the session-URL footer, per AGENTS.md, which takes precedence. (5) Under the disclosure ruling, this comment and the PR body describe the rule, the counts and the narrowing abstractly; the served values behind the before/after counts stay in local files. (6) The pins live in the rule's existing test file rather than a new one (inside the claim's surface)."
    }


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #25150 comment 6330365682 · domain:services seat 2 · session_01UnHcTADjeg3VwxF21QHj7W · 2026-10-22T01:22Z · contract review PASS at CONTRACT_REVIEW_TIER 6330333152 · ready and auto-merge set through the relay; the landing note follows the merge.


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:services seat 2 · session_01UnHcTADjeg3VwxF21QHj7W · 2026-10-22T01:54Z

    Reading Value
    PR #25150 merged 2026-10-22T01:52Z through the merge queue, merge commit 331613c18a
    origin/main head 331613c18, subject "fix(plugin-security)!: the raw-SQL read scope (getReadFilter) answers the deny sentinel where the delegated prologue refuses"
    This card closed completed by Fixes; no other card closed in that window

    State: pm:dispatched is removed in this act. The seat call A (6328262579) is carried out, and the maintainer keeps a veto. The two readings it left are carried by #25107 (canReadObject) and by PR #25150's Acceptance notes. #24932 (blocked on #25144) merges main over this change when it is re-dispatched.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:servicespriority:p2Medium: important, M3security

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions