Skip to content

Commit 30ce56e

Browse files
fix(platform-objects,metadata-core,service-messaging): Setup descriptions are plain admin sentences; ADR references move to the docblocks (#23845)
Fixes #23802 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`. Both reach every locale through the generated translation bundles. This PR rewrites the Setup-visible object descriptions in the admin's words and moves every ADR number, decision id and API call out of the strings in this lane's packages and into the docblock or a comment beside the string (the card's constraint: docblocks and ADR links in code stay, only user-facing strings move). Wording only: no field, index, permission or behaviour change. Scope at the claim: `packages/platform-objects`, `packages/metadata-core/src/objects/sys-metadata*.object.ts` and `packages/services/service-messaging/src/objects/*.object.ts`. The descriptions produced in `plugin-approvals`, `plugin-security`, `service-automation`, `plugin-sharing` and `packages/spec/src/ui/view.form.ts` (the permission set `organization_admin_no_bypass`, Record Shares, Approval Delegations) belong to #23829, which remains open and is untouched here. ## Before / after Measured by loading the BUILT object definitions of the three packages (61 objects; multi-line values included) and matching the card's patterns (`ADR-` followed by a digit, a decision id such as D2, `finding F`, `emit()`, `kernel`). Before, at base `1ecb08a1c`: 15 distinct strings matched (17 rows; two metadata-core strings appear twice because platform-objects re-exports them). After, at `a6586f72a`: 0. Object descriptions on a Setup page, rewritten (the last two carried schema vocabulary and no pattern): | Object (Setup nav entry) | Before | After | |---|---|---| | `sys_business_unit` (People and Organization, Business Units) | Canonical Business Unit tree — hierarchical org/data-partition node (company / division / department / region / office). ADR-0057 D2. | Your company structure — divisions, departments, regions and offices — used to scope data and reports. | | `sys_notification` (Diagnostics, Notification Events) | Notification events — one row per emit() (ADR-0030 Layer 2 ingress) | Every notification the platform sent, one row per event. | | `sys_http_delivery` (Integrations, HTTP Deliveries) | Durable outbox row for one outbound-HTTP attempt (ADR-0018). Managed by @objectstack/service-messaging; do not write directly. | Outgoing HTTP calls made by webhooks and flows, one row per call, with its delivery status. | | `sys_notification_preference` (Configuration, Notification Preferences) | Per-user × topic × channel notification toggle (mute/allow), with admin-global defaults. | Which topics and channels each user receives; admins set the defaults. | | `sys_notification_template` (Configuration, Notification Templates) | Per (topic × channel × locale) render template for notifications. | The subject and body each notification topic sends, per channel and language. | Field help on Setup forms: the ADR reference is removed and the rest of the help text is unchanged, because it is operational detail an admin acts on. - `sys_user.role`: "(ADR-0068 D2)" removed - `sys_user.manager_id`: "(ADR-0057 / @objectstack/security-enterprise)" removed - `sys_user.primary_business_unit_id`: "(ADR-0057 addendum D12)" removed - `sys_organization.parent_organization_id`: "(ADR-0105 D6)" removed - `sys_invitation.business_unit_id` and `sys_invitation.positions`: "(ADR-0105 D8)" removed - `sys_sso_provider.domain_verified` (Access Control, SSO Providers): "(ADR-0135 D6)" removed Judged NOT Setup-visible (no Setup nav entry in any of the 12 contributors that declare `app: 'setup'`, and not the subject of a Setup record page); the ADR reference is removed and the wording is otherwise kept: - `sys_metadata_audit` (metadata-core): "(ADR-0010)" removed - `sys_metadata_commit` (metadata-core; in no translation bundle): "(ADR-0067)" removed - `sys_metadata.environment_id` (metadata-core): "(ADR-0131 D6)" removed - `sys_metadata_activation` (platform-objects; in no translation bundle): "(ADR-0126 §4)" removed. It backs the Packaged Automation page, which renders its own copy rather than this description. - `sys_notification_delivery` (service-messaging): "(ADR-0030 Layer 4)" removed They are edited anyway because they sit in the claimed file surface, three of them ship in the platform-objects bundles to every locale, and the test below then pins every object a package ships. No hand-kept Setup roster is needed, so it cannot go stale when a plugin adds a nav entry. Setup nav labels and the `SETUP_APP` description carried none of the patterns. No nav string changed. ## Translations: what the generator required `os i18n extract` (run for all nine bundle sets by `node scripts/check-i18n-bundles.mjs --write`, which reads each package's documented command) rewrites the `en` bundle from source on every run. It keeps any non-empty translated-locale value (merge mode). A translated leaf whose source moved is therefore NOT updated by the generator. Its own generated header says to re-translate it by hand. So the order was: 1. platform-objects zh-CN / ja-JP / es-ES `objects` bundles: the 11 affected leaves re-translated in place (leaf values only, no key added or removed). None of them had a recorded source hash, so the provenance tables did not move. 2. service-messaging zh-CN: the 4 affected descriptions re-translated in place. 3. service-messaging ja-JP / es-ES: these bundles are untranslated English fills with recorded provenance, so the 4 stale fills were emptied and the generator re-filled them from the new source. It refreshed their entries in `ja-JP` / `es-ES.source-hashes.generated.ts` itself. If they had been left alone, both locales would have kept a byte-identical superseded draft, which `check:i18n-stale-fill` exists to catch. 4. `check-i18n-bundles --write` regenerated the `en` bundles and the hash tables. `pnpm check:i18n` and `pnpm check:i18n-stale-fill` are green after it. ## Acceptance 1: tests in the packages' own suites No new `check:*` script, lint rule or CI wiring. - `packages/platform-objects/src/apps/setup-copy-vocabulary.test.ts` covers four populations: every object this package and `@objectstack/metadata-core` export (each `label` / `pluralLabel` / `description` anywhere in the definition); every leaf of the four `objects` bundles; the type-level `label` / `description` of the four `metadataForms` bundles (the sentence a Setup metadata page such as Capabilities shows); and `SETUP_APP` plus `SETUP_NAV_CONTRIBUTIONS` plus each locale's `apps.setup` subtree. It also has a positive control showing the matcher recognises each kind of vocabulary. - `packages/services/service-messaging/src/objects/admin-copy-vocabulary.test.ts` applies the same rule to every messaging object and its four bundles. platform-objects cannot import service-messaging, and no dependency was added for a test. - Patterns are case-sensitive except `kernel`. The decision-id pattern uses word boundaries and matched no legitimate text in any population. The one lower-case hit in the instrument run, `adr-0104-file-references` (a migration id inside `sys_migration.id`'s help), is a machine id; the case-sensitive pattern does not match it. Ablation: four legs through `scripts/ablation-replace.mjs`, each restored with blob hash equal to HEAD and an empty `git diff HEAD`. - (A) an ADR reference re-added to the Business Units source description turned the object test red, naming `sys_business_unit.description`. - (B) the old `emit()` / ADR sentence put back into the zh-CN bundle turned the zh-CN bundle test red. - (C) an ADR reference added to the messaging preference description turned the messaging object test red. - (D) an ADR reference added to `sys_metadata_commit`, with metadata-core rebuilt, turned the object test red. `ablation-dist-preflight` confirmed the marker was present in 4 dist files. Restore leg: rebuild, then `--absent` confirmed the marker gone from all 12 dist files with a clean tree, and the suite was green again. ## Local verification (HEAD `a6586f72a`) - `pnpm --filter @objectstack/platform-objects test`: 71 files, 1103 tests passed. - `pnpm --filter @objectstack/service-messaging test`: 51 files, 574 passed. - `pnpm --filter @objectstack/metadata-core test`: 18 files, 733 passed (run at `3b5ffa17f`; nothing in metadata-core changed after it). - `typecheck` for all three packages: exit 0. Both new test files are in their tsc programs (counted with `--listFiles`). - `pnpm check:i18n`, `pnpm check:i18n-stale-fill` and `pnpm check:i18n-coverage`: exit 0. - Derived gate list (`dispatch-gates --commands`, 66 families): 65 exit 0. `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 is NOT MEASURED locally and left to CI. `--ran` reconciliation: 66 derived, 65 run, 1 NOT-MEASURED, 0 UNRUN. ## Acceptance notes - `sys_notification_subscription` keeps its description ("Standing subscription of a principal (role/team/user) to a notification topic."). Its docblock records that the subscription-to-recipient expansion is not wired, so the Setup grid is admin-authored data, not routing. Any user-voice sentence of the "who receives this topic" kind would advertise behaviour the runtime does not deliver. - Not Setup-visible, schema vocabulary, no pattern, left as is: `sys_inbox_message`, `sys_notification_receipt` ("Per-recipient × channel receipt …") and `sys_business_unit_member` (shown only as a related list, which renders the label). - `SETUP_APP.protection.reason` ("… see ADR-0010.") is a lock reason, not a nav label or description. Not edited. - Out of this lane, reported to the PM rather than edited: - Setup's Permission Sets and Positions forms show spec form help that carries ADR numbers. Producers: `packages/spec/src/security/permission.form.ts` (`isDefault`, `managedBy`, `packageId`, `adminScope`) and `packages/spec/src/identity/position.form.ts` (`delegatable`). - The "Installed Apps" note the card quotes is produced in objectui (`packages/i18n/src/locales/*.ts`, key `installedAdditiveNote`, rendered by `InstalledListWidget.tsx`), not by `cloud-connection`. - The Studio-only metadata-form help texts in the same bundles (object, field, view, action, agent, skill) also carry ADR numbers. They are spec copy outside Setup and were not judged here. --- _Generated by [Claude Code](https://claude.ai/code/session_01TQLy3Yq6vF4SDpTXdr3Uwi)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1eac7ad commit 30ce56e

27 files changed

Lines changed: 424 additions & 86 deletions

‎.changeset/23802-setup-copy.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@objectstack/platform-objects': patch
3+
'@objectstack/metadata-core': patch
4+
'@objectstack/service-messaging': patch
5+
---
6+
7+
Clause-②: no
8+
9+
Setup pages describe their records in plain admin sentences. Business Units now reads "Your
10+
company structure — divisions, departments, regions and offices — used to scope data and
11+
reports.", Notification Events "Every notification the platform sent, one row per event.",
12+
Notification Preferences "Which topics and channels each user receives; admins set the
13+
defaults.", Notification Templates "The subject and body each notification topic sends, per
14+
channel and language." and HTTP Deliveries "Outgoing HTTP calls made by webhooks and flows, one
15+
row per call, with its delivery status." Field help on Users, Organizations, Invitations and SSO
16+
Providers, and the metadata-storage and notification-delivery object descriptions, no longer
17+
carry design-record numbers; those references stay in the code comments. The zh-CN, ja-JP and
18+
es-ES translations follow. Wording only: no field, permission or behaviour changes.

‎packages/metadata-core/src/objects/sys-metadata-audit.object.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ export const SysMetadataAuditObject = ObjectSchema.create({
4545
retention: { maxAge: '365d' },
4646
archive: { after: '365d', to: 'archive' },
4747
},
48-
description: 'Append-only audit trail of metadata write decisions (ADR-0010).',
48+
// ADR-0010 — the reference lives in the docblock above, not in the copy.
49+
description: 'Append-only audit trail of metadata write decisions.',
4950

5051
fields: {
5152
/** Primary Key (UUID) */

‎packages/metadata-core/src/objects/sys-metadata-commit.object.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ export const SysMetadataCommitObject = ObjectSchema.create({
2828
icon: 'git-commit',
2929
isSystem: true,
3030
managedBy: 'engine-owned',
31-
description: 'Package-scoped commit log grouping a turn’s metadata changes (ADR-0067).',
31+
// ADR-0067 — the reference lives in the docblock above, not in the copy.
32+
description: 'Package-scoped commit log grouping a turn’s metadata changes.',
3233

3334
fields: {
3435
/**

‎packages/metadata-core/src/objects/sys-metadata.object.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ export const SysMetadataObject = ObjectSchema.create({
158158
environment_id: Field.lookup('sys_environment', {
159159
label: 'Environment (deprecated)',
160160
required: false,
161-
description: 'DEPRECATED. Overlays are environment rows (ADR-0131 D6); no tenant column.',
161+
// ADR-0131 D6 — overlays are environment rows.
162+
description: 'DEPRECATED. Overlays are environment rows; no tenant column.',
162163
}),
163164

164165
/** Version number for optimistic concurrency */
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* Setup copy carries no design-record vocabulary.
5+
*
6+
* An administrator reads three kinds of string this package ships: the
7+
* sentence under a Setup page title (the object's `description`), a field's
8+
* help tooltip (the field's `description`, extracted as `help`), and the Setup
9+
* left nav (`SETUP_APP` plus `SETUP_NAV_CONTRIBUTIONS`). The generated bundles
10+
* carry the same strings into every locale. An ADR number, a decision id
11+
* ("D2"), a review-finding id ("finding F2"), an API call ("emit()") or a
12+
* runtime internal ("kernel") means nothing to that reader: the reference
13+
* belongs in the docblock or comment next to the string, never in the string.
14+
*
15+
* Population, all of it read from this checkout's source (no build artifact
16+
* except `@objectstack/metadata-core`, a registered unaliased pair in
17+
* `scripts/check-test-source-alias.mjs`):
18+
*
19+
* 1. every object schema this package exports, plus every one
20+
* `@objectstack/metadata-core` exports (`sys_metadata_commit` included,
21+
* which no bundle carries) — each `label`, `pluralLabel` and
22+
* `description` anywhere in the definition;
23+
* 2. every leaf of the four committed `objects` bundles;
24+
* 3. the type-level `label` / `description` of the four `metadataForms`
25+
* bundles — the sentence a Setup metadata page (Positions, Capabilities,
26+
* Permission Sets) shows under its title. Section descriptions and field
27+
* `helpText` of those forms are the spec's form copy and are not judged
28+
* here;
29+
* 4. `SETUP_APP` and this package's `SETUP_NAV_CONTRIBUTIONS`, and the
30+
* hand-authored `apps.setup` subtree of each locale.
31+
*
32+
* Nav entries other packages contribute, and the service-messaging objects,
33+
* are outside this package's import graph; `service-messaging` pins its own
34+
* objects in `src/objects/admin-copy-vocabulary.test.ts`.
35+
*/
36+
37+
import { describe, expect, it } from 'vitest';
38+
import * as MetadataCore from '@objectstack/metadata-core';
39+
import * as PlatformObjects from '../index.js';
40+
import { SETUP_APP } from './setup.app.js';
41+
import { SETUP_NAV_CONTRIBUTIONS } from './setup-nav.contributions.js';
42+
import { en } from './translations/en.js';
43+
import { zhCN } from './translations/zh-CN.js';
44+
import { jaJP } from './translations/ja-JP.js';
45+
import { esES } from './translations/es-ES.js';
46+
import { enObjects } from './translations/en.objects.generated.js';
47+
import { zhCNObjects } from './translations/zh-CN.objects.generated.js';
48+
import { jaJPObjects } from './translations/ja-JP.objects.generated.js';
49+
import { esESObjects } from './translations/es-ES.objects.generated.js';
50+
import { enMetadataForms } from './translations/en.metadata-forms.generated.js';
51+
import { zhCNMetadataForms } from './translations/zh-CN.metadata-forms.generated.js';
52+
import { jaJPMetadataForms } from './translations/ja-JP.metadata-forms.generated.js';
53+
import { esESMetadataForms } from './translations/es-ES.metadata-forms.generated.js';
54+
55+
/** The design-record vocabulary an admin-facing string must not carry. */
56+
const DESIGN_RECORD_VOCABULARY: ReadonlyArray<readonly [string, RegExp]> = [
57+
['an ADR number', /ADR-\d/],
58+
['a decision id', /\bD\d+\b/],
59+
['a review-finding id', /finding F/],
60+
['an API call', /\bemit\(\)/],
61+
['a runtime internal', /\bkernel\b/i],
62+
];
63+
64+
function vocabularyIn(text: string): string[] {
65+
return DESIGN_RECORD_VOCABULARY.filter(([, re]) => re.test(text)).map(([name]) => name);
66+
}
67+
68+
const COPY_KEYS = new Set(['label', 'pluralLabel', 'description']);
69+
70+
/** Every `label` / `pluralLabel` / `description` string under `node`, with its path. */
71+
function copyStrings(node: unknown, path: string, out: Array<[string, string]>): void {
72+
if (Array.isArray(node)) {
73+
node.forEach((v, i) => copyStrings(v, `${path}[${i}]`, out));
74+
return;
75+
}
76+
if (!node || typeof node !== 'object') return;
77+
for (const [k, v] of Object.entries(node)) {
78+
const at = path ? `${path}.${k}` : k;
79+
if (typeof v === 'string') {
80+
if (COPY_KEYS.has(k)) out.push([at, v]);
81+
} else {
82+
copyStrings(v, at, out);
83+
}
84+
}
85+
}
86+
87+
/** Every string leaf under `node`, with its path. */
88+
function leafStrings(node: unknown, path: string, out: Array<[string, string]>): void {
89+
if (typeof node === 'string') {
90+
out.push([path, node]);
91+
return;
92+
}
93+
if (!node || typeof node !== 'object') return;
94+
for (const [k, v] of Object.entries(node)) leafStrings(v, path ? `${path}.${k}` : k, out);
95+
}
96+
97+
function offenders(strings: Array<[string, string]>): string[] {
98+
return strings
99+
.map(([at, text]) => [at, text, vocabularyIn(text)] as const)
100+
.filter(([, , hits]) => hits.length > 0)
101+
.map(([at, text, hits]) => `${at} (${hits.join(', ')}): ${text}`);
102+
}
103+
104+
type ObjectLike = { name: string; fields: Record<string, unknown> };
105+
function isObjectSchema(v: unknown): v is ObjectLike {
106+
return !!v && typeof v === 'object'
107+
&& typeof (v as ObjectLike).name === 'string'
108+
&& !!(v as ObjectLike).fields && typeof (v as ObjectLike).fields === 'object';
109+
}
110+
111+
function objectSchemas(...modules: Array<Record<string, unknown>>): Map<string, ObjectLike> {
112+
const byName = new Map<string, ObjectLike>();
113+
for (const mod of modules) {
114+
for (const v of Object.values(mod)) if (isObjectSchema(v) && !byName.has(v.name)) byName.set(v.name, v);
115+
}
116+
return byName;
117+
}
118+
119+
const LOCALES = { en, 'zh-CN': zhCN, 'ja-JP': jaJP, 'es-ES': esES } as const;
120+
const OBJECT_BUNDLES = { en: enObjects, 'zh-CN': zhCNObjects, 'ja-JP': jaJPObjects, 'es-ES': esESObjects } as const;
121+
const FORM_BUNDLES = {
122+
en: enMetadataForms, 'zh-CN': zhCNMetadataForms, 'ja-JP': jaJPMetadataForms, 'es-ES': esESMetadataForms,
123+
} as const;
124+
125+
describe('Setup copy carries no design-record vocabulary', () => {
126+
it('the matcher recognises each kind of vocabulary it exists to keep out', () => {
127+
// A matcher that matches nothing passes every assertion below; each kind
128+
// must be seen on a sentence of the shape it was written for.
129+
expect(vocabularyIn('Business Unit tree (ADR-0057).')).toEqual(['an ADR number']);
130+
expect(vocabularyIn('Placement intent, decision D12.')).toEqual(['a decision id']);
131+
expect(vocabularyIn('Bypass rule (finding F2).')).toEqual(['a review-finding id']);
132+
expect(vocabularyIn('One row per emit().')).toEqual(['an API call']);
133+
expect(vocabularyIn('The Kernel API is additive.')).toEqual(['a runtime internal']);
134+
expect(vocabularyIn('Your company structure, used to scope data and reports.')).toEqual([]);
135+
});
136+
137+
it('object, field and view copy of every object this package and metadata-core export', () => {
138+
const objects = objectSchemas(
139+
PlatformObjects as unknown as Record<string, unknown>,
140+
MetadataCore as unknown as Record<string, unknown>,
141+
);
142+
// The population is not allowed to shrink to nothing: the objects whose
143+
// copy this suite was written against must still be in it.
144+
for (const name of [
145+
'sys_user', 'sys_business_unit', 'sys_notification', 'sys_sso_provider',
146+
'sys_metadata', 'sys_metadata_audit', 'sys_metadata_commit', 'sys_metadata_activation',
147+
]) {
148+
expect(objects.has(name), `${name} is in the population`).toBe(true);
149+
}
150+
expect(objects.size).toBeGreaterThanOrEqual(50);
151+
152+
const strings: Array<[string, string]> = [];
153+
for (const [name, def] of objects) copyStrings(def, name, strings);
154+
expect(offenders(strings)).toEqual([]);
155+
});
156+
157+
it.each(Object.keys(OBJECT_BUNDLES))('every leaf of the %s objects bundle', (locale) => {
158+
const strings: Array<[string, string]> = [];
159+
leafStrings(OBJECT_BUNDLES[locale as keyof typeof OBJECT_BUNDLES], `objects`, strings);
160+
expect(strings.length).toBeGreaterThan(1000);
161+
expect(offenders(strings)).toEqual([]);
162+
});
163+
164+
it.each(Object.keys(FORM_BUNDLES))('the type-level label and description of the %s metadataForms bundle', (locale) => {
165+
const forms = FORM_BUNDLES[locale as keyof typeof FORM_BUNDLES] as Record<string, { label?: string; description?: string }>;
166+
const strings: Array<[string, string]> = [];
167+
for (const [type, form] of Object.entries(forms)) {
168+
if (typeof form.label === 'string') strings.push([`metadataForms.${type}.label`, form.label]);
169+
if (typeof form.description === 'string') strings.push([`metadataForms.${type}.description`, form.description]);
170+
}
171+
expect(forms.capability?.description, 'the Capability page sentence is in the population').toBeTypeOf('string');
172+
expect(offenders(strings)).toEqual([]);
173+
});
174+
175+
it('the Setup app, its nav contributions, and every locale\'s apps.setup translations', () => {
176+
const strings: Array<[string, string]> = [];
177+
copyStrings(SETUP_APP, 'SETUP_APP', strings);
178+
copyStrings(SETUP_NAV_CONTRIBUTIONS, 'SETUP_NAV_CONTRIBUTIONS', strings);
179+
for (const [locale, data] of Object.entries(LOCALES)) {
180+
leafStrings(data.apps?.setup, `${locale}.apps.setup`, strings);
181+
}
182+
expect(strings.some(([at]) => at.endsWith('nav_business_units.label'))).toBe(true);
183+
expect(offenders(strings)).toEqual([]);
184+
});
185+
});

‎packages/platform-objects/src/apps/translations/en.objects.generated.ts‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
3535
},
3636
role: {
3737
label: "Platform Role",
38-
help: "Legacy better-auth role scalar (admin, user, …). ObjectStack no longer writes it (ADR-0068 D2). To grant platform-admin standing, list the user's verified email in `OS_PLATFORM_OWNER_EMAIL`; under the `single` tenancy posture an unscoped `admin_full_access` assignment in `sys_user_permission_set` also confers it."
38+
help: "Legacy better-auth role scalar (admin, user, …). ObjectStack no longer writes it. To grant platform-admin standing, list the user's verified email in `OS_PLATFORM_OWNER_EMAIL`; under the `single` tenancy posture an unscoped `admin_full_access` assignment in `sys_user_permission_set` also confers it."
3939
},
4040
banned: {
4141
label: "Banned",
@@ -97,11 +97,11 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
9797
},
9898
manager_id: {
9999
label: "Manager",
100-
help: "This user's direct manager. Forms the reporting chain the `own_and_reports` hierarchy scope walks (ADR-0057 / @objectstack/security-enterprise)."
100+
help: "This user's direct manager. Forms the reporting chain the `own_and_reports` hierarchy scope walks."
101101
},
102102
primary_business_unit_id: {
103103
label: "Primary Business Unit",
104-
help: "The user's primary business unit — a denormalised projection of sys_business_unit_member.is_primary, maintained by plugin-sharing (ADR-0057 addendum D12). Lets a user-lookup filter candidates by business unit without traversing the membership junction. Do not edit directly; set it via business-unit membership."
104+
help: "The user's primary business unit — a denormalised projection of sys_business_unit_member.is_primary, maintained by plugin-sharing. Lets a user-lookup filter candidates by business unit without traversing the membership junction. Do not edit directly; set it via business-unit membership."
105105
},
106106
source: {
107107
label: "Identity Source",
@@ -537,7 +537,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
537537
},
538538
parent_organization_id: {
539539
label: "Parent Organization",
540-
help: "Reporting/grouping parent. Grants NOTHING — visibility across organizations comes from membership, never from this reference (ADR-0105 D6)."
540+
help: "Reporting/grouping parent. Grants NOTHING — visibility across organizations comes from membership, never from this reference."
541541
},
542542
sort_order: {
543543
label: "Sort Order",
@@ -710,11 +710,11 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
710710
},
711711
business_unit_id: {
712712
label: "Placement Business Unit",
713-
help: "Business unit the invitee is placed under on acceptance (ADR-0105 D8). Must lie inside the issuer's delegated subtree."
713+
help: "Business unit the invitee is placed under on acceptance. Must lie inside the issuer's delegated subtree."
714714
},
715715
positions: {
716716
label: "Placement Positions",
717-
help: "Position names assigned on acceptance (ADR-0105 D8). Every position's permission sets must be allowlisted by the issuer's adminScope."
717+
help: "Position names assigned on acceptance. Every position's permission sets must be allowlisted by the issuer's adminScope."
718718
}
719719
},
720720
_views: {
@@ -848,7 +848,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
848848
sys_business_unit: {
849849
label: "Business Unit",
850850
pluralLabel: "Business Units",
851-
description: "Canonical Business Unit tree — hierarchical org/data-partition node (company / division / department / region / office). ADR-0057 D2.",
851+
description: "Your company structure — divisions, departments, regions and offices — used to scope data and reports.",
852852
fields: {
853853
name: {
854854
label: "Name"
@@ -1797,7 +1797,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
17971797
},
17981798
domain_verified: {
17991799
label: "Domain Verified",
1800-
help: "Whether DNS ownership of the email domain has been proven (ADR-0135 D6). Set by “Verify Domain” after the DNS TXT record resolves. Managed by better-auth — not directly editable. Only enforced when domain verification is enabled for the environment."
1800+
help: "Whether DNS ownership of the email domain has been proven. Set by “Verify Domain” after the DNS TXT record resolves. Managed by better-auth — not directly editable. Only enforced when domain verification is enabled for the environment."
18011801
},
18021802
oidc_config: {
18031803
label: "OIDC Config",
@@ -2356,7 +2356,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
23562356
sys_notification: {
23572357
label: "Notification Event",
23582358
pluralLabel: "Notification Events",
2359-
description: "Notification events — one row per emit() (ADR-0030 Layer 2 ingress)",
2359+
description: "Every notification the platform sent, one row per event.",
23602360
fields: {
23612361
id: {
23622362
label: "Notification ID"
@@ -2984,7 +2984,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
29842984
},
29852985
environment_id: {
29862986
label: "Environment (deprecated)",
2987-
help: "DEPRECATED. Overlays are environment rows (ADR-0131 D6); no tenant column."
2987+
help: "DEPRECATED. Overlays are environment rows; no tenant column."
29882988
},
29892989
version: {
29902990
label: "Version"
@@ -3090,7 +3090,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
30903090
sys_metadata_audit: {
30913091
label: "Metadata Audit",
30923092
pluralLabel: "Metadata Audit",
3093-
description: "Append-only audit trail of metadata write decisions (ADR-0010).",
3093+
description: "Append-only audit trail of metadata write decisions.",
30943094
fields: {
30953095
id: {
30963096
label: "ID"

0 commit comments

Comments
 (0)