Repository navigation
ADR-0139 E7 (comments): sys_comment gains a writer-stamped object_name + record_id pair with a backfill, and the comment-thread read gate emits one ReadableIds leaf per parent object over it (ruling on #23732, batch #354 item 2) #23857
Description
Filing gate: ④ a ruled execution card — the ruling on #23732 (batch #354 item 2, letter A on Q1, the maintainer's 「同意」; its comment id is the first line of that card's body), filed by the director seat (summon #43, session_01QJC7i981TSs9L1CGJK59Ax). ⛔ Not a claim. Facts were read at objectstack origin/main 3fed1eb00a.
Carries the comment-thread half of ADR-0139's execution-plan row E7. The attachment half landed as PR #23767 (0b1179f332, Part of #23732); the reaction gate stays on the bounded probe by D5.2 (Q2 of the same ruling). #23732 is pm:blocked on this card and closes completed when this card lands.
The work (ADR-0139 D3, D4, D5; ADR-0052 §5)
- The pair.
sys_comment(packages/plugins/plugin-audit/src/objects/sys-comment.object.ts) gainsobject_nameandrecord_id, writer-stamped fromthread_id({object}:{record_id}) on create and on the re-point rule, read-only to authors, indexed.thread_idstays the authored key: no ADR-0087 conversion, and no writer changes (objectui'sRecordDetailViewkeeps writingthread_id). - The backfill. One idempotent stored-row migration under the
os migratedoor, in the shape E6 landed (ADR-0139 E6: sys_activity gains a writer-stamped changed_fields column with an idempotent backfill, and the withheld-update rule becomes a predicate with no SYSTEM pre-scan (D4) #23731 → PR feat(plugin-audit): sys_activity gains writer-stamped read-rule columns with an idempotent backfill, and the withheld-row rule is a predicate with no SYSTEM pre-scan (ADR-0139 E6) #23814,5b6c257b06: a writer-stamped column plus a backfill). The changeset's first paragraph names the door and the rollout consequence, as ADR-0139 E6: sys_activity gains a writer-stamped changed_fields column with an idempotent backfill, and the withheld-update rule becomes a predicate with no SYSTEM pre-scan (D4) #23731's did. A row the backfill has not reached keeps the bounded probe (fail closed), never a leaf. - The gate.
installCommentReadVisibility(packages/plugins/plugin-audit/src/comment-access-hooks.ts) emits oneReadableIdsleaf per registered parent object,{ object_name: P, record_id: { $in: ReadableIds.of(P) } }, ANDed into the read'swhere, with no pre-scan and no caller-scoped parent read. D5's three classes keep the bounded fail-closed probe by name (a delegated caller; a parent narrowed by an object-scoped read middleware; a federated parent), chosen up front, ⛔ never reached by catching a refusal. No leaf withoutcanReadObject(E5's guard). The consumer does not catch the composition refusal into a deny-all sentinel (D3). - Reactions. The reaction gate (
sys_comment_reaction, parentsys_comment) keeps the probe: D5.2 namessys_comment(docs/adr/0139-engine-internal-semi-join-leaf-readable-parent-ids.md:212). Recorded here as D5.2's class with the reading of 2026-10-16: member 1,763 of 2,300; administratortotal2,000 of 2,601. No code.
Pins
- A member with more than 2,000 readable candidate comments is served every visible comment, and
countequals the rows served — the plan row's bound case, measured before and after as E5 and the attachment half were (today: member 1,765 of 2,300; administratortotal2,000 of 2,601, the dev's scratch reading on ADR-0139 E7: the comment-thread, comment-reaction and attachment read gates emit one ReadableIds leaf per parent object and do no pre-scan; D5's three classes keep the probe (D4, D5) #23732). - An unreadable parent's comments stay hidden.
- Each D5 class keeps the probe at the gate.
- A row the backfill has not reached is probed, not leafed.
- A reaction read is unchanged (D5.2).
Notes carried
- From 6206614195 on ADR-0139 E7: the comment-thread, comment-reaction and attachment read gates emit one ReadableIds leaf per parent object and do no pre-scan; D5's three classes keep the probe (D4, D5) #23732: the checklist item
attachments-storage.read-inherits-parent-rlsshould also name the gate's two whole-read probe states (nocanReadObjector no security service; an engine that cannot classify), and the 500's driver name is in the log, not the response body. The comments item's revision in this card carries the same two points. - From the E5 and attachment reports: plugin-security's
explainanswers a SYSTEM contextallowed: falsewhilecanReadObjectanswers true, so the gate writes no leaf withoutcanReadObject. Ondriver-mongodbthe switched gate fails 500 (O3, a ruled consequence of ADR-0139 D3). - The D5 classification now exists twice beside the engine's (
planParentReads,planAttachmentParentReads); its carrier is ADR-0139 execution: the engine-internal semi-join leaf across spec, engine, drivers and consumers (E0–E7 coordination) #22788 (domain:engine), not this card.
Governing text
ADR-0139 header (「A is the end state」, :16), D3, D4 (:177-187), D5 (:201-214); ADR-0052 §5 (:208, the object_name / record_id pair); ADR-0112 (the refusal envelope); the ruling on #23732 named above.
Dedupe
MCP search_issues on this repo, closed included, for "sys_comment pointer pair object_name record_id backfill comment-thread read gate ReadableIds leaf": 10 hits; the nearest are #23732 (the parent decision, now pm:blocked on this card), #23673 (E5, closed), #22861 (E2, closed) and #4630 (the sys_comment record-level gate, closed). None carries the comment pointer pair. Dedupe words: ADR-0139 E7 comment thread pointer pair object_name record_id backfill; installCommentReadVisibility ReadableIds leaf no pre-scan; sys_comment thread_id writer-stamped.
Activity
objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 6 · 2026-10-16T09:31Z
Session:
session_018VqJPGA1NDNSCZsnecsChP(the dispatching seat; the dev runs as a cloud session that seat post #21118 names)Account:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-23857-comment-parent-pairWorktree:
objectstack-issue-23857(in the cloud session's container)Domain:
domain:servicesSeat:
domain:services#2(seat post #21118)File surface (at
origin/maina31ff2eb5dor later; stop on a breach and explain it in the report):packages/plugins/plugin-audit/src/:objects/sys-comment.object.ts(the pair);comment-access-hooks.ts(the gate and its stamping hook, or one new module beside it); one backfill module besidestored-metadata-body-migration.ts, exported fromsrc/index.ts; their tests;packages/qa/dogfood/test/;os migratedoor underpackages/cli/src/commands/migrate/, with its test and its family registrations (thedomain:clihalf, declared to seat [PM seat] domain:cli — 🟢 os-sales · session_01BVm1pAXVXQ3PjC42j1kPFf · serial, p1/p2 + #24022 (maintainer) #6024 in this act, as E6's was);minorchangeset;Exclusions:
writeAuditinaudit-writers.ts: Audit log: sys_user_preference writes are not audit events #23804 is in flight there. If the stamping hook must register inaudit-writers.ts, then only thesys_commenthook region (near:2180-2310), declared in the report; the later lander mergesmain.packages/spec/**,packages/objectql,packages/coreor any driver.parent-record-read-gate.ts(ADR-0139 execution: the engine-internal semi-join leaf across spec, engine, drivers and consumers (E0–E7 coordination) #22788's).packages/cli/src/commands/migrate/organization-ownership*(PR fix(driver-turso,cli): the v18 organization-ownership ceremony runs on a Turso remote database #23843 is open on them).RecordDetailViewkeeps writingthread_id.Container & model:
L (~500–900 lines, 1–2 PRs by the ruling's column; a real-engine read gate, a backfill and a door, measured on the dogfood stack),mode:cloud,model: opus(TIER_DEFAULT;dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate")Clause-②: yes — two columns on the published platform object
sys_comment, an exported backfill, and a new CLI door widen the published surface. The face is the declaration (nopackages/spec/src/**path), so aTIER_DEFAULTcontract review of record is owed before the queue. This seat orders it.Responsibility:
plugin-audit (this lane): the comment-thread read gate serves every visible comment, with count equal to the rows served, via one ReadableIds leaf per parent object | none: E7's attachment half landed as PR #23767; reactions stay on the probe by D5.2 | #23732 closes completed when this lands; ADR-0139's execution epic #22788Thread-read: none
Ruling-ref: #23732 ruling
6212058353(batch #354 item 2, letter A on Q1, A on Q2, maintainer 「同意」 2026-10-16T09:06Z). Precedents: E6 #23731 → PR #23814 (5b6c257b06) and E5 PR #23693.Serial constraints cleared: no open PR touches
comment-access-hooks.ts,sys-comment.object.tsor the backfill modules (all open PRs' file lists read at this write). #23804 (this seat, in flight) is onaudit-writers.tswriteAudit, which this card does not touch.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 23857, "status": "done", "branch": "claude/issue-23857-comment-parent-pair", "pr": "https://github.com/objectstack-ai/objectstack/pull/23881", "session": "session_01NX4Woa8XhvMs6xpqQpx8kK (this cloud run's Claude-Session line)", "premise_still_valid": true, "summary": "sys_comment gains readonly, indexed object_name + record_id, derived from thread_id by one planner (planCommentParentPair, the parse every comment gate authorizes by). They are stamped for every caller on create, over any value sent, and re-stamped on an update naming thread_id (the re-point rule). A non-system update's own pair is dropped by the engine's readonly strip (measured). installCommentReadVisibility now runs E5's computeParentRecordFilter, imported and not edited, so no third D5 copy exists. It runs over the pair: one ReadableIds leaf per registered object other than sys_comment; D5's classes and the two whole-read states get the bounded probe up front; no leaf is written without canReadObject. Rows with no stamped pair get the old thread probe, ORed in and restricted to object_name IS NULL (probed, never leafed). next() is outside the try (D3). The reaction gate is unchanged (D5.2). backfillCommentParentPair, exported, and its door os migrate comment-parent-pair (E6's shape, 3 family registrations) stamp stored rows under preserveAudit, so updated_at is kept (measured). Bound case before -> after: real engine member 1,766 -> 2,303 of 2,303, administrator total 2,000 -> 2,605; real SecurityPlugin + AuditPlugin dogfood stack, member 981 -> 2,050 of 2,050. Reaction reading recorded on the card as D5.2's class (member 1,763 of 2,300; administrator total 2,000 of 2,601), no code.", "tests": "At head e499adaf6 (origin/main 34b740f2d merged), shared box, under os-verify-lock. pnpm --filter @objectstack/plugin-audit test: 53 files / 863 passed. plugin-audit typecheck exit 0 (test-typecheck OK). @objectstack/cli unit project: 301 files / 4,496 passed; cli typecheck exit 0. CLI integration (the diff touches it): comment-parent-pair + data-commands.absent-database + schema-migrate.one-shot-family 147/147; json-stdout-purity.e2e (OS_TEST_TIERS=nightly) 62/62 (run before the main merge, at the CLI-door commit). Dogfood typecheck exit 0. Dogfood, 9 files / 79 passed: comment-thread-parent-pair (new) + 7 sys_comment suites + activity-withheld-row-predicate. Readings: E7-COMMENT-READING after {rowsAtRest 2607, memberServed 2303 of 2303, memberTotal 2303, adminTotal 2605 of 2605}; E7-DOGFOOD-READING after {visible 2050, served 2050, totals [2050]}. ABLATIONS through scripts/ablation-replace.mjs, each restored 'blob == HEAD' with git diff HEAD empty. Unless noted, the pins are comment-thread-leaf.test.ts + comment-parent-pair.integration.test.ts on src. A0: main's whole-read thread probe, src 7/17 red (before reading member 1766/2303, adminTotal 2000/2605). A0 dogfood leg: OS_SKIP_DTS rebuild, ablation-dist-preflight marker A0-BEFORE present exit 0, 4/5 red (member served 981 of 2050). Restore rebuild exit 0, --absent exit 0. A1 stamped branch admits all: 11 red. A2 unstamped not probed: 5. A3 probe branch loses the IS NULL conjunct: 2. A4 leaf without canReadObject: 1. A5 consumer catches the refusal: 2. A6 stamp keeps the writer's pair: 7. A7 re-point not re-stamped: 2. A8b D5.2 parent leafed (temporary planParentReads mutation): 9. A9 delegated leafed: 2. A10b refused backfill read not counted: 1. A11 a thread naming no record stamped: 7. Void legs: the first A0 (the replacement contained the anchor; refused, nothing landed); first A8 and A10 (the replacement already occurred; refused); A4, A5 and A9 rerun after a test-only stand-in restructure, same reds.", "gates": "LOCAL: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at e499adaf6 derives 103 commands (23 paths vs merge base 34b740f2d, 2,276 changed lines, under 3,000). All 103 exit 0, each captured before any pipe. --ran: 'Run reconciliation — 103 derived, 103 run, 0 NOT-MEASURED, 0 UNRUN.' and '103 run, 0 NOT-MEASURED (a DERIVED zero — all 103 recorded an exit code and none of them is 3)'. The first union (at e34c95d5) had 7 non-zero, none in the final record. check-tenant-audit-census and its --self-test exit 1: prose figures 226 vs 227, fixed by hand. check:engine-double-contract and check:objectql-double-limit exit 1, both on my unit stand-in: an unneeded findOne, and a find the limit gate could not judge; restructured, no ledger touched. Three exit 3 (PREREQUISITE NOT MET): check:skill-examples and check:dual-build-cjs-loads (dist missing, re-run after a full build) and check-plugin-teardown-shape --self-test (a shallow clone, re-run after fetching 621a487607). Also local: pnpm check:adr-symbol-anchors exit 0 ('2348 anchors across 142 records resolve'), check:adr-anchors 0, check:nul-bytes 0. CI on PR #23881 at e499adaf6 when this report was written: 24 check-runs, 1 success, 1 skipped, 22 in_progress. Not awaited, per the contract.", "mcp_calls": "1 — mcp__claude-code-remote__subscribe_pr_activity on #23881 (the cloud harness's post-PR default; not a GitHub write). 0 MCP GitHub calls.", "api_writes": "2. (1) pr_create through the fleet-write relay (scripts/pm/fleet-write/dispatch.mjs, transport dispatch): POST /repos/objectstack-ai/objectstack/dispatches (204). Run 38892815365 executed it as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/23881/assignees ([os-elon-musk]). Read-back: 11,056 bytes sent, 11,056 stored, identical. (2) This report: POST /repos/objectstack-ai/objectstack/issues/23857/comments via scripts/pm/post-stamped.mjs. label-write: 0 (outside the dispatch's budget). git push: the empty branch probe, then each step (not a REST write). Reads: gh api GETs of #23857 and its comments, #23732 and its comments, contract record 6209058891, PR #23814's files, and #23881's check-runs.", "open_questions": [ { "question": "Which objects are the comment gate's parents? Comments can hang off any record (enforceFeedsCapability allows any object whose feeds are not off, and the console writes thread_id from every record detail page), but enumerateParentObjects excludes AUDIT_EXCLUDED_OBJECTS unless a gate names them.", "options": [ "A: name every AUDIT_EXCLUDED_OBJECTS entry as a namedParent, so the gate enumerates every registered object but sys_comment, exactly the set parseCommentThreadId accepts (taken)", "B: keep the audit exclusion, which would hide comments on sys_session, sys_job and the like that the old probe served" ], "recommendation": "A, taken. Real need: it preserves every comment the old gate served. Long-term: one parent set, the parse's. AI-safety: no silent narrowing. Startup focus: no new surface. The cost is ~25 more leaf branches per unpinned read; a refused object is answered $in: [] by canReadObject, with no read." }, { "question": "The card asks that 'the comments item's revision' carry the two checklist notes, but no platform-checklist item covers comment read inheritance (records-forms.json's comment items are about feeds and posting).", "options": [ "A: revise only attachments-storage.read-inherits-parent-rls (revision 5) and record the absence (taken)", "B: author a new comments read-inheritance item, which is checklist-author's work" ], "recommendation": "A, taken. A new item is a new surface, not a revision; the seat can route B to a checklist-author sweep if wanted." } ], "out_of_scope_findings": [ "carrier: #22788 (domain:engine) · noted, not filed · parent-record-read-gate.ts#WHOLE_READ_PROBE_WHY['no-object-admission'] still cites 'the SYSTEM re-read of this WHERE that the withheld-update rule makes'. E6 removed that re-read, and the comment gate now prints this sentence too, once per engine, when no canReadObject is composed. Prose only; the behaviour is right. Dedupe words: no-object-admission warning stale withheld-update re-read; WHOLE_READ_PROBE_WHY parent-record-read-gate" ], "line_budget": "2,276 changed lines (+2,226 / -50) over 23 files, generated files included (dispatch-gates' count at e499adaf6). Under the 3,000 human-merge threshold, so no 维护者速读 section. Over the ruling's 500–900 estimate: about 1,300 lines are tests (two plugin-audit suites, the dogfood pin, the CLI door suite) and about 190 are the CLI door.", "deviations": "1) File surface: docs/qa/platform-checklist/areas/attachments-storage.json (the carried notes, which the ruling's item 6 rides on this card) and content/docs/permissions/tenant-audit-census.mdx + docs/audits/2026-08-tenant-audit-write-call-sites.counts.md (the census, regenerated, plus 7 hand-written prose figures 226 -> 227) and content/docs/deployment/cli.mdx + docs/qa/platform-checklist/areas/cli.json (the door rows). All are docs or gate-regenerated, as in E6's landing. 2) The stamping hook and the gate live in comment-access-hooks.ts, not in a new module; the backfill is its own module. audit-writers.ts is untouched; comment-access-hooks.ts imports its AUDIT_EXCLUDED_OBJECTS. 3) parent-record-read-gate.ts is imported (computeParentRecordFilter), not edited and not copied: no third D5 classification. Ablations A8b and A9 mutated it temporarily, restored and proven blob == HEAD. 4) The first dogfood fixture (two threads) passed under A0 because the old probe bounds distinct threads, not rows. It was rebuilt with one comment per record, and A0 then turned it red; the first fixture's green is not counted as evidence. 5) A bundled lock call with ';' parts got VERDICT batch-last-exit 0; each part's own exit (AUDIT 0, AUDITTC 0, CLIUNIT 0, CLITC 0) was echoed and is quoted instead. 6) One rm of packages/runtime/.objectstack after the main merge was refused by a harness safety check and not run; the suites run here do not read it. 7) json-stdout-purity.e2e was run before the main merge, at the CLI-door commit; the merge brought no CLI file it reads besides organization-ownership. 8) The primary checkout was detached so the branch could live in the worktree objectstack-issue-23857. 9) The harness reminder's model-named Co-Authored-By trailer was not used; the commits carry AGENTS.md's model-free pair. 10) One MCP call (subscribe_pr_activity), see mcp_calls.", "files_changed": [ ".changeset/23857-comment-parent-pair.md", "content/docs/deployment/cli.mdx", "content/docs/permissions/tenant-audit-census.mdx", "docs/audits/2026-08-tenant-audit-write-call-sites.counts.md", "docs/qa/platform-checklist/areas/attachments-storage.json", "docs/qa/platform-checklist/areas/cli.json", "packages/cli/src/commands/migrate/comment-parent-pair.ts", "packages/cli/src/commands/migrate/comment-parent-pair.integration.test.ts", "packages/cli/src/commands/migrate/data-commands.absent-database.integration.test.ts", "packages/cli/src/utils/schema-migrate.one-shot-family.integration.test.ts", "packages/cli/test/json-stdout-purity.e2e.test.ts", "packages/plugins/plugin-audit/src/audit-plugin.ts", "packages/plugins/plugin-audit/src/comment-access-hooks.ts", "packages/plugins/plugin-audit/src/comment-parent-pair-backfill.ts", "packages/plugins/plugin-audit/src/comment-parent-pair.integration.test.ts", "packages/plugins/plugin-audit/src/comment-thread-leaf.test.ts", "packages/plugins/plugin-audit/src/index.ts", "packages/plugins/plugin-audit/src/objects/sys-comment.object.ts", "packages/plugins/plugin-audit/src/translations/en.objects.generated.ts", "packages/plugins/plugin-audit/src/translations/es-ES.objects.generated.ts", "packages/plugins/plugin-audit/src/translations/ja-JP.objects.generated.ts", "packages/plugins/plugin-audit/src/translations/zh-CN.objects.generated.ts", "packages/qa/dogfood/test/comment-thread-parent-pair.dogfood.test.ts" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 23857, "addendum_to": 6214364566, "round": "patch, on contract record 6215049807 (FAIL at e499adaf6)", "status": "done", "pr": "https://github.com/objectstack-ai/objectstack/pull/23881", "head": "32b6f5300", "branch": "claude/issue-23857-comment-parent-pair", "session": "session_01NX4Woa8XhvMs6xpqQpx8kK", "summary": "FAIL reason 1 is cured, and observation (a) is cured by the same change. The sys_comment beforeUpdate stamp now runs for every caller whenever an update names thread_id, object_name or record_id. Naming thread_id: stamped from it, as before. Naming the pair without a thread: re-derived from the row's stored thread (ctx.previous.thread_id) by planCommentParentPair. No stored row to derive from: both keys are dropped from the write. So no writer's pair lands under preserveAudit, where the engine's update-side strip keeps a readonly value. The backfill's SYSTEM write of the pair is re-derived from the row's thread as it stands at write time, which closes the read-then-write race in (a). A predicate update naming the pair over rows with different threads is refused whole by the engine (MULTI_UPDATE_HOOK_KEY_DIVERGENCE), as one SET clause cannot carry two pairs. The prose is now true of the fix: the object docblock, the hook docblock, the backfill docblock and the changeset's third paragraph. Observation (b): the changeset names the first parameter's widening to ParentRecordGateEngine and both types it brings into reach. Observation (c): the door's docblock now names activity-changed-fields' flags. Observation (d): app-scale cost is not measured, unchanged.", "reproduction": "The pin was written first and run at the FAIL head's code. A member's update {object_name: e7_vault, record_id: VAULT} with context {...MEMBER_A, preserveAudit: true} stored object_name e7_vault and record_id of the vault, where the thread's pair was expected (vitest diff: expected e7_doc, received e7_vault). With the fix it reads back the thread's pair, and so does a record_id-only update.", "tests": "At 32b6f5300, under os-verify-lock. plugin-audit build, then test: 53 files / 864 passed; typecheck exit 0. Dogfood (plugin-audit through dist, rebuilt in the same lock call): 9 files / 79 passed, with E7-DOGFOOD-READING {visible 2050, served 2050, totals [2050]}; dogfood typecheck exit 0. CLI integration: comment-parent-pair + data-commands.absent-database + schema-migrate.one-shot-family 147/147. New pins: integration 'the re-point rule re-stamps the pair; a member's own pair is never written' gains two preserveAudit updates (the pair, then record_id alone); unit 'update: a pair named without a thread is re-derived from the stored thread, or dropped when there is none'. Fixtures that plant unstamped rows now write below the engine (driver.update), as a pre-upgrade row exists, because every engine write of the pair is now re-derived. The dogfood pin restores those rows through the engine and asserts the re-derived pair. ABLATIONS through scripts/ablation-replace.mjs, restored 'blob == HEAD (2e9d279ddcaa)' with git diff HEAD empty: A12 (the update stamp ignores a pair named without a thread) turned 2 red, the unit pin and the preserveAudit integration pin; A13 (no stored thread keeps the writer's pair) turned 1 red.", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 32b6f5300: 103 commands, 23 paths, 2,340 changed lines (+2,290 / -50), under 3,000. All 103 exit 0, each captured before any pipe. --ran: 'Run reconciliation — 103 derived, 103 run, 0 NOT-MEASURED, 0 UNRUN.' with a DERIVED zero. The first record of this round listed 4 UNRUN: the runner's shell was moved to the background mid-run, so check:type-check-debt, check:vendor-version-stamps, check:watch-hint-literal and check:where-matcher had no exit code. Run then, each exit 0, and reconciled to 103/103. pnpm check:adr-symbol-anchors exit 0. CI on the new head not read or awaited.", "pr_body_for_the_seat": "The PR body's 'Who can write the pair' bullet 3 ('A non-system update that names the pair without a thread: the engine's update-side stripReadonlyFields drops it. Measured on a real engine.') is false at 32b6f5300. Suggested replacement: 'An update that names either column without a thread: the update stamp re-derives the pair from the row's stored thread, for every caller (under preserveAudit the engine's strip keeps a readonly value), and drops it when there is no stored row. Pinned, ablated A12/A13.' The Ablations table gains rows A12 (2 red) and A13 (1 red). The dev does not PATCH the body.", "mcp_calls": "0 this round.", "api_writes": "1, this comment: POST /repos/objectstack-ai/objectstack/issues/23857/comments via scripts/pm/post-stamped.mjs. git push: one commit (32b6f5300). Reads: gh api GET of the contract record 6215049807 and of #23881's check-runs.", "deviations": "None beyond the 4 first-pass UNRUN gates above, which are recorded and re-run." }Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
ACCEPT → PR #23881 comment 6218283155 ·
domain:servicesseat 2 ·session_018VqJPGA1NDNSCZsnecsChP· 2026-10-16T15:00Z. Landing through the merge queue.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landed ·
domain:servicesseat 2 (#21118) ·os-elon-musk·session_018VqJPGA1NDNSCZsnecsChP· 2026-10-16T15:42Z.Landed: PR #23881 (
Fixes #23857) merged through the merge queue as67e8792ff4. That commit is onorigin/main(git merge-base --is-ancestor). Timeline:added_to_merge_queue2026-10-16T15:03Z →merged2026-10-16T15:26Z. ACCEPT6218283155, after contract records6215049807FAIL,6216478197FAIL and6218239397PASS.origin/mainobjects/sys-comment.object.ts: the pairobject_name:163,record_id:172comment-access-hooks.ts: the multi-row divergence refusalrefusePairDivergence, 3 hitscomment-access-hooks.ts: the gate composes overparent-record-read-gate.tscomputeParentRecordFilterimported (:121)packages/cli/src/commands/migrate/comment-parent-pair.tsand its integration test, presentWhat it changes, measured by the dev at the landed head:
totalreads 2,605 of 2,605; before, 2,000.nulluntilos migrate comment-parent-pair --applystamps them. Until then the gate answers them with the bounded probe, failing closed.Closure: #23732 closes
completedin this act, per ruling6212058353item 6. E7's row is now complete: attachments by PR #23767 (0b1179f332), comments by this PR, reactions recorded under D5.2. The staleWHOLE_READ_PROBE_WHY['no-object-admission']prose goes to carrier #22788 by a pointer in this act.pm:dispatchedis cleared, the assignee is released, and the dev session is archived in this act.Generated by Claude Code