Skip to content

fix(platform-objects, plugin-security, plugin-approvals, service-messaging, objectql): Setup field help is written for administrators, and the inert access-review fields are hidden - #25377

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-xlmv3p
Oct 23, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-xlmv3p

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Fixes #25331

Clause-②: no
Metadata-protocol: none

Ruling carried: objectstack-ai/hotcrm#2194, record 6354968262:

25251 B hotcrm B

It adopts T2-U02. The card's Done when is the acceptance.

What changes

Each developer string the Setup pass met is replaced by help an administrator can act on: what the field means and what to do with it. Where the old text held a fact a developer needs, that fact moved into the code comment beside the field.

Field Was Now says
sys_user_permission_set.user_id, sys_user_position.user_id "Foreign key to sys_user." the user who receives the set / holds the position
sys_user_permission_set.permission_set "… NULL only on a grant written before the column existed." pick a permission set defined in Setup; an unknown name is rejected
last_certified_at, certified_by (both objects) "Reserved for a future access-recertification workflow … Inert today: no platform code writes this column …" not in use yet, kept for a future access-review feature; and hidden: true
sys_approval_delegation.valid_from "Enforced at resolution time via isGrantActive …" checked each time an approval is routed, no scheduled job
sys_notification_preference.digest "Batch cadence (P3 digest middleware)." what none / daily / weekly do, critical notifications are never batched, set it on a * channel row
sys_notification_preference.quiet_hours "Optional { tz, start, end } window (P3 quiet-hours middleware)." an example value, HH:MM in the time zone, may wrap midnight, critical not held, * channel row
sys_user.ai_access, sys_user.locale "… plugin-hono-server resolveCtx … AiSeatPlugin … Owned by objectql (better-auth is oblivious to this column)." what the seat gives and that the license caps it; the language tag and its fallback
sys_oauth_access_token / _refresh_token / _consent / _client_resource reference fields "Foreign key to sys_user.id" (and to sys_oauth_application.client_id, sys_session.id, sys_oauth_refresh_token.id, sys_oauth_resource.identifier) which user, application, session, refresh token or resource it is
sys_metadata.package_version_id "Foreign key to sys_package_version (UUID). …" the package release the metadata came from, empty for built-in and local changes
Data Lifecycle settings page and its Retention overrides help "Governance for ADR-0057 … LifecycleService (Reaper / Rotator / Archiver)", "(ADR-0057 §3.2)" what the page controls and that the periodic cleanup sweep applies it

The behaviour claims in the new digest and quiet-hours help were read from service-messaging/src/preference-resolver.ts (resolveDigest / resolveQuietHours read only the channel * row; critical bypasses both; digestDeferral flushes at local midnight and Monday 00:00).

Hidden, not deleted. last_certified_at and certified_by on sys_user_permission_set and sys_user_position now carry hidden: true, the field's own "Hidden from default UI" flag. objectui's form auto-layout (plugin-form/src/autoLayout.ts) and the record detail panel (plugin-detail/src/RecordDetailPanel.tsx) both skip a hidden field. The columns, their stored values and the API are unchanged. No other field's help says it is inert.

Bundles. en regenerated from the sources (node scripts/check-i18n-bundles.mjs --write). The zh-CN, ja-JP and es-ES values of every rewritten leaf were translated by hand (they were translations of the old developer text, or for the ja-JP / es-ES approvals and messaging leaves, byte copies of it). The generator then dropped the four source-hashes.generated.ts entries that recorded those byte copies, which is its documented behaviour once a leaf is translated. The AI Access help keeps the word "capability" (ai_seat capability, 能力 / ケイパビリティ): two translation-decision tests derive the capability wording from that leaf.

Pin. The four existing admin-copy vocabulary tests (platform-objects setup-copy-vocabulary.test.ts, plugin-security, plugin-approvals, service-messaging admin-copy-vocabulary.test.ts) gain five entries: a foreign-key note, the isGrantActive function name, an internal component (middleware, "better-auth is oblivious", Reaper), the "NULL only on" storage note and the "Inert today" notice, each with a positive control. They walk every object this package ships and every leaf of all four locale bundles. plugin-security's test also asserts the four access-review fields are hidden. The settings manifest had no copy test, so objectql/src/lifecycle/lifecycle-settings.test.ts is new (ADR number, section reference, internal component names).

Surface note: one string outside the declared surface

