Skip to content

fix(setup-copy): approval, security, automation and sharing descriptions read as admin copy; ADR numbers move to comments - #23917

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-23829-setup-copy-services
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-23829-setup-copy-services

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #23829
Clause-②: no

What changed

The sentence an administrator reads under a Setup page title is the object's description; a field's help tooltip is the field's description; the Permission Sets page lists each shipped set with its description. This PR rewrites those strings in the four domain:services packages the card names (plugin-approvals, plugin-security, service-automation, plugin-sharing) and moves every ADR number, decision id and review-finding id out of the strings into a comment beside each one or the docblock that already cites it. Docblocks and ADR links in code stay. Wording only: no field, index, permission or behaviour change.

Form copied from #23845 (the parent #23802's landed PR): field help keeps its operational text and loses only the design-record reference; object descriptions are rewritten as one sentence.

Before / after

Measured by loading every object each package exports from src (13 objects, every string leaf at any depth, multi-line values included) plus plugin-security's 8 shipped permission sets, against the card's patterns (ADR- followed by a digit, a decision id such as D2, finding F, emit(), kernel). Before, at base 94114c1f26: 26 object strings and 3 permission-set descriptions matched. After: 0 and 0. The card's own reading (single-line values only) had found 9 of the 29.

Object descriptions, rewritten:

Object (where Setup shows it) Before After
sys_approval_delegation (Approvals, Delegations (OOO)) Self-service out-of-office rule: route this user's approver slots to a delegate within a time window. While someone is away, approvals assigned to them personally go to their delegate.
sys_record_share (Access Control, Record Shares) Per-record sharing grant — extends OWD with explicit access Records shared beyond their owner, one row per grant.
sys_user_position (a user's Positions list, View all) Assigns a position, by name, to a user. Platform-owned (ADR-0057 D4, ADR-0090 D3). Which positions each user holds, one row per assignment.
sys_audience_binding_suggestion (no Setup page) Package-suggested everyone-anchor grant and the deployment-level decision on it (ADR-0090 D5/D9). A package's suggestion to give one of its permission sets to everyone who signs in, and the decision taken on it.
sys_automation_run (no Setup page) Durable automation run state: live suspended runs (resumable, ADR-0019) and terminal run history (completed / failed / cancelled / timed_out / refused, for observability). Paused automation runs waiting to resume, and the recent history of finished runs.

The Approval Delegations sentence departs from the card's starting sentence ("Route your approvals to someone else while you are away.") on purpose: ApprovalService.expandApprovers reroutes only individually-routed approvers (user / field / manager); team, department, position and membership-level approvers are not rerouted, so "your approvals" would promise more than the runtime does. The comment beside the string says so.

Field help and other strings, the design-record reference removed and the rest unchanged:

  • sys_approval_request: flow_run_id, flow_node_id, node_config_json ("(ADR-0019)"; the section comment already cites it).
  • sys_approval_delegation.valid_from ("(ADR-0091 D2 predicate)").
  • sys_audience_binding_suggestion: package_id ("ADR-0086 D3 provenance"), anchor ("ADR-0090 D9").
  • sys_user_position: business_unit_id, valid_from, valid_until, reason, delegated_from, last_certified_at, certified_by (the "[ADR-0091 Dn]" / "[ADR-0090 Addendum]" prefixes and the "(D2)", "(D3)", "(D4)", "(D12)" ids), and the reserved_identity_position validation's description ("ADR-0068 D2").
  • Permission set organization_admin_no_bypass: "(ADR-0105 D4 / finding F2)". Its producer is deriveWallLessOrgAdmin in packages/plugins/plugin-security/src/objects/default-permission-sets.ts; the card's reading missed it because the description is a multi-line concatenation.

Beyond the card's list, in the same packages

These sit in the four packages but not in the card's list. Each is the same defect (design-record vocabulary in admin copy), the fix is the same mechanical removal, no open PR touches the file, and each is covered by the same pin and bundle family, so it is fixed here rather than reported. Without them, each package's pin over every object it ships would be red.

  • sys_user_permission_set (plugin-security; a user's Permission Sets list and its grant form): permission_set, valid_from, valid_until, reason, last_certified_at, certified_by help and the validity_window_order validation's description. These are the byte-identical "[ADR-0091 Dn]" phrases of the sibling sys_user_position, in the same bundle.
  • Permission sets mcp_agent_data_read and mcp_agent_data_write (same producer file as organization_admin_no_bypass): "via the ADR-0090 D10 intersection" became "by the delegating user's own permissions".
  • reservedIdentityNameMessage (plugin-security objects/reserved-identity-names.ts): the refusal a Setup assignment form shows read "These names are ADR-0068 built-in identities"; it now reads "These names are built-in identities". It is a leaf of every locale's security bundle. The tests compare against the function, so none changed.
  • sys_flow_dispatch (service-automation; no Setup page): "a rebuilt kernel" became "a reload or restart".

Setup reachability

  • Setup nav entries: sys_approval_request, sys_approval_action, sys_approval_delegation (approvals-plugin.ts), sys_record_share, sys_sharing_rule (sharing-plugin.ts).
  • Reached through the user record page: sys_user_position and sys_user_permission_set (the Positions and Permission Sets related lists in platform-objects/src/pages/sys-user.page.ts; New opens each object's form, View all opens its list page).
  • Permission sets: Access Control, Permission Sets (/apps/setup/metadata/permission).
  • Not reachable from Setup (no nav entry, no record page in this repository): sys_audience_binding_suggestion (objectui reads its rows through a dedicated suggested-bindings API and renders its own copy) and sys_automation_run. Both are cleaned because the card names them.

Translations

node scripts/check-i18n-bundles.mjs --write --filter=approvals|security|sharing regenerated the en bundles from source. service-automation generates no bundle. Merge mode keeps every non-empty translated-locale value, so the order was the one #23845 used:

  1. Translated leaves whose source moved were edited in place, leaf values only: plugin-security zh-CN, ja-JP and es-ES (13 help texts with the same references removed, and the sys_user_position description re-translated); plugin-sharing zh-CN, ja-JP and es-ES (the sys_record_share description); plugin-approvals zh-CN (the delegation description and valid_from help).
  2. English fills with recorded provenance were emptied and refilled by the generator, which refreshed their source hashes: the three flow_* help texts in all three approvals locales, the delegation description and valid_from help in approvals ja-JP and es-ES, and the reserved-position refusal in all three security locales.
  3. The bundle commit (the hand edits above plus the regeneration) touches only these leaves and their hash entries: 18 files, 100 insertions and 100 deletions.

Pins (acceptance 2)

One unit test per package, in the form #23845 landed (service-messaging/src/objects/admin-copy-vocabulary.test.ts). That pin restates its matcher rather than importing a shared helper, so these do the same. No new check:* script, lint rule or CI wiring.

  • packages/plugins/plugin-approvals/src/admin-copy-vocabulary.test.ts: every object the package exports plus sys_approval_token (registered by the plugin, not exported); every leaf of the four objects bundles.
  • packages/plugins/plugin-security/src/objects/admin-copy-vocabulary.test.ts: every object objects/index.ts exports; the label and description of every shipped permission set; every leaf of the four bundles.
  • packages/plugins/plugin-sharing/src/objects/admin-copy-vocabulary.test.ts: every object objects/index.ts exports; every leaf of the four bundles.
  • packages/services/service-automation/src/admin-copy-vocabulary.test.ts: every object the package exports (no bundle exists).

Each has a positive control showing the matcher recognises every kind of vocabulary, and a minimum roster so the population cannot quietly shrink.

Ablation, through scripts/ablation-replace.mjs (WRAP mode, trap-armed restore): " (ADR-0057 D4)" put back into the sys_user_position description (anchor 1 to 0, marker 0 to 1, blob fbd17436adff to 7ea8a4913087). The security pin went red on exactly one test, naming sys_user_position.description (an ADR number, a decision id); 6 others stayed green. Restore: blob equal to HEAD (fbd17436adff), git diff HEAD empty. No build was involved, because the pin imports the object through relative src paths, not through a dist export.

Local verification (HEAD 85fb81cfd1)

Built first: turbo run build --filter=@objectstack/cli... (62 packages, the CLI closure the i18n generator needs, which contains all four packages), exit 0, after merging origin/main at 497518c3f6.

  • pnpm --filter @objectstack/plugin-approvals test: 79 files, 1088 tests passed. typecheck: exit 0.
  • pnpm --filter @objectstack/plugin-security test: 187 files, 3721 passed, 45 skipped. typecheck: exit 0.
  • pnpm --filter @objectstack/plugin-sharing test: 47 files, 1073 passed. typecheck: exit 0.
  • pnpm --filter @objectstack/service-automation test: 187 files, 2503 passed. typecheck: exit 0.
  • Each new pin is in its package's test tsc program (tsc -p tsconfig.test.json --listFilesOnly: 1 hit each), which check:test-typecheck compiles.
  • Derived gate list (dispatch-gates --commands --repo objectstack-ai/objectstack, 65 families): 64 exit 0, among them check:i18n ("10 package(s) — all bundles in sync"), check:i18n-stale-fill ("no new stale fills, 0 baselined"), check:cross-package-test-inputs and check:nul-bytes. check:dual-build-cjs-loads printed PREREQUISITE NOT MET (exit 3): it reads every package's dist, and this worktree built only the CLI closure. That one is NOT MEASURED locally and left to CI. --ran reconciliation: 65 derived, 64 run, 1 NOT-MEASURED, 0 UNRUN.
  • Also run, not derived: pnpm check:i18n-coverage, exit 0 ("621 baselined untranslated string(s), none new").
  • Not run locally: test:repo and the rest of the farm, which belong to CI.

Acceptance notes

  • The declaration-closure reading the dispatch asked for, measured: these packages' built dist/index.d.ts carry each object's description as a string literal type (readonly description: "Records shared beyond their owner, one row per grant."), so the declaration files change byte-wise in those literals only. No export, type shape or accept set moved.
  • Out of these packages' object files and left alone: the everyone and guest built-in positions' descriptions in plugin-security/src/builtin-positions.ts carry "(ADR-0090 D5)" and "(ADR-0090 D9)" on Setup's Positions page. That file is outside this card's surface, and builtin-positions.boot.test.ts pins the same text as the stored legacy rows the retired seeder wrote, so a change there also moves a stored-row fixture and needs its own reading. Reported to the PM for the family's closing card; the security pin does not judge the positions population.
  • sys_approval_request's other descriptions and the excluded sys-approval-request.page.ts were not touched (PR feat(plugin-approvals): the request page's Details tab ends with the request snapshot's raw JSON, gated on studio.access #23837 holds the page).
  • The Approval Delegations, Record Shares and User Positions sentences are this PR's choices from the card's starting sentences; the reasons are above and in the comments beside the strings.

Generated by Claude Code

…ons carry no ADR numbers

Object and field descriptions an administrator reads in Setup are rewritten in
the admin's words; ADR numbers and decision ids move to comments beside the
strings. Wording only.

Claude-Session: https://claude.ai/code/session_018VqJPGA1NDNSCZsnecsChP
Co-authored-by: Claude <noreply@anthropic.com>
…rom the new descriptions

Translated leaves whose source moved are re-translated in place (leaf values
only); English fills with recorded provenance were emptied and refilled by
`check-i18n-bundles --write`, which also refreshed their source hashes.

Claude-Session: https://claude.ai/code/session_018VqJPGA1NDNSCZsnecsChP
Co-authored-by: Claude <noreply@anthropic.com>
… vocabulary

One unit test per package (approvals, security, sharing, automation), in the
form the service-messaging pin landed: every object the package ships, the
security permission sets, and every leaf of the package's objects bundles.

Claude-Session: https://claude.ai/code/session_018VqJPGA1NDNSCZsnecsChP
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Oct 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/plugin-approvals, @objectstack/plugin-security, @objectstack/plugin-sharing, @objectstack/service-automation, touching 17 documentable anchor(s).

17 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json d5666be8769a18c5c8d7695b3ac9100af2394620.

⛔ 12 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 20 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json d5666be8769a18c5c8d7695b3ac9100af2394620 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 8f0ffd74b306d4238d496b7a3ac788d979276373 — the merge of head 85fb81cfd1db2eebc634ef41eb7e3e49e11c45c8 into base d5666be8769a18c5c8d7695b3ac9100af2394620, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 8f0ffd74b306d4238d496b7a3ac788d979276373 && git checkout 8f0ffd74b306d4238d496b7a3ac788d979276373
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d5666be8769a18c5c8d7695b3ac9100af2394620 85fb81cfd1db2eebc634ef41eb7e3e49e11c45c8 && git checkout -B drift-repro d5666be8769a18c5c8d7695b3ac9100af2394620 && git merge --no-ff 85fb81cfd1db2eebc634ef41eb7e3e49e11c45c8

node scripts/docs-audit/affected-docs.mjs --json d5666be8769a18c5c8d7695b3ac9100af2394620

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs d5666be8769a18c5c8d7695b3ac9100af2394620 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · review · domain:services seat 2 · session_018VqJPGA1NDNSCZsnecsChP · 2026-10-16T12:40Z

At head 85fb81cfd1, from the dev's report on the card (comment 6215628349).

  • check-governed-merges --pr 23917: NOT governed. 789 changed lines, under 3,000.
  • The PR carries Clause-②: no and the dev measured it: the .d.ts files change only in description string literals. So this PR owes no contract review. The seat reviewed the diff itself.
  • CI is still running (Test Core 1–6/6 and Type Check · workspace). ACCEPT waits for it.

What the seat re-read

  • Delegation sentence. "assigned to them personally" holds at approval-service.ts:2388–2400. Only resolveAs: 'user' values go through applyOooDelegation. Graph kinds (team, department, position, membership) are not OOO-substituted. The card's sentence would have promised more than the runtime delivers (AGENTS.md rule 10 corollary).
  • No other copy of the old strings. A repo-wide git grep at this head, generated bundles and CHANGELOGs excluded, finds none of the eight retired strings. The reserved-identity refusal is pinned only inside plugin-security, and its tests pass on the dev's run.
  • References kept. Each moved ADR reference sits in a comment beside its string. Docblocks are unchanged.
  • The four pins. Each walks every exported object, at any depth, plus the shipped permission sets. The one ablation went red on exactly the re-added string.

Answers to the report's questions

  1. Approval Delegations sentence: A, keep the shipped sentence. The reason is the one above.
  2. The other four object sentences: A, keep them. "recent history" is right, because finished runs age out at 30 days.
  3. Field help in the fix(platform-objects,metadata-core,service-messaging): Setup descriptions are plain admin sentences; ADR references move to the docblocks #23845 form: A. The operational text is what an admin acts on.
  4. Scope beyond the claim's file surface: A, accepted.
    • The files are sys-user-permission-set.object.ts, reserved-identity-names.ts, sys-flow-dispatch.object.ts, and the two mcp_agent_data_* descriptions in the claimed default-permission-sets.ts.
    • Same defect class, wording only, pinned, and no other claim on those files.
    • The seat appends them to the claim's file surface on the card.

Out-of-scope findings

Next: once CI is green on this head, the seat posts ACCEPT and lands this PR through the queue.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · domain:services seat 2 · session_018VqJPGA1NDNSCZsnecsChP · 2026-10-16T13:02Z

Reviewed against GitHub at head 85fb81cfd1, not against the dev's report (6215628349 on #23829). The seat's review is 6215716563.

  • Form:
    • Draft, base main. The first line is Fixes #23829, then Clause-②: no. No other card's number sits beside a closing keyword.
    • 33 files, all on claim 6214458606's surface plus the amendment 6215723565.
    • One patch changeset covers the four packages.
    • check-governed-merges.mjs --pr 23917, re-run at this head: NOT governed, 789 changed lines.
  • The card's Acceptance:
    1. Plain admin sentences: met. The five object descriptions each read as one admin sentence. Field help, three permission-set descriptions, the flow-dispatch ledger and the reserved-position refusal lose only their design-record references (the fix(platform-objects,metadata-core,service-messaging): Setup descriptions are plain admin sentences; ADR references move to the docblocks #23845 form). Each reference moved to a comment beside its string, and docblocks are unchanged.
    2. Package pins: met. Each of the four packages has a unit test in the fix(platform-objects,metadata-core,service-messaging): Setup descriptions are plain admin sentences; ADR references move to the docblocks #23845 form over every exported object, at any depth, plus the shipped permission sets. No new check:* script or CI gate. The one ablation (re-adding (ADR-0057 D4)) turned exactly one test red, and the restore was proven by blob.
    3. Bundles: met. zh-CN, ja-JP and es-ES were regenerated from source, and check:i18n reports all bundles in sync. service-automation ships no bundle.
  • Measured premises:
    • At base 94114c1f26 there were 29 matching strings (the card read 9), and 0 after.
    • The organization_admin_no_bypass producer is deriveWallLessOrgAdmin.
    • "assigned to them personally" holds at approval-service.ts:2388–2400.
    • A repo-wide grep finds no copy of the retired strings outside generated bundles and CHANGELOGs.
  • Clause-②: no: measured. The .d.ts files change only in description string literals. No export, type shape or accept set moved.
  • CI: 40 check-runs, latest per name: 34 success, 0 failure. 6 skipped, all on the roster: Build Docs, Console Pin Gate, Dogfood Regression Gate matrix, Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance.
  • Gates: 65 derived, 64 exit 0, reconciled with --ran. The 65th, check:dual-build-cjs-loads, needs every dist and was NOT MEASURED locally; CI's builds and checks are green.
  • Open questions: all four answered A in 6215716563.
  • Split out: the everyone / guest built-in position descriptions → Setup copy: the Everyone and Guest built-in positions' descriptions carry ADR-0090 decision ids, and stored rows hold the same text #23919. Stored rows hold that text, so the change is more than wording.

ACCEPT. This act marks the PR ready and enables auto-merge through the fleet relay. It lands through the merge queue.


Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

2 participants