Skip to content

Comment reactions (ruling A amended on #22505): a reaction is the reactor's own sys_comment_reaction record, and sys_comment.reactions retires with no aggregate and no data migration #22566

Closed

Description

@objectstack-fleet

Filing gate ③: a task the maintainer directed. On #22505, the maintainer ruled A with two amendments (director record 6091550406), verbatim: 「同意;sys_comment.reactions 可以退役;可以不用考虑历史数据迁移;」. The maintainer then delegated the aggregate question (6091621568), verbatim: 「sys_comment.reactions 是否需要只读汇总 你综合判断。」. The director judged it: no aggregate. Filed by domain:services seat 1 (seat post #6021, session_013j5gkUCpqQiti4GgPqqmnt); the record's State line hands this seat the platform card. #22500, the defect, closes on the PRs that execute it.

Reader: triage first, for the lane. The record declares Clause-②: yes for the new object: it widens plugin-audit's published surface. Under the clause-② dispatch rule, that makes it spec-lane work, even though the files sit in domain:services packages (plugin-audit, plugin-security). The claimant declares those files to the domain:services seat post (#6021).

The ruling, executed (premises read on origin/main 6a3f82efa7)

  1. A new object sys_comment_reaction (the comment, the emoji, the user), owned by the reactor.
    • A member adds or removes their own reaction on any comment they can read, under the platform's ordinary own-record rule.
    • ⛔ The author-only update floor on sys_comment is not touched (plugin-security, default-permission-sets.ts:1164; sys_comment_moderation alternate at :1217).
    • Two members reacting at once write two rows, so the whole-column overwrite and its lost updates are gone by construction.
  2. Its permission-set rows: create, read, and delete-own (the record's Execution line).
  3. sys_comment.reactions retires (plugin-audit/src/objects/sys-comment.object.ts:125, a JSON textarea on the comment's row).
    • Nothing takes its place on the comment row: no stored aggregate, no computed-on-read block (6091621568).
    • The retirement carries the retirement discipline's own records: a retired-keys or D3 semantic entry, whichever the field's declaration shape requires. That is governance, not data migration.
  4. No migration of stored reactions. Existing reactions are not converted and disappear with the column. The changeset says so plainly: after the upgrade, existing emoji reactions are gone.

Open for the claimant to measure (not ruled)

  • Read: which read rule lets a reaction be read exactly when its comment can be read. Measure whether the comment's own read gate (plugin-audit's comment-access-hooks.ts) or the parent-record gate applies, and reuse it. ⛔ No copy of a readability rule.
  • Uniqueness: whether (comment, emoji, user) is one row, and how a second identical reaction is refused or treated as a no-op.
  • Consumers of the retired column: a census. The director found objectui's chatter as the only reader (6091621568); cloud has none. packages/spec/src/ui/component.zod.ts's enableReactions (feed prop) is a different surface and stays out unless the census says otherwise.
  • The pinned objectui (.objectui-sha) still writes the column until its chatter card lands. Measure what the data door answers that write once the field is retired. Land in an order that leaves no window where a member's reaction click fails worse than today (AGENTS.md Post-Task Checklist step 4: a removal the pinned sibling depends on ships with the sibling fix and the pin bump).

The objectui half

objectui's chatter writes and reads reaction records and stops writing the column. It does one batched find on sys_comment_reaction for the feed's comment ids and groups client-side into the Record<string, string[]> shape CommentThread already renders (6091621568). That card lives in objectstack-ai/objectui; this session has no write channel there, so it is asked of triage on #22505.

Dedupe: MCP search_issues, this repo, sys_comment_reaction reactor own record comment reactions retire sys_comment.reactions → 5 hits (#22500, #22505, #20558, #4756, #4630; the last three closed, on other questions). objectui, chatter reaction records objectui comment reaction write path → 2 hits (objectui#11019 and objectui#11035, both closed, other defects). None is this card.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, enhancement · priority:p2 · domain:services · area:records · pm:queue. Scope: the additive half; the retirement moves to #22573

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-10T02:04Z. ⛔ Not a claim, ⛔ not a dispatch. This answers 6092101588 item 1 on #22505.

  2. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-10T02:26Z
    Session: session_013j5gkUCpqQiti4GgPqqmnt
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-22566-comment-reaction-record
    Worktree: objectstack-issue-22566
    Domain: domain:services
    Seat: domain:services#1 (seat post #6021)
    Ruling-ref: 6091550406 (and the delegated judgment 6091621568), both on #22505, read in this act. Scope per triage 6092508551: the additive half. The retirement of sys_comment.reactions is #22573.
    File surface, read on origin/main 25be87612d:


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22566,
    "status": "needs_decision",
    "branch": "claude/issue-22566-comment-reaction-record",
    "pr": "#22603",
    "session": "session_013j5gkUCpqQiti4GgPqqmnt (subagent: the parent's harness-stamped id; CLAUDE_CODE_REMOTE_SESSION_ID cse_013j5gkUCpqQiti4GgPqqmnt)",
    "premise_still_valid": true,
    "summary": "Built the additive half on draft PR #22603 (head 32c30d8, line 1 'Part of #22566', line 2 'Clause-②: yes'). It adds sys_comment_reaction (comment_id id column, emoji, user_id; apiMethods get/list/create/delete; unique (comment_id, emoji, user_id) scoped 'organization'), registered and provisioned beside sys_comment. Read rule: the comment gate's existing installers answer for the reaction with one handler per seam. A reaction is narrowed to comment_id $in the comments resolveReadableParentIds says the caller can read, which is one caller-scoped read of sys_comment that runs its grant, row scope and thread gate, so no readability rule is copied. Create rule: the same evaluator, plus user_id stamped from the session. Delete: the shipped owner_only_deletes floor (created_by), pinned with no new code. Uniqueness: the declared index; a duplicate is DUPLICATE_RECORD 409 at the engine and 409 UNIQUE_VIOLATION at the door, with no new code. Mechanism hypothesis 2 is FALSIFIED: default-permission-sets.ts :1164-:1218 holds only the sys_comment_moderation delete alternate. The platform ships no sys_comment create or read bit, so apps grant them (hotcrm#2043), and ADR-0090 D5 forbids allowDelete on member_default, the only set every member resolves. So the card's 'permission-set rows (create, read, delete-own)' cannot be built as the card words them; see open_questions. Census: objectui's RecordDetailView.tsx is the only reader and writer of sys_comment.reactions, at main d758f2f20d and at the pin 47b1f0bb71. objectstack has no runtime reader. enableReactions is a different surface. cloud is NOT MEASURED. sys_comment.reactions, the author-only floor, packages/spec, objectui and content/docs are untouched.",
    "tests": "plugin-audit: comment-reaction-access.integration.test.ts (real kernel, real ObjectQLPlugin, real SQLite, AuditPlugin) 21/21, and sys-comment-reaction.object.test.ts 8/8. The full suite is 44 files, 701 passed; typecheck exit 0, with the test layer compiled and both new files in the program per --listFilesOnly. plugin-security: comment-reaction-own-record-floor.test.ts (real SecurityPlugin with the shipped member_default, real engine and driver) 3/3, and default-permission-sets.test.ts gains a tripwire. The full suite is 194 files, 4079 passed, 45 skipped; typecheck exit 0. Gates: 76/76 derived families exited 0 at 32c30d8 (list in 'gates'). Ablations, each through scripts/ablation-replace.mjs with the anchor hit 1 to 0, the blob changed, a trap restore, and the restore proven as blob == HEAD with git diff HEAD empty; run at 8361ea8 and again at 32c30d8. A1, the owner_only_deletes object '*' made a nonexistent object: floor test 2 red / 1 green, since another member's delete then answers ok. A2, the reaction read middleware's registration deleted: 9 red / 12 green. A3, the reaction insert hook's registration deleted (8361ea8 only): setup red, VALIDATION_FAILED user_id required, 21 skipped. A3b, the readability check short-circuited: 3 red / 18 green. A4, the app grant's allowDelete set false: 2 red / 1 green, so the first pin rests on the grant. Every direction is a turn to red. No dist/ is on any ablated path: the subjects resolve from the package's own src, so no rebuild leg applies.",
    "mcp_calls": "0",
    "api_writes": "3 relay writes, each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving #22603 as a draft (run 38022228506); (2) label-write --assign zhuangjianguo, POST /repos//issues/22603/assignees (run 38022264312); (3) this os-dev-report comment, POST /repos//issues/22566/comments. git push is not a REST write and is not counted.",
    "open_questions": [
    {
    "question": "Where do sys_comment_reaction's object bits come from? The card and the ruling's Execution line ask for 'permission-set rows (create, read, delete-own)'. member_default is the only shipped set every member resolves, and ADR-0090 D5 hard-blocks allowDelete there: describeHighPrivilegeBits would flag 'delete/purge/transfer on sys_comment_reaction', bindBaselineToEveryone would refuse to bind the whole baseline, and audience-anchor-set-claims.pin.test.ts pins it anchor-safe. The platform also ships no create or read bit on sys_comment itself; apps grant those (hotcrm#2043). The delete-own half needs no row, because owner_only_deletes already keeps a delete to the reactor (pinned).",
    "options": [
    "A: member_default grants sys_comment_reaction read+create (anchor-safe); delete stays app-granted. Cost: two lines and pins. On an app that grants no delete, a member can add a reaction and never remove it, and the chatter's toggle-off answers 403 there.",
    "B: no platform grant (PR #22603 as it stands). An app grants read, create and delete on sys_comment_reaction wherever it grants sys_comment; the floor keeps delete to the reactor. Cost: one object line per comment-granting app set. A missing grant fails loudly (403) on the first add and remove alike. The card's 'rows' then live in the app's set.",
    "C: amend ADR-0090 D5 to admit an owner-scoped delete bit on an everyone-bound set, then grant all three in member_default. Cost: a Tier H ADR, a packages/spec predicate change (Clause-② narrowing or widening of the anchor contract), the lint rule and the boot refusal; it widens a hard-blocked class (ADR-0056, no silent loosening)."
    ],
    "recommendation": "B, on the four axes. Actual business need: the one measured consumer, hotcrm, already grants sys_comment per app set (hotcrm#2043), so adding the reaction line beside it is the same act. The showcase and CRM grant members nothing on sys_comment, so a baseline reaction grant (A) would serve no member who can read a comment. Long-term soundness: B keeps ADR-0090 D5 intact and keeps one source for who may use comments (the app's set), instead of splitting it between the baseline (create/read) and the app (delete). Preventing AI mistakes: B is all-or-nothing, and a missing grant is a loud 403 on first use. A ships the trap where adding works and removing silently does not. C loosens a hard-blocked bit class an AI author would then copy. Startup focus: B adds nothing to the baseline and needs no ADR; A adds a baseline grant with no pull, and C is the largest. If B is taken, PR #22603 needs no code change: the seat rewrites its line 1 to close the card. If A is taken, a follow-up adds two member_default lines plus pins. If C is taken, the ADR goes first."
    }
    ],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted, not filed — comment-access-hooks.ts header paragraph 1 still says the default member sets 'grant wildcard CRUD with no row scoping' (stale since #5491); prose drift, no reach; in the PR's Acceptance notes",
    "carrier: 承接者:无 · noted, not filed — content/docs/permissions/system-context.mdx row 45 describes the comment hooks without naming reactions; anchors and counts still hold (check:system-context-census green); docs-only, outside this claim (no content/docs); in Acceptance notes",
    "carrier: PR #22526 (holds audit-writers.ts) · noted, not filed — sys_audit_log still records every reaction create and delete (the ledger is always on; activities:false stops only the sys_activity mirror); SKIP_OBJECTS is the knob if volume matters; in Acceptance notes"
    ],
    "gates": [
    "node scripts/check-adr-0087-registration.mjs --base origin/main -> exit 0",
    "node scripts/check-adr-0087-registration.mjs --self-test -> exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main -> exit 0",
    "node scripts/check-changeset-no-major.mjs --self-test -> exit 0",
    "node scripts/check-ci-filter-parity.mjs -> exit 0",
    "node scripts/check-closing-keyword-parity.mjs -> exit 0",
    "node scripts/check-closing-keyword-parity.mjs --self-test -> exit 0",
    "node scripts/check-comment-mask-adoption.mjs -> exit 0",
    "node scripts/check-comment-mask-adoption.mjs --self-test -> exit 0",
    "node scripts/check-comment-mask-corpus.mjs -> exit 0",
    "node scripts/check-dts-emitted.mjs --self-test -> exit 0",
    "node scripts/check-empty-changeset.mjs --base origin/main -> exit 0",
    "node scripts/check-empty-changeset.mjs --self-test -> exit 0",
    "node scripts/check-issue-citations.mjs -> exit 0",
    "node scripts/check-keyed-text-bounds.mjs -> exit 0",
    "node scripts/check-keyed-text-bounds.mjs --self-test -> exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs -> exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs --self-test -> exit 0",
    "node scripts/check-plugin-teardown-shape.mjs -> exit 0",
    "node scripts/check-plugin-teardown-shape.mjs --self-test -> exit 0",
    "node scripts/check-registry-log-declared.mjs -> exit 0",
    "node scripts/check-registry-log-declared.mjs --self-test -> exit 0",
    "node scripts/check-rest-log-spy-declared.mjs -> exit 0",
    "node scripts/check-rest-log-spy-declared.mjs --self-test -> exit 0",
    "node scripts/check-scripts-symbol-anchors.mjs -> exit 0",
    "node scripts/check-scripts-symbol-anchors.mjs --self-test -> exit 0",
    "node scripts/check-system-context-census.mjs -> exit 0",
    "node scripts/check-system-context-census.mjs --self-test -> exit 0",
    "node scripts/check-tenant-audit-census.mjs -> exit 0",
    "node scripts/check-tenant-audit-census.mjs --self-test -> exit 0",
    "node scripts/check-undeclared-dep-imports.mjs -> exit 0",
    "node scripts/check-undeclared-dep-imports.mjs --self-test -> exit 0",
    "node scripts/docs-audit/check-affected-docs.mjs -> exit 0",
    "node scripts/docs-audit/check-drift-comment.mjs -> exit 0",
    "node scripts/pm/release-rehearsal-clone.mjs --self-test -> exit 0",
    "node scripts/release-pending-publish.mjs --self-test -> exit 0",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys -> exit 0",
    "pnpm check:agent-test-spelling -> exit 0",
    "pnpm check:bash32-floor -> exit 0",
    "pnpm check:changeset-gate-self-tests -> exit 0",
    "pnpm check:cli-command-ids -> exit 0",
    "pnpm check:cross-package-test-inputs -> exit 0",
    "pnpm check:dispatcher-error-vocabulary -> exit 0",
    "pnpm check:doc-authoring -> exit 0",
    "pnpm check:driver-memory-census -> exit 0",
    "pnpm check:dts-closure -> exit 0",
    "pnpm check:dual-build-cjs-loads -> exit 0",
    "pnpm check:engine-double-contract -> exit 0",
    "pnpm check:entry-guard -> exit 0",
    "pnpm check:error-status-conformance -> exit 0",
    "pnpm check:gitlink-declared -> exit 0",
    "pnpm check:i18n -> exit 0",
    "pnpm check:i18n-stale-fill -> exit 0",
    "pnpm check:issue-citations -> exit 0",
    "pnpm check:lean-entry-closure -> exit 0",
    "pnpm check:logger-receiver-detach -> exit 0",
    "pnpm check:merge-driver -> exit 0",
    "pnpm check:nul-bytes -> exit 0",
    "pnpm check:objectql-double-limit -> exit 0",
    "pnpm check:objectui-changeset -> exit 0",
    "pnpm check:org-identifier -> exit 0",
    "pnpm check:page-declaration-shape -> exit 0",
    "pnpm check:parse-guard -> exit 0",
    "pnpm check:pm-changeset-deadline-census -> exit 0",
    "pnpm check:pnpm-filter-targets -> exit 0",
    "pnpm check:published-files -> exit 0",
    "pnpm check:query-options-erasure -> exit 0",
    "pnpm check:refd-timer-probe -> exit 0",
    "pnpm check:slot-lookup -> exit 0",
    "pnpm check:sourcemap-no-sources-content -> exit 0",
    "pnpm check:test-source-alias -> exit 0",
    "pnpm check:tier-file-adoption -> exit 0",
    "pnpm check:type-check-coverage -> exit 0",
    "pnpm check:type-check-debt -> exit 0",
    "pnpm check:watch-hint-literal -> exit 0",
    "pnpm check:where-matcher -> exit 0",
    "OS_VERIFY_LOCK_SLOT=issue-22566 bash scripts/pm/os-verify-lock.sh -c 'pnpm --filter @objectstack/plugin-audit exec vitest run --maxWorkers=2 && pnpm --filter @objectstack/plugin-audit typecheck' (at cdd0198) -> VERDICT command-exit 0 (44 files, 701 passed)",
    "pnpm --filter @objectstack/plugin-security exec vitest run --maxWorkers=2 (at 1c5d95a, under the lock) -> SEC_TEST_EXIT=0 (194 files, 4079 passed, 45 skipped)",
    "pnpm --filter @objectstack/plugin-audit typecheck && pnpm --filter @objectstack/plugin-security typecheck (content of 32c30d8, under the lock) -> VERDICT command-exit 0",
    "pnpm --filter @objectstack/plugin-audit exec vitest run --maxWorkers=2 src/comment-reaction-access.integration.test.ts && pnpm --filter @objectstack/plugin-security exec vitest run --maxWorkers=2 src/comment-reaction-own-record-floor.test.ts src/objects/default-permission-sets.test.ts (at 32c30d8 content, under the lock) -> VERDICT command-exit 0 (21/21, 31/31)",
    "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran-with-exit.txt -> exit 0 ('76 derived, 76 run, 0 NOT-MEASURED (a DERIVED zero)')",
    "pnpm check:i18n-coverage -> NOT MEASURED (exit 3, PREREQUISITE NOT MET: the four example apps unbuilt; not in the derived set; CI)"
    ],
    "line_budget": "20 files, +1174 / -62 vs merge base (99801d8), 1236 changed lines, under the 3000-line class (c) threshold. No governed surface touched.",
    "deviations": [
    "PR line 1 is 'Part of #22566', not the dispatch's 'Fixes #22566': the role file forbids a closing keyword on a card that goes to the decision box (needs_decision). On option B the seat can rewrite line 1; no code changes.",
    "default-permission-sets.ts (claimed) is unchanged in source; only its test gains a tripwire. Measured reason: the rows cannot live in a shipped set as the card words them (open_questions).",
    "comment-access-hooks.ts: the existing sys_comment beforeInsert handler and read middleware are now ONE handler per seam, registered on both objects. This keeps the isSystem census at 123 read sites with no new anchor on content/docs/permissions/system-context.mdx, which the claim excludes. The comment behaviour is unchanged: 114 existing comment-gate tests pass.",
    "Two existing plugin-audit tests that enumerate registered objects were updated (audit-plugin.test.ts provisioning fixtures, translations/bundle-ownership.test.ts OWNED_OBJECTS); both are within the plugin-audit tests surface.",
    "origin/main 99801d8 was merged into the branch (1c5d95a) before the full suites, with no conflicts; the affected closures were rebuilt.",
    "The PM's suggested ablation ('drop the own-record row, the first pin goes red') maps differently under the measured mechanism. The own-record row is the floor, and dropping it (A1) reddens 'cannot delete another member's reaction'. The first pin rests on the object grant (A4). Both were run.",
    "zh-CN, ja-JP and es-ES carry the generator's source fills for the new object (provenance recorded); no hand translation, per the claim's 'regenerated, never by hand'."
    ],
    "files_changed": [
    ".changeset/22566-comment-reaction-record.md",
    "packages/plugins/plugin-audit/scripts/i18n-extract.config.ts",
    "packages/plugins/plugin-audit/src/audit-plugin.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-reaction-access.integration.test.ts",
    "packages/plugins/plugin-audit/src/objects/index.ts",
    "packages/plugins/plugin-audit/src/objects/sys-comment-reaction.object.test.ts",
    "packages/plugins/plugin-audit/src/objects/sys-comment-reaction.object.ts",
    "packages/plugins/plugin-audit/src/translations/bundle-ownership.test.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/es-ES.source-hashes.generated.ts",
    "packages/plugins/plugin-audit/src/translations/ja-JP.objects.generated.ts",
    "packages/plugins/plugin-audit/src/translations/ja-JP.source-hashes.generated.ts",
    "packages/plugins/plugin-audit/src/translations/zh-CN.objects.generated.ts",
    "packages/plugins/plugin-audit/src/translations/zh-CN.source-hashes.generated.ts",
    "packages/plugins/plugin-security/src/comment-reaction-own-record-floor.test.ts",
    "packages/plugins/plugin-security/src/objects/default-permission-sets.test.ts",
    "scripts/platform-object-tenancy-census.json"
    ]
    }

  4. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    The dev's needs_decision answered in-seat: B. The object's bits come from the application's permission sets, as sys_comment's do · domain:services seat 1 (#6021) · session_013j5gkUCpqQiti4GgPqqmnt · 2026-10-10T04:01Z

    The question (os-dev-report 6093527449, PR #22603 at 32c30d8034). The ruling's Execution line (6091550406 on #22505) asks for "sys_comment_reaction and its permission-set rows (create, read, delete-own)". Where do those bits come from? The dev offered three options:

    • A: member_default grants read and create;
    • B: no platform grant; an application grants the object wherever it grants sys_comment, and the shipped own-record floor keeps a delete to the reactor;
    • C: amend ADR-0090 D5 to admit an owner-scoped delete on an everyone-bound set.

    Why this is execution, not a decision. Both premises were re-read on origin/main 99801d831f. check-prior-rulings --card 22566 names accepted ADR decisions that answer it.

    • Governing text 1, the maintainer's ruling recorded on member_default (default-permission-sets.ts, about :679–:702, member_default's * wildcard object grant (C/R/E) union-merges into every org member — app-side explicit-allow object gates are erased on three axes #5491): the everyone baseline "narrows to explicit-allow. Object access comes from OWDs plus profile / permission-set declarations only … Everything else is the application's to declare." The set grants nothing on sys_comment itself; the only sys_comment row in the file is the sys_comment_moderation delete alternate (about :1217). A baseline grant on the reaction object (A) would run against that ruling, and it would serve no member who cannot already read a comment through an application's grant.
    • Governing text 2, ADR-0090 D5: "Lint (D7) hard-blocks high-privilege bits on everyone bindings: … allowDelete …". C would reverse an accepted decision. That takes a new ADR (AGENTS.md Prime Directive 13) and is not an execution choice.
    • B is what both texts already say. Read through them, "its permission-set rows (create, read, delete-own)" lands as: the create and read bits are declared by the application beside its sys_comment grant, and "delete-own" is delivered by the shipped owner_only_deletes floor (created_by, positions org_member), which the PR pins with an ablation (A1). No new platform grant and no loosening.

    Consequence, recorded: an application that shows reactions grants sys_comment_reaction read, create and delete in the same set that grants sys_comment. The changeset says so ("Granting it"). A missing grant answers a loud 403 on the first add, not a silent half-feature.

    Open to the maintainer's veto. This reading departs from the letter of the director's Execution line, so it is listed in this seat's round report.

    Next on this card:


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment (file surface) · domain:services seat 1 (#6021) · session_013j5gkUCpqQiti4GgPqqmnt · 2026-10-10T04:13Z. It amends claim 6092717444, with the same session, branch and Clause-②: yes.

    Added to the file surface under triage's cross-domain exception (6092508551: "If the retirement record or a published-schema file lands in packages/spec, the claim declares that file under the cross-domain exception path"):

    • packages/spec/src/system/constants/platform-object-names.ts: one registry row, sys_comment_reaction in the plugin-audit group of PLATFORM_OBJECTS_BY_PACKAGE (about :104), plus whatever generated artifacts check:generated proves stale. Nothing else in packages/spec.
    • packages/plugins/plugin-audit/src/objects/sys-comment-reaction.object.ts (already declared) gains 'bulk' in apiMethods. The platform's conformance test requires batch wherever single-record writes are granted. The bulk create and delete paths are pinned against the same rules.

    Why: CI at 32c30d8034 (Test Core 1/6, @objectstack/spec#test:repo) failed in the two packages/spec repo tests that enumerate platform objects and apiMethods. Both are this PR's own. The patch round is with the dev; the contract-review-tier record will be taken on the new head (the one started on 32c30d8034 was stopped unposted).


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Correction to the seat's answer above · domain:services seat 1 (#6021) · session_013j5gkUCpqQiti4GgPqqmnt · 2026-10-10T04:14Z

    The answer said a baseline grant (option A) "would run against" the maintainer's ruling recorded on member_default. That overstates it. The block does name a few platform objects, each added by its own maintainer ruling with a _self scope. The accurate reading:

    • A is not barred by that text. It would be one more named baseline grant, and every such grant so far came by a maintainer ruling. A seat adds none on its own: widening what every member is granted is a security-boundary loosening, a human-floor matter.
    • C stays out. ADR-0090 D5 hard-blocks allowDelete on everyone bindings.
    • B stands, as the no-widening default. The application grants the object beside its sys_comment grant, and owner_only_deletes keeps a delete to the reactor.

    The answer is unchanged, and it stays open to the maintainer's veto. If the maintainer wants A, it is two member_default lines plus pins, as a follow-up. The correction comes from the at-tier contract reviewer's reading (unposted; its review was stopped when CI showed the head must change).


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22566,
    "round": 1,
    "status": "done",
    "branch": "claude/issue-22566-comment-reaction-record",
    "pr": "#22603",
    "head": "9f26b002a1",
    "session": "session_013j5gkUCpqQiti4GgPqqmnt (subagent: the parent's harness-stamped id; CLAUDE_CODE_REMOTE_SESSION_ID cse_013j5gkUCpqQiti4GgPqqmnt)",
    "premise_still_valid": true,
    "summary": "Patch round 1 on PR #22603, now at 9f26b00 with origin/main merged twice (76bc1e0, then d748ae8; no conflicts). Both CI reds at 32c30d8 are fixed at the producer. (1) sys_comment_reaction's apiMethods gains 'bulk'. The bulk paths keep every rule, and nothing bypasses the hook. The bulk gate is bulk ∧ derived(child), so updateMany and upsert stay refused. createManyData is one engine.insert of the rows and insertManyData is engine.insertMany, and the engine runs beforeInsert per row, so each row is stamped from the session, and a row on an unreadable comment refuses the whole batch (403 RECORD_NOT_ACCESSIBLE) with nothing written. deleteManyData deletes by id, one at a time, so owner_only_deletes refuses another member's row on its own (PERMISSION_DENIED) and the row survives. Batched reads are ordinary reads under the read gate. (2) packages/spec/src/system/constants/platform-object-names.ts lists sys_comment_reaction in PLATFORM_OBJECTS_BY_PACKAGE['plugin-audit']. This is one row, declared by the seat's claim amendment 6093649317. check:generated proves all 15 artifacts current, so none was regenerated. The changeset now also grades @objectstack/spec minor for the registry name, and keeps Clause-②: yes (widening). The PR body was not touched; its replacement and append text is in pr_body_text.",
    "tests": "New pins. plugin-audit comment-reaction-access.integration.test.ts 'bulk create' (3): createMany stamps every row with the session user; createMany with one unreadable row is refused (RECORD_NOT_ACCESSIBLE, 403) and writes nothing; insertMany likewise. plugin-security comment-reaction-own-record-floor.test.ts 'the batch doors keep the own-record floor' (1): createManyData then deleteManyData through the real ObjectStackProtocolImplementation over the real engine; the caller's own 2 are deleted, the other member's fails alone with PERMISSION_DENIED and survives. The object test pins apiMethods with bulk. Suites at 9f26b00: plugin-audit 44 files/704 passed; plugin-security 194 files/4080 passed, 45 skipped; both typechecks exit 0 with the test layers compiled. spec repo project 54/915 at e4e0c35; the two CI-failing files 15/15. Ablations at 11e9afa, through scripts/ablation-replace.mjs with the anchor hit 1 to 0, the blob changed, a trap restore, and the restore proven as blob == HEAD with git diff HEAD empty. A1 (owner_only_deletes object '*' made a nonexistent object): 3 red / 1 green, including the deleteMany pin. A2 (reaction read middleware registration deleted): 9 red / 15 green. A3b (comment-readability check short-circuited): 5 red / 19 green, including both bulk-create refusals. A4 (app grant allowDelete false): 3 red / 1 green. Every direction is a turn to red. The subjects resolve from the package's own src, so no dist/ rebuild leg applies.",
    "mcp_calls": "0",
    "api_writes": "1 relay write this round: this os-dev-report comment, POST /repos//issues/22566/comments via POST /repos/objectstack-ai/objectstack/dispatches as objectstack-fleet[bot]. No PR body PATCH and no label write. git push is not a REST write.",
    "open_questions": [],
    "out_of_scope_findings": [],
    "gates": [
    "node scripts/check-adr-0087-registration.mjs --base origin/main -> exit 0",
    "node scripts/check-adr-0087-registration.mjs --self-test -> exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main -> exit 0",
    "node scripts/check-changeset-no-major.mjs --self-test -> exit 0",
    "node scripts/check-ci-filter-parity.mjs -> exit 0",
    "node scripts/check-closing-keyword-parity.mjs -> exit 0",
    "node scripts/check-closing-keyword-parity.mjs --self-test -> exit 0",
    "node scripts/check-comment-mask-adoption.mjs -> exit 0",
    "node scripts/check-comment-mask-adoption.mjs --self-test -> exit 0",
    "node scripts/check-comment-mask-corpus.mjs -> exit 0",
    "node scripts/check-dev-prereqs.mjs --self-test -> exit 0",
    "node scripts/check-dts-emitted.mjs --self-test -> exit 0",
    "node scripts/check-empty-changeset.mjs --base origin/main -> exit 0",
    "node scripts/check-empty-changeset.mjs --self-test -> exit 0",
    "node scripts/check-issue-citations.mjs -> exit 0",
    "node scripts/check-keyed-text-bounds.mjs -> exit 0",
    "node scripts/check-keyed-text-bounds.mjs --self-test -> exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs -> exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs --self-test -> exit 0",
    "node scripts/check-plugin-teardown-shape.mjs -> exit 0",
    "node scripts/check-plugin-teardown-shape.mjs --self-test -> exit 0",
    "node scripts/check-registry-log-declared.mjs -> exit 0",
    "node scripts/check-registry-log-declared.mjs --self-test -> exit 0",
    "node scripts/check-rest-log-spy-declared.mjs -> exit 0",
    "node scripts/check-rest-log-spy-declared.mjs --self-test -> exit 0",
    "node scripts/check-scripts-symbol-anchors.mjs -> exit 0",
    "node scripts/check-scripts-symbol-anchors.mjs --self-test -> exit 0",
    "node scripts/check-spec-docblock-symbol-anchors.mjs -> exit 0",
    "node scripts/check-spec-docblock-symbol-anchors.mjs --self-test -> exit 0",
    "node scripts/check-system-context-census.mjs -> exit 0",
    "node scripts/check-system-context-census.mjs --self-test -> exit 0",
    "node scripts/check-tenant-audit-census.mjs -> exit 0",
    "node scripts/check-tenant-audit-census.mjs --self-test -> exit 0",
    "node scripts/check-undeclared-dep-imports.mjs -> exit 0",
    "node scripts/check-undeclared-dep-imports.mjs --self-test -> exit 0",
    "node scripts/docs-audit/check-affected-docs.mjs -> exit 0",
    "node scripts/docs-audit/check-drift-comment.mjs -> exit 0",
    "node scripts/pm/release-rehearsal-clone.mjs --self-test -> exit 0",
    "node scripts/release-pending-publish.mjs --self-test -> exit 0",
    "pnpm --filter @objectstack/lint run check:doc-formula-expressions -> exit 0",
    "pnpm --filter @objectstack/spec run check:api-surface -> exit 0",
    "pnpm --filter @objectstack/spec run check:authorable-surface -> exit 0",
    "pnpm --filter @objectstack/spec run check:browser-reachable-entries -> exit 0",
    "pnpm --filter @objectstack/spec run check:docs -> exit 0",
    "pnpm --filter @objectstack/spec run check:dual-source-exports -> exit 0",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys -> exit 0",
    "pnpm --filter @objectstack/spec run check:empty-state -> exit 0",
    "pnpm --filter @objectstack/spec run check:entry-nameability -> exit 0",
    "pnpm --filter @objectstack/spec run check:export-origins -> exit 0",
    "pnpm --filter @objectstack/spec run check:exported-any -> exit 0",
    "pnpm --filter @objectstack/spec run check:liveness -> exit 0",
    "pnpm --filter @objectstack/spec run check:llms-txt -> exit 0",
    "pnpm --filter @objectstack/spec run check:objectui-pin-citations -> exit 0",
    "pnpm --filter @objectstack/spec run check:skill-refs -> exit 0",
    "pnpm --filter @objectstack/spec run check:strictness-ledger -> exit 0",
    "pnpm --filter @objectstack/spec run check:variant-docs -> exit 0",
    "pnpm --filter @objectstack/spec run check:yaml-examples -> exit 0",
    "pnpm check:agent-test-spelling -> exit 0",
    "pnpm check:bash32-floor -> exit 0",
    "pnpm check:changeset-gate-self-tests -> exit 0",
    "pnpm check:cli-command-ids -> exit 0",
    "pnpm check:cross-package-test-inputs -> exit 0",
    "pnpm check:dispatcher-error-vocabulary -> exit 0",
    "pnpm check:doc-authoring -> exit 0",
    "pnpm check:driver-memory-census -> exit 0",
    "pnpm check:dts-closure -> exit 0",
    "pnpm check:dual-build-cjs-loads -> exit 0 (first run exit 3, PREREQUISITE NOT MET: 4 unrelated dists absent in the recreated worktree; built them, re-run exit 0)",
    "pnpm check:engine-double-contract -> exit 0",
    "pnpm check:entry-guard -> exit 0",
    "pnpm check:error-status-conformance -> exit 0",
    "pnpm check:gitlink-declared -> exit 0",
    "pnpm check:i18n -> exit 0",
    "pnpm check:i18n-stale-fill -> exit 0",
    "pnpm check:issue-citations -> exit 0",
    "pnpm check:lean-entry-closure -> exit 0",
    "pnpm check:logger-receiver-detach -> exit 0",
    "pnpm check:merge-driver -> exit 0",
    "pnpm check:nul-bytes -> exit 0",
    "pnpm check:objectql-double-limit -> exit 0",
    "pnpm check:objectui-changeset -> exit 0",
    "pnpm check:org-identifier -> exit 0",
    "pnpm check:page-declaration-shape -> exit 0",
    "pnpm check:parse-guard -> exit 0",
    "pnpm check:pm-changeset-deadline-census -> exit 0",
    "pnpm check:pm-prior-rulings -> exit 0",
    "pnpm check:pnpm-filter-targets -> exit 0",
    "pnpm check:published-files -> exit 0",
    "pnpm check:query-options-erasure -> exit 0",
    "pnpm check:refd-timer-probe -> exit 0",
    "pnpm check:slot-lookup -> exit 0",
    "pnpm check:sourcemap-no-sources-content -> exit 0",
    "pnpm check:spec-parsed-alias -> exit 0",
    "pnpm check:test-source-alias -> exit 0",
    "pnpm check:tier-file-adoption -> exit 0",
    "pnpm check:type-check-coverage -> exit 0",
    "pnpm check:type-check-debt -> exit 0",
    "pnpm check:watch-hint-literal -> exit 0",
    "pnpm check:where-matcher -> exit 0",
    "lock: pnpm exec turbo run build (spec, ...plugin-audit, ...plugin-security, cli) && pnpm --filter @objectstack/spec check:generated && plugin-audit vitest && plugin-audit typecheck && plugin-security vitest && plugin-security typecheck (at 9f26b00) -> VERDICT command-exit 0 (check:generated 15/15 up to date, none regenerated; plugin-audit 44 files/704 passed; plugin-security 194 files/4080 passed, 45 skipped; both typecheck test layers OK)",
    "lock: pnpm --filter @objectstack/spec exec vitest run --project repo --maxWorkers=2 (at e4e0c35) -> VERDICT command-exit 0 (54 files, 915 passed)",
    "lock: pnpm --filter @objectstack/spec exec vitest run --project repo src/data/api-methods-batch-conformance.test.ts src/system/constants/platform-object-names.test.ts (at 11e9afa) -> VERDICT command-exit 0 (2 files, 15 passed)",
    "pnpm check:i18n-coverage (at 9f26b00) -> exit 0 ('13 config(s), 621 baselined untranslated string(s), none new')",
    "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran-r1.txt -> exit 0 ('98 run, 0 NOT-MEASURED (a DERIVED zero)')"
    ],
    "line_budget": "21 files, +1300 / -63 vs merge base d748ae8 (1363 changed lines; this round added +126 / -1 over round 0's 20 files plus 1 spec file). Under the 3000-line class (c) threshold. No governed surface touched.",
    "deviations": [
    "The worktree was recreated from origin at 32c30d8 (it was removed after round 0); pnpm install --frozen-lockfile; then origin/main 76bc1e0 was merged (92e75cd), and later d748ae8 (9f26b00), both without conflicts.",
    "check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET: @objectstack/studio, embedder-openai, knowledge-ragflow and service-cluster-redis had no dist/ in the recreated worktree). It is unrelated to this diff. Those four were built under the lock and the gate re-run exited 0. The reconciliation records the re-run's exit.",
    "spec repo-project full run is at e4e0c35. The changeset commit (11e9afa) and the merge of d748ae8 (a spec i18n-resolver change from main) came after it. The two target files were re-run at 11e9afa, and check:generated was re-run at 9f26b00.",
    "Bulk is pinned at the engine calls the batch doors make (plugin-audit) and through ObjectStackProtocolImplementation (plugin-security); the REST route handler's apiMethods 405 for updateMany is the existing bulk ∧ derived(child) machinery, not re-pinned here."
    ],
    "files_changed": [
    ".changeset/22566-comment-reaction-record.md",
    "packages/plugins/plugin-audit/scripts/i18n-extract.config.ts",
    "packages/plugins/plugin-audit/src/audit-plugin.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-reaction-access.integration.test.ts",
    "packages/plugins/plugin-audit/src/objects/index.ts",
    "packages/plugins/plugin-audit/src/objects/sys-comment-reaction.object.test.ts",
    "packages/plugins/plugin-audit/src/objects/sys-comment-reaction.object.ts",
    "packages/plugins/plugin-audit/src/translations/bundle-ownership.test.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/es-ES.source-hashes.generated.ts",
    "packages/plugins/plugin-audit/src/translations/ja-JP.objects.generated.ts",
    "packages/plugins/plugin-audit/src/translations/ja-JP.source-hashes.generated.ts",
    "packages/plugins/plugin-audit/src/translations/zh-CN.objects.generated.ts",
    "packages/plugins/plugin-audit/src/translations/zh-CN.source-hashes.generated.ts",
    "packages/plugins/plugin-security/src/comment-reaction-own-record-floor.test.ts",
    "packages/plugins/plugin-security/src/objects/default-permission-sets.test.ts",
    "packages/spec/src/system/constants/platform-object-names.ts",
    "scripts/platform-object-tenancy-census.json"
    ],
    "regenerated_artifacts": "none — pnpm --filter @objectstack/spec check:generated: 15 of 15 up to date (at 11e9afa's spec and again at 9f26b00); no --fix run",
    "pr_body_text": "REPLACE the first bullet under "## What this adds" with:\n\n- The object (plugin-audit/src/objects/sys-comment-reaction.object.ts, registered beside sys_comment in AuditPlugin.init and provisioned with it). Fields: comment_id (text, at most 255 characters), emoji (text, at most 64), user_id (lookup to sys_user), created_at. apiMethods: ['get', 'list', 'create', 'delete', 'bulk']; userActions: { edit: false, import: false }; feeds: false, activities: false. No sharingModel, and the audit columns are injected, so created_by exists and is stamped. @objectstack/spec's platform object registry (PLATFORM_OBJECTS_BY_PACKAGE['plugin-audit']) lists it.\n\nINSERT a new section after "## Uniqueness":\n\n## The batch doors (bulk)\n\nThe object grants bulk, as api-methods-batch-conformance.test.ts requires of every whitelist that grants single-record writes. It opens no path around the rules above:\n\n- The bulk gate is bulk ∧ derived(child): a batched child is admitted only when it is allowed on its own. update is not offered, so updateMany and an upsert child stay refused.\n- createMany (createManyData) is one engine.insert of the rows, and the partial-success batch (insertManyData) is engine.insertMany. The engine runs beforeInsert once per row in both, so every row meets the create gate. Each row is stamped with the session's user, whatever it sent. A row on a comment the caller cannot read refuses the whole batch with 403 RECORD_NOT_ACCESSIBLE, and nothing is written. Pinned in comment-reaction-access.integration.test.ts under "bulk create" (3 tests).\n- deleteMany (deleteManyData) deletes one id at a time, by id, so every row meets owner_only_deletes. The caller's own reactions are deleted, and another member's fails on its own row (PERMISSION_DENIED) and survives. Pinned in comment-reaction-own-record-floor.test.ts under "the batch doors keep the own-record floor", driven through the real ObjectStackProtocolImplementation over the real engine.\n- A batched read is an ordinary read, and the read gate narrows it. The reader's comment_id $in read is the pinned case.\n- Ablations at 11e9afaac5. A1, dropping the floor, reddens the deleteMany pin. A3b, short-circuiting the comment-readability check, reddens both bulk-create refusal pins.\n\nAPPEND at the end of the body, before the footer:\n\n## Round 1 (patch): files and results at 9f26b002a1\n\nThe two CI reds at 32c30d8034 (Test Core 1/6, @objectstack/spec#test:repo) were this PR's own, and both are fixed at the producer:\n- api-methods-batch-conformance.test.ts: the object now grants bulk (see "The batch doors").\n- platform-object-names.test.ts: PLATFORM_OBJECTS_BY_PACKAGE['plugin-audit'] now lists sys_comment_reaction. This is the one packages/spec file, declared by the seat's claim amendment 6093649317 under triage's cross-domain exception. check:generated proves all 15 generated artifacts current, so none was regenerated. The changeset now grades @objectstack/spec minor for the new registry name.\n\nFiles (21, +1300 / −63 against merge base d748ae80af):\n- .changeset/22566-comment-reaction-record.md\n- packages/plugins/plugin-audit/scripts/i18n-extract.config.ts\n- packages/plugins/plugin-audit/src/audit-plugin.ts, audit-plugin.test.ts\n- packages/plugins/plugin-audit/src/comment-access-hooks.ts\n- packages/plugins/plugin-audit/src/comment-reaction-access.integration.test.ts\n- packages/plugins/plugin-audit/src/objects/index.ts, sys-comment-reaction.object.ts, sys-comment-reaction.object.test.ts\n- packages/plugins/plugin-audit/src/translations/bundle-ownership.test.ts, and the seven generated bundle files (en / es-ES / ja-JP / zh-CN .objects.generated.ts, three .source-hashes.generated.ts)\n- packages/plugins/plugin-security/src/comment-reaction-own-record-floor.test.ts\n- packages/plugins/plugin-security/src/objects/default-permission-sets.test.ts\n- packages/spec/src/system/constants/platform-object-names.ts\n- scripts/platform-object-tenancy-census.json\n\nResults (under the verify lock, exits captured before any pipe):\n- @objectstack/spec: the repo project gave 54 files and 915 tests passed (at e4e0c355ca). Of those, the two files CI failed gave 15/15. check:generated: 15 of 15 up to date at 9f26b002a1.\n- @objectstack/plugin-audit: 44 files and 704 tests passed. typecheck exit 0, with the test layer compiled.\n- @objectstack/plugin-security: 194 files, 4080 passed and 45 skipped. typecheck exit 0, with the test layer compiled.\n- 98 derived gate families exited 0 (dispatch-gates --ran: "98 run, 0 NOT-MEASURED, a derived zero"). check:dual-build-cjs-loads needed four unrelated packages built first, and was then re-run green. check:i18n-coverage is OK: 13 configs, none new.\n- Ablations re-run at 11e9afaac5: A1 3 red / 1 green, A2 9 red / 15 green, A3b 5 red / 19 green, A4 3 red / 1 green. Every leg was restored to a blob equal to HEAD.\n"
    }

  8. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT (seat review, patch round 1): PR #22603 at head 9f26b002a1. sys_comment_reaction: an emoji reaction is its reactor's own record

    domain:services seat 1 (#6021) · session_013j5gkUCpqQiti4GgPqqmnt · 2026-10-10T05:46Z. Claim 6092717444, amended 6093649317 (the one packages/spec file). Scope: the additive half (triage 6092508551). Seat answer B 6093553917, corrected 6093657666. Round-1 report 6094184898. Read against GitHub and the PR head fetched into a seat-owned ref, not the report.

    Review route. Clause-②: yes (widening): a new platform object, and a new name in @objectstack/spec's platform object registry. The contract-review-tier record is on the PR (6094334803): Served-tier: CONTRACT_REVIEW_TIER, head 9f26b002a1dc1225c27b15b3472ad678dcfe3609, Local-runs: none, an isolated at-tier subagent adopted by this seat, PASS. A review started on the round-0 head 32c30d8034 was stopped before it posted a record. Its one reading that reached the board is the seat's correction 6093657666.

    Shape. Draft, base main. Line 1 is Fixes #22566 (rewritten by the seat with answer B) and line 2 is Clause-②: yes. 21 files, +1300 / −63. NOT governed (check-governed-merges --pr 22603: 0 of 21 paths, 1363 changed lines). The changeset grades @objectstack/plugin-audit minor and @objectstack/spec minor; no major.

    The change, as read in the diff

    • plugin-audit registers sys_comment_reaction beside sys_comment: comment_id, emoji, user_id, one row per (comment, emoji, user), unique within an organization. apiMethods are get, list, create, delete and bulk; no update.
    • A reaction is readable exactly when its comment is. Every read is narrowed through the comment's own read rule, under the caller's context.
    • A create needs a readable comment, else 403 RECORD_NOT_ACCESSIBLE. user_id is stamped from the session.
    • A delete is held to the reactor by the platform's own-record rule (owner_only_deletes), unchanged.
    • comment-access-hooks.ts moves to one handler per seam, registered on both objects. The sys_comment behaviour is unchanged, and its existing pins stay green.
    • Round 1 adds bulk, which the batch-conformance rule requires of a whitelist granting single-record writes. The batch doors admit only children allowed one at a time. createMany and insertMany run the create gate per row, and deleteMany deletes by id, row by row, under the floor. Pinned at the engine calls and through the real protocol implementation.
    • PLATFORM_OBJECTS_BY_PACKAGE['plugin-audit'] lists the new name. check:generated is 15 of 15 current, and nothing was regenerated.
    • member_default grants nothing on the object. Answer B: an application grants read, create and delete beside its sys_comment grant. ADR-0090 D5 keeps allowDelete off everyone-bound sets.

    Evidence read. Four ablations from a committed head, each restored to a blob equal to HEAD; every leg turns red. 98 derived gate families exit 0. plugin-audit 704 passed; plugin-security 4080 passed, 45 skipped. Both typechecks exit 0 with the test layers compiled.

    CI at 9f26b002a1: 32 success, 3 skipped (Build Docs, Console Pin Gate, Packed-tarball smoke (opt-in), all rostered; the diff touches none of their surfaces). mergeable_state: clean.

    The PR's Acceptance notes, disposed

    • Every reaction create and delete still writes sys_audit_log (only the sys_activity mirror is off): Acceptance notes. Volume has no named need.
    • A deleted comment's reactions stay in storage, read by nobody: Acceptance notes. No cleanup need is named.
    • comment-access-hooks.ts's header still says the member sets "grant wildcard CRUD": stale prose. It rides the next edit of that file. This seat's ledger records it.
    • The isSystem census page does not name reactions: Acceptance notes. Anchors and counts hold.
    • The REST door's PATCH refusal is NOT MEASURED at HTTP: Acceptance notes. The declaration is pinned, and the 405 is existing machinery.

    Downstream.

    Landing: ready plus auto-merge through the queue, in this act.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:services seat 1 (#6021) · session_013j5gkUCpqQiti4GgPqqmnt · 2026-10-10T06:23Z


    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

No one assigned

    Labels

    area:recordsBusiness objects, records, the views that show data, usable forms, searchdomain:servicesenhancementNew feature or requestpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions