You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
security(approvals): a lookup target's title in the approvals inbox (payload_display) is read under the system context without asking whether the reader may read that target record (row-level, sharing), unlike $expand and dataset labels; measure first #23637
Filing gate ①, the possible-data-leak exception: measure reachability first.
What is read
plugin-approvals' enrichRows titles each lookup target in a request's payload snapshot (payload_display). It reads the target record under the system context.
Ruling C keeps the approval doors serving the subject's FLS-redacted snapshot to a routed approver, whatever their access to the subject record. payload-redaction.ts's header (#10749) says the same: the seam "does not gate on OBJECT-level access" to "the object under approval".
Both speak about the SUBJECT. A lookup target is a different record, and its title is server-resolved text the snapshot never stored. PR #23629's contract record (6187371379) judged this a separate question from #23618, not a gap in it.
Asked of the dispatched reader (domain:services seat, one dev)
Measure first: booted, on main, with the real SecurityPlugin. Use a routed approver who may read the target object's display field but not the target ROW (one row-level or sharing class is enough). Does getRequest or listRequests serve that row's title in payload_display?
If it does: narrow the title by the reader's access to the target row, through the door the platform already has for that question. ⛔ Do not add a second rule; degrade as a deleted target does (no display value; the stored id stands).
If the fix needs a reading of ruling C (whether approval routing implies sight of referenced records), stop and return it as a fork. ⛔ Widening is the maintainer's.
reach: not yet measured (point 1 is the measurement). Function level only; ⛔ no reproduction recipe on this card.
Dedupe: MCP search_issues, this repo, open and closed, with two queries: approval inbox payload_display lookup target title served to approver who cannot read the referenced record row-level sharing, and referenced record title disclosure row-level security lookup expand system context approvals. 32 hits each. Positive control #23618 came back first. The nearest are #22738 (closed: exposure only, its text names no caller access) and #22661 (closed: the data and dataset doors). Neither names the caller's row access for this read.
Source: PR #23629's Acceptance notes, as the dev for #23618 noted it (6187170508).
It never asks whether the reader may read that target row (object read, sharing, row-level rules).
The two sibling doors that title a lookup target both do:
the dataset door's label pass is row-scope filtered;
$expand reads under the caller's context.
Grade: p2 + security, measure first. It is a possible disclosure of a single title past row-level security, to a routed approver (an authenticated member), read from source and not measured.
The stop condition: if point 1 measures it served, the dev records the measurement, this card goes to p1, and the round continues to the fix. The fix is the card's point 2: narrow through the platform's existing row-access door, and degrade as a deleted target does.
Claim: PM loop round 3 · 2026-10-15T11:03Z
Session: session_017WLmd5in9RXu7AjyHR8fKQ
Account: os-bill (the seat's linked user as GET /user answers it; the card's assignee from this act)
Branch: claude/issue-23637-lookup-target-row-access
Worktree: objectstack-issue-23637
Domain: domain:services
Seat: domain:services#1 (seat post #6021)
File surface: packages/plugins/plugin-approvals/src/approval-service.ts (enrichRows → titlesAsServed, the lookup-target title read), with its tests; one changeset .changeset/23637-*.md. ⛔ Not packages/core (resolveReadableParentIds may be CALLED, not changed), and not plugin-audit / plugin-security, which #23279 holds. Stop on breach; explain in the report.
Container & model: M, mode:subagent, model: default tier (dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate"). Measure first. If it measures served, narrowing a served field owes one CONTRACT_REVIEW_TIER review before the queue, as for #23594 and #23618.
Clause-②: no
Responsibility: plugin-approvals (this lane): enrichRows titles each payload_display lookup target from a system-context read, asking the target's exposure (#22738) and, since PR #23629, the reader's field-level security, but not the reader's access to the target row | the data door's $expand and the dataset door's labels judge the caller's row access | a routed approver reading the inbox or a request detail; read from source, not measured
Thread-read: 6188373141
Serial constraints cleared: no open PR touches packages/plugins/plugin-approvals/** or packages/core/src/security/** (all 7 open PRs' file lists read at this write). PR #23629 (#23618) landed on enrichRows as b513343ac1. This seat's other card in flight, #23279, holds plugin-audit's parent-record gate: the files are disjoint, but a reader-context read of a target the reader cannot read meets the same denial log #23279 works on. That interplay is a measurement for the report, ⛔ never a reason to mute a log.
os-dev-report
{
"issue": 23637,
"status": "done",
"branch": "claude/issue-23637-lookup-target-row-access",
"pr": "#23672",
"session": "session_017WLmd5in9RXu7AjyHR8fKQ - the parent's id (mode:subagent); the claim's Session line, the relay envelope's session and the commits' Claude-Session trailer agree",
"premise_still_valid": true,
"summary": "SERVED, measured: booted on main 286eb9e with the real SecurityPlugin composed, a routed approver who may read the target object's display field was served a lookup target's title in payload_display on getRequest and listRequests for two denial classes (a row hidden by a row-level rule on an object the reader may read; no object-level read on the target object), while the data door showed neither record. Per triage 6188373141 this card goes to p1 and the round continued to the fix. Fix in plugin-approvals only: after the exposure gate, enrichRows asks (1) the security service's canReadObject once per target object (reader's envelope minus operation-private keys; fail closed on a throw or a non-true answer; absent service or member = left to step 2), as the coordinator offered mid-task in the shape of PR #23663, then (2) resolveReadableParentIds from @objectstack/core once per admitted target object per read, as the reader, and titles only the readable ids with the unchanged read and FLS pick (titlesAsServed). An unreadable target gets no display value and the stored id stands, as a deleted target does. The subject's record_title, label and snapshot are unchanged. ApprovalsServicePlugin wires the admission from the registered security service, resolved lazily. Re-measured with the real SecurityPlugin: both titles withheld, a readable row keeps its title; WARN denial lines per inbox read: 1 without the admission wired, 0 with it. No ruling-C reading was needed: what ruling C gives an approver is unchanged and nothing is granted. Draft PR #23672, assignee os-bill. A CONTRACT_REVIEW_TIER review is owed before the queue (claim).",
"tests": "Red before, the first five pins on base 286eb9e before the fix existed: 3 failed / 2 passed = (a), (a-row), (c) red; (b), (d) green, as predicted. New pin file lookup-target-title-row-access.integration.test.ts: 8 tests green at 9e88df4. Package suite pnpm --filter @objectstack/plugin-approvals exec vitest run --maxWorkers=2: 78 files / 1080 tests passed at 9e88df4, lock VERDICT command-exit 0 (later commits: changeset text and two origin/main merges touching .claude/** and scripts/pm/** only). pnpm --filter @objectstack/plugin-approvals typecheck: exit 0; check:test-typecheck held at 8 files / 324 errors / 27 signatures; tsc --listFiles on tsconfig.test.json compiles both edited test files, 0 errors in them. eslint --no-inline-config over the 4 changed TS files: exit 0. Ablations at 9e88df4 via scripts/ablation-replace.mjs wrap mode under an EXIT/INT/TERM restore trap, 8 tests each, red set predicted first: A old behaviour 6 failed / 2 passed = (a),(a-row),(c),(e),(e-closed),(f); B admission ignored 3 failed / 5 passed = (e),(e-closed),(f); C one ask per id 2 failed / 6 passed = (c),(e); D plugin wiring call deleted 1 failed / 7 passed = (f). All four as predicted; restores proven by blob equal to HEAD (0e12be2ed246 for A-C, ffdaebd5269e for D) and empty git diff HEAD. No dist step: subjects imported from src by relative path. Real-SecurityPlugin measurement: a throwaway rig, never committed (see deviations).",
"gates": "Local, derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 9aed095: 67 commands; all 67 run sequentially under os-verify-lock, each exit captured before any pipe. 65 exit 0 on the first run; check:dual-build-cjs-loads and check:i18n first answered 3 PREREQUISITE NOT MET (no workspace dist), then 0 after a workspace build (turbo build, 75 tasks, 64 cached, exit 0). check:type-check-debt's first attempt was cut by my batch wrapper's timeout (not a measurement), re-run to completion: exit 0 (1 ledger entry re-measured, no surplus). Re-derived at 37573fb after the second origin/main merge: the same 67. --ran: 67 derived, 67 run, 0 NOT-MEASURED (a derived zero), 0 UNRUN, exit 0. Ratchet and census families (12) re-run on 37573fb: all exit 0. UNRECOGNISED lines, verbatim: UNRECOGNISED [engine-double-contract]: 22 construct(s) in packages, examples declare a scanned verb (delete, update, findOne) alongside engine siblings, and this gate could not read the implementation -- so they are in NEITHER the pinned population nor the ledger. 225 further construct(s) are SCOPED OUT by a stated criterion and are not counted here. This is a verdict, not a finding: it never fails a run (#9747, ruling of 2026-08-18). (This diff adds no engine double.) Local-only families check:dev-prereqs and check:skill-frame-freshness: not owed (no packages/spec build input or frame file touched). PR #23672 check-runs on 37573fb at one read, no waiting: 23 total; 1 success (No other open PR may claim the same issue), 1 skipped (Packed-tarball smoke, opt-in), 21 in_progress (Check Changeset, Check Documentation Links, Check PR Size, Flag docs affected by code changes, Governed Surface Queue Guard, the 8 Lint families, both claim and single-writer guards, Part-of guard, the 4 Type Check families, filter). None failed at the read; Build Core and Test Core not yet listed.",
"mcp_calls": "0 - no MCP GitHub call of any kind; reads went through gh api (single-card, comment, PR and check-run REST reads)",
"api_writes": "2 relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml as objectstack-fleet[bot]. (1) pr_create, run 38732553536: POST /repos/objectstack-ai/objectstack/pulls (draft) plus POST /repos//issues/23672/assignees [os-bill]; read-back 10406 bytes sent, 10406 stored, identical. (2) this os-dev-report comment: POST /repos//issues/23637/comments. Label step: zero writes (the dispatch named no label; skip-changeset does not apply, a changeset ships). Not REST: 5 git pushes of the branch (empty probe, fix, admission, changeset edit, merge head 37573fb).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none - noted, not filed (PR #23672 Acceptance notes only): submitter_name and pending_approver_names are still read under the system context; they are the approval's own participants, part of the inbox entry ruling C gives an approver, not referenced records. Dedupe words: approval participant names system context; submitter_name approver names read access.",
"carrier: none - noted, not filed (PR #23672 Acceptance notes only): a lookup pointing at the request's own subject record now follows the reader's row access to that record while record_title is served regardless; same title, no disclosure. Dedupe words: self-lookup subject payload_display; record_title payload_display parity."
],
"deviations": [
"File surface beyond the claim's approval-service.ts and its tests: packages/plugins/plugin-approvals/src/approvals-plugin.ts, one wiring call handing the service the registered security service's canReadObject (the coordinator's mid-task offer); without it the admission is dead in the composed runtime. Named in the PR body. Nothing in plugin-security, plugin-audit or packages/core changed.",
"Throwaway measurement: one test file in packages/plugins/plugin-approvals/src imported plugin-security's source by relative path (read-only) to compose the real SecurityPlugin; run three times (before, after without the admission, after with it) and deleted; never committed or pushed; the tree was verified clean.",
"Push order: after the empty-branch probe, the pins and the fix went up together in the first content push, so nothing red reached the remote (the card's security rule).",
"Gates were run under os-verify-lock as the dispatch ordered, although check:* gates normally run outside it; one batch wrapper timeout cut check:type-check-debt's first attempt, which was then re-run to completion in the background (PID recorded, log read): exit 0.",
"Two merges of origin/main (1ced0f8, 881eeff; .claude/** and scripts/pm/** only) before opening the PR, because dispatch-gates reported a stale tree; the package suite was not re-run after them (no package input changed).",
"Attribution: commits carry the repository's model-free trailer pair and the PR body ends with the repository's session-URL footer, rather than the harness reminder's model-named trailer and footer (AGENTS.md wins; the pre-push hook refuses a model id)."
],
"line_budget": "not applicable: no skills/** or ledgered line-budget surface touched; no governed surface. The diff is +592/-11 over 5 files, under the 3000-line human-merge threshold.",
"files_changed": [
".changeset/23637-lookup-target-title-row-access.md",
"packages/plugins/plugin-approvals/src/approval-service.ts",
"packages/plugins/plugin-approvals/src/approvals-plugin.ts",
"packages/plugins/plugin-approvals/src/implicit-reference-target-lookup.test.ts",
"packages/plugins/plugin-approvals/src/lookup-target-title-row-access.integration.test.ts"
]
}
Regrade on triage's stated stop condition · domain:services seat 1 · os-bill · session_017WLmd5in9RXu7AjyHR8fKQ · 2026-10-15T12:14Z. priority:p2 → priority:p1 in this act.
The condition, verbatim from triage 6188373141: "if point 1 measures it served, the dev records the measurement, this card goes to p1, and the round continues to the fix."
The measurement (dev report on this card; PR fix(plugin-approvals): a payload_display lookup target is titled only for a target record the reader may read #23672, function level): booted on main286eb9ef32 with the real SecurityPlugin. A routed approver was served a lookup target's title in payload_display on getRequest and listRequests for two classes: a target row hidden by a row-level rule on an object the reader may read, and a target object the reader has no object-level read on. The data door showed the reader neither record. Served.
ACCEPT → PR #23672 comment 6191993021 · domain:services seat 1 · session_017WLmd5in9RXu7AjyHR8fKQ · 2026-10-15T12:25Z. The contract-tier record 6191970854 is PASS on head 37573fbd67. Landing waits on every check green.
added_to_merge_queue 2026-10-15T12:33Z by the fleet relay → merged 2026-10-15T12:51Z
origin/main by content
7e6e4e1da6. approval-service.ts holds private async admittedTargetObjects (1 hit), and approvals-plugin.ts wires attachObjectReadAdmission (1 hit). lookup-target-title-row-access.integration.test.ts and .changeset/23637-lookup-target-title-row-access.md are present
State change: the card was closed completed by Fixes #23637. This write clears pm:dispatched and the assignee. security, priority:p1 (triage's pre-ruled regrade, 6191803622), domain:services and the type labels stay.
Residuals carried (contract record 6191970854, ACCEPT 6191993021):
The approval-path title family is closed on this row:
Activity
objectstack-fleet commentedon Oct 15, 2026
Triage: first grade ·
bug·security·priority:p2·domain:services·pm:queue· measure first · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-15T08:58ZRead fresh.
plugin-approvals'enrichRowstitles each lookup target inpayload_displayunder the system context.$expandreads under the caller's context.Grade: p2 +
security, measure first. It is a possible disclosure of a single title past row-level security, to a routed approver (an authenticated member), read from source and not measured.Lane
domain:services(plugin-approvals, by the lane table).Order: none. PR #23629 (#23618), which edited the same
enrichRowstitle pick, merged at 08:54Z (b513343ac1). Start from amainthat carries it.Function level only on this card, as filed.
objectstack-fleet commentedon Oct 15, 2026
Claim: PM loop round 3 · 2026-10-15T11:03Z
Session:
session_017WLmd5in9RXu7AjyHR8fKQAccount:
os-bill(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-23637-lookup-target-row-accessWorktree:
objectstack-issue-23637Domain:
domain:servicesSeat:
domain:services#1(seat post #6021)File surface:
packages/plugins/plugin-approvals/src/approval-service.ts(enrichRows→titlesAsServed, the lookup-target title read), with its tests; one changeset.changeset/23637-*.md. ⛔ Notpackages/core(resolveReadableParentIdsmay be CALLED, not changed), and notplugin-audit/plugin-security, which #23279 holds. Stop on breach; explain in the report.Container & model:
M,mode:subagent,model: default tier(dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate"). Measure first. If it measures served, narrowing a served field owes oneCONTRACT_REVIEW_TIERreview before the queue, as for #23594 and #23618.Clause-②: no
Responsibility:
plugin-approvals (this lane): enrichRows titles each payload_display lookup target from a system-context read, asking the target's exposure (#22738) and, since PR #23629, the reader's field-level security, but not the reader's access to the target row | the data door's $expand and the dataset door's labels judge the caller's row access | a routed approver reading the inbox or a request detail; read from source, not measuredThread-read: 6188373141
Serial constraints cleared: no open PR touches
packages/plugins/plugin-approvals/**orpackages/core/src/security/**(all 7 open PRs' file lists read at this write). PR #23629 (#23618) landed onenrichRowsasb513343ac1. This seat's other card in flight, #23279, holdsplugin-audit's parent-record gate: the files are disjoint, but a reader-context read of a target the reader cannot read meets the same denial log #23279 works on. That interplay is a measurement for the report, ⛔ never a reason to mute a log.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{
"issue": 23637,
"status": "done",
"branch": "claude/issue-23637-lookup-target-row-access",
"pr": "#23672",
"session": "session_017WLmd5in9RXu7AjyHR8fKQ - the parent's id (mode:subagent); the claim's Session line, the relay envelope's session and the commits' Claude-Session trailer agree",
"premise_still_valid": true,
"summary": "SERVED, measured: booted on main 286eb9e with the real SecurityPlugin composed, a routed approver who may read the target object's display field was served a lookup target's title in payload_display on getRequest and listRequests for two denial classes (a row hidden by a row-level rule on an object the reader may read; no object-level read on the target object), while the data door showed neither record. Per triage 6188373141 this card goes to p1 and the round continued to the fix. Fix in plugin-approvals only: after the exposure gate, enrichRows asks (1) the security service's canReadObject once per target object (reader's envelope minus operation-private keys; fail closed on a throw or a non-true answer; absent service or member = left to step 2), as the coordinator offered mid-task in the shape of PR #23663, then (2) resolveReadableParentIds from @objectstack/core once per admitted target object per read, as the reader, and titles only the readable ids with the unchanged read and FLS pick (titlesAsServed). An unreadable target gets no display value and the stored id stands, as a deleted target does. The subject's record_title, label and snapshot are unchanged. ApprovalsServicePlugin wires the admission from the registered security service, resolved lazily. Re-measured with the real SecurityPlugin: both titles withheld, a readable row keeps its title; WARN denial lines per inbox read: 1 without the admission wired, 0 with it. No ruling-C reading was needed: what ruling C gives an approver is unchanged and nothing is granted. Draft PR #23672, assignee os-bill. A CONTRACT_REVIEW_TIER review is owed before the queue (claim).",
"tests": "Red before, the first five pins on base 286eb9e before the fix existed: 3 failed / 2 passed = (a), (a-row), (c) red; (b), (d) green, as predicted. New pin file lookup-target-title-row-access.integration.test.ts: 8 tests green at 9e88df4. Package suite pnpm --filter @objectstack/plugin-approvals exec vitest run --maxWorkers=2: 78 files / 1080 tests passed at 9e88df4, lock VERDICT command-exit 0 (later commits: changeset text and two origin/main merges touching .claude/** and scripts/pm/** only). pnpm --filter @objectstack/plugin-approvals typecheck: exit 0; check:test-typecheck held at 8 files / 324 errors / 27 signatures; tsc --listFiles on tsconfig.test.json compiles both edited test files, 0 errors in them. eslint --no-inline-config over the 4 changed TS files: exit 0. Ablations at 9e88df4 via scripts/ablation-replace.mjs wrap mode under an EXIT/INT/TERM restore trap, 8 tests each, red set predicted first: A old behaviour 6 failed / 2 passed = (a),(a-row),(c),(e),(e-closed),(f); B admission ignored 3 failed / 5 passed = (e),(e-closed),(f); C one ask per id 2 failed / 6 passed = (c),(e); D plugin wiring call deleted 1 failed / 7 passed = (f). All four as predicted; restores proven by blob equal to HEAD (0e12be2ed246 for A-C, ffdaebd5269e for D) and empty git diff HEAD. No dist step: subjects imported from src by relative path. Real-SecurityPlugin measurement: a throwaway rig, never committed (see deviations).",
"gates": "Local, derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 9aed095: 67 commands; all 67 run sequentially under os-verify-lock, each exit captured before any pipe. 65 exit 0 on the first run; check:dual-build-cjs-loads and check:i18n first answered 3 PREREQUISITE NOT MET (no workspace dist), then 0 after a workspace build (turbo build, 75 tasks, 64 cached, exit 0). check:type-check-debt's first attempt was cut by my batch wrapper's timeout (not a measurement), re-run to completion: exit 0 (1 ledger entry re-measured, no surplus). Re-derived at 37573fb after the second origin/main merge: the same 67. --ran: 67 derived, 67 run, 0 NOT-MEASURED (a derived zero), 0 UNRUN, exit 0. Ratchet and census families (12) re-run on 37573fb: all exit 0. UNRECOGNISED lines, verbatim: UNRECOGNISED [engine-double-contract]: 22 construct(s) in packages, examples declare a scanned verb (delete, update, findOne) alongside engine siblings, and this gate could not read the implementation -- so they are in NEITHER the pinned population nor the ledger. 225 further construct(s) are SCOPED OUT by a stated criterion and are not counted here. This is a verdict, not a finding: it never fails a run (#9747, ruling of 2026-08-18). (This diff adds no engine double.) Local-only families check:dev-prereqs and check:skill-frame-freshness: not owed (no packages/spec build input or frame file touched). PR #23672 check-runs on 37573fb at one read, no waiting: 23 total; 1 success (No other open PR may claim the same issue), 1 skipped (Packed-tarball smoke, opt-in), 21 in_progress (Check Changeset, Check Documentation Links, Check PR Size, Flag docs affected by code changes, Governed Surface Queue Guard, the 8 Lint families, both claim and single-writer guards, Part-of guard, the 4 Type Check families, filter). None failed at the read; Build Core and Test Core not yet listed.",
"mcp_calls": "0 - no MCP GitHub call of any kind; reads went through gh api (single-card, comment, PR and check-run REST reads)",
"api_writes": "2 relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml as objectstack-fleet[bot]. (1) pr_create, run 38732553536: POST /repos/objectstack-ai/objectstack/pulls (draft) plus POST /repos//issues/23672/assignees [os-bill]; read-back 10406 bytes sent, 10406 stored, identical. (2) this os-dev-report comment: POST /repos//issues/23637/comments. Label step: zero writes (the dispatch named no label; skip-changeset does not apply, a changeset ships). Not REST: 5 git pushes of the branch (empty probe, fix, admission, changeset edit, merge head 37573fb).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none - noted, not filed (PR #23672 Acceptance notes only): submitter_name and pending_approver_names are still read under the system context; they are the approval's own participants, part of the inbox entry ruling C gives an approver, not referenced records. Dedupe words: approval participant names system context; submitter_name approver names read access.",
"carrier: none - noted, not filed (PR #23672 Acceptance notes only): a lookup pointing at the request's own subject record now follows the reader's row access to that record while record_title is served regardless; same title, no disclosure. Dedupe words: self-lookup subject payload_display; record_title payload_display parity."
],
"deviations": [
"File surface beyond the claim's approval-service.ts and its tests: packages/plugins/plugin-approvals/src/approvals-plugin.ts, one wiring call handing the service the registered security service's canReadObject (the coordinator's mid-task offer); without it the admission is dead in the composed runtime. Named in the PR body. Nothing in plugin-security, plugin-audit or packages/core changed.",
"Throwaway measurement: one test file in packages/plugins/plugin-approvals/src imported plugin-security's source by relative path (read-only) to compose the real SecurityPlugin; run three times (before, after without the admission, after with it) and deleted; never committed or pushed; the tree was verified clean.",
"Push order: after the empty-branch probe, the pins and the fix went up together in the first content push, so nothing red reached the remote (the card's security rule).",
"Gates were run under os-verify-lock as the dispatch ordered, although check:* gates normally run outside it; one batch wrapper timeout cut check:type-check-debt's first attempt, which was then re-run to completion in the background (PID recorded, log read): exit 0.",
"Two merges of origin/main (1ced0f8, 881eeff; .claude/** and scripts/pm/** only) before opening the PR, because dispatch-gates reported a stale tree; the package suite was not re-run after them (no package input changed).",
"Attribution: commits carry the repository's model-free trailer pair and the PR body ends with the repository's session-URL footer, rather than the harness reminder's model-named trailer and footer (AGENTS.md wins; the pre-push hook refuses a model id)."
],
"line_budget": "not applicable: no skills/** or ledgered line-budget surface touched; no governed surface. The diff is +592/-11 over 5 files, under the 3000-line human-merge threshold.",
"files_changed": [
".changeset/23637-lookup-target-title-row-access.md",
"packages/plugins/plugin-approvals/src/approval-service.ts",
"packages/plugins/plugin-approvals/src/approvals-plugin.ts",
"packages/plugins/plugin-approvals/src/implicit-reference-target-lookup.test.ts",
"packages/plugins/plugin-approvals/src/lookup-target-title-row-access.integration.test.ts"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Regrade on triage's stated stop condition ·
domain:servicesseat 1 ·os-bill·session_017WLmd5in9RXu7AjyHR8fKQ· 2026-10-15T12:14Z.priority:p2→priority:p1in this act.6188373141: "if point 1 measures it served, the dev records the measurement, this card goes to p1, and the round continues to the fix."main286eb9ef32with the realSecurityPlugin. A routed approver was served a lookup target's title inpayload_displayongetRequestandlistRequestsfor two classes: a target row hidden by a row-level rule on an object the reader may read, and a target object the reader has no object-level read on. The data door showed the reader neither record. Served.CONTRACT_REVIEW_TIERreview is owed before the queue, per the claim.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
ACCEPT → PR #23672 comment 6191993021 ·
domain:servicesseat 1 ·session_017WLmd5in9RXu7AjyHR8fKQ· 2026-10-15T12:25Z. The contract-tier record6191970854is PASS on head37573fbd67. Landing waits on every check green.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Landing note ·
domain:servicesseat 1 ·os-bill·session_017WLmd5in9RXu7AjyHR8fKQ· 2026-10-15T12:52ZFixes #23637)added_to_merge_queue2026-10-15T12:33Z by the fleet relay →merged2026-10-15T12:51Zorigin/mainby content7e6e4e1da6.approval-service.tsholdsprivate async admittedTargetObjects(1 hit), andapprovals-plugin.tswiresattachObjectReadAdmission(1 hit).lookup-target-title-row-access.integration.test.tsand.changeset/23637-lookup-target-title-row-access.mdare presentState change: the card was closed
completedbyFixes #23637. This write clearspm:dispatchedand the assignee.security,priority:p1(triage's pre-ruled regrade,6191803622),domain:servicesand the type labels stay.Residuals carried (contract record
6191970854, ACCEPT6191993021):submitter_name,pending_approver_names) stay as the inbox entry's own content under ruling C. They are not filed.Generated by Claude Code