packages/metadata-core/src/objects/sys-metadata.object.ts (package_version_id help) is outside the claim's file surface. It is the same defect class, a one-line mechanical rewrite, and it is in the population platform-objects' vocabulary test already walks (that test reads metadata-core's objects, and the help lands in the platform-objects bundle), so the new "foreign key" entry could not go green without it. Taken under os-dev's bounded in-place fix; the seat amends the file surface.

Verification (head ee5da23123)

  • pnpm turbo run test --only --continue on the six packages: metadata-core 19/19 files, platform-objects 88/88, plugin-security 212/212, plugin-approvals 94/94, service-messaging 60/60, objectql 465/465 (lock VERDICT command-exit 0). A first run went red in two platform-objects translation-decision tests that read sys_user.fields.ai_access.help as evidence for the capability wording; fixed by keeping the capability in that help.
  • pnpm turbo run typecheck --only on the six packages: 6/6 (VERDICT command-exit 0).
  • node scripts/check-i18n-bundles.mjs: all ten packages in sync.
  • dispatch-gates --commands: 71 families, 70 exit 0, 1 NOT MEASURED (check:dual-build-cjs-loads exit 3, PREREQUISITE NOT MET: this worktree has no full workspace build). --ran reconciles 71/71. CI runs the rest of the farm.
  • No ablation: the change is copy and a declared flag; each new vocabulary entry carries a positive-control assertion that it matches the old string.

Acceptance notes

🤖 Generated with Claude Code

https://claude.ai/code/session_01RsXNmkeex9WY5XsjNwtRYv

…aging, objectql): Setup field help written for administrators; the inert access-review pair hidden

Claude-Session: https://claude.ai/code/session_01RsXNmkeex9WY5XsjNwtRYv
Co-authored-by: Claude <noreply@anthropic.com>
…eld help in zh-CN, ja-JP and es-ES

Claude-Session: https://claude.ai/code/session_01RsXNmkeex9WY5XsjNwtRYv
Co-authored-by: Claude <noreply@anthropic.com>
…elp, the evidence the capability wording is derived from

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 6 package(s): @objectstack/metadata-core, @objectstack/objectql, @objectstack/platform-objects, @objectstack/plugin-approvals, @objectstack/plugin-security, @objectstack/service-messaging, touching 21 documentable anchor(s).

24 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 fb63d396b15c91f3f16041817e9934e2dea93759.

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

What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: sys_user (symbol, 42 pages)
  • 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 — 34 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 fb63d396b15c91f3f16041817e9934e2dea93759 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from fd77bc1452d1c8769c8421b9d04498921ba3a503 — the merge of head ee5da23123ab035c1916fa9055da5dd748d36373 into base fb63d396b15c91f3f16041817e9934e2dea93759, 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 fd77bc1452d1c8769c8421b9d04498921ba3a503 && git checkout fd77bc1452d1c8769c8421b9d04498921ba3a503
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin fb63d396b15c91f3f16041817e9934e2dea93759 ee5da23123ab035c1916fa9055da5dd748d36373 && git checkout -B drift-repro fb63d396b15c91f3f16041817e9934e2dea93759 && git merge --no-ff ee5da23123ab035c1916fa9055da5dd748d36373

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

⚠️ 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 fb63d396b15c91f3f16041817e9934e2dea93759 → 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

席位核对

ACCEPT · domain:engine seat 1 · os-tesla · session_014Hse9cj2i4o5UAVrd21NKr · 2026-10-23T05:13Z · head ee5da2312 · #25331 (Fixes)

  • Shape: 37 files, +292 / −148. Admin-facing field help is rewritten across platform-objects, metadata-core, plugin-security, plugin-approvals, service-messaging and the objectql Data Lifecycle settings. Four last_certified_at / certified_by fields gain hidden: true. The bundles are regenerated or hand-translated, and vocabulary pins are extended in four packages plus one new pin. Read from the diff. NOT GOVERNED, under the 3000-line threshold. Clause-② no: copy and an existing display flag. The columns, stored values and API are unchanged.
  • Cross-lane: the services files (plugin-security, plugin-approvals, service-messaging) were declared on [PM seat] domain:services — 🟢 os-sales #6021 before this PR, and no objection was posted.
  • Gates: 41 check-runs on ee5da2312: 34 success, 7 skipped (opt-in or path-filtered), 0 failed. The dev's one NOT-MEASURED gate (check:dual-build-cjs-loads) is covered by CI's Lint & Repo Gates, green.
  • Pins: each new vocabulary entry (foreign-key note, isGrantActive, internal component names, "NULL only on", "Inert today") walks every shipped object and all four locale bundles, and carries a positive control that it matches the old string. plugin-security also pins the four access-review fields as hidden. Ablation is not applicable: this is copy, and the positive controls stand in.
  • Premise measured by the dev: the digest and quiet-hours help were read from service-messaging/src/preference-resolver.ts (* channel row only, critical bypasses both).
  • Accepted deviation: metadata-core/src/objects/sys-metadata.object.ts (package_version_id help) is outside the claimed file surface. It is the same defect class, one line, and in the population the platform-objects pin already walks. The seat amends the surface to include it.
  • Out of scope, noted and not filed: 34 better-auth mentions and a few code identifiers in other platform-objects help. The [ADR-0086 D3] string lives only in packages/spec .describe() text, and whether the Capabilities page renders it was not measured.
  • Serial: Setup forms show machine values as option text (cost_center, business_unit, unit_and_subordinates, autoMigrate) and labels followed by their machine key ("Display name* name") — show labelled options only (hotcrm#2194 T2-U03) #25332 (PR fix(platform-objects, plugin-sharing, spec): Setup forms show option labels instead of machine values #25370) regenerates the same platform-objects bundles. The second to land merges main and re-runs the generator.
  • Landing: the seat marks it ready and enables auto-merge; the merge queue lands it.

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/m tests tooling

Projects

None yet

2 participants