Skip to content

Commit 85fb81c

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-23829-setup-copy-services
2 parents 9cc38b6 + 497518c commit 85fb81c

13 files changed

Lines changed: 140 additions & 49 deletions
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/spec': patch
3+
'@objectstack/platform-objects': patch
4+
---
5+
6+
Clause-②: no
7+
8+
Six help texts an administrator reads in Setup no longer carry ADR numbers. On the Permission Sets edit form,
9+
`isDefault`, `managedBy` and `packageId` are rewritten as plain sentences that say what the field does, and
10+
`adminScope` drops its "(ADR-0090 D12)" prefix. On the Positions edit form, `delegatable` drops "(ADR-0091 D3)".
11+
The view form's End-user controls description drops "(ADR-0047, Airtable Interface parity)".
12+
13+
The ADR references moved to the comments beside the form rows. The generated metadata-forms translations carry
14+
the new wording in en, zh-CN, ja-JP and es-ES. No key, type or accept/refuse result changes.

‎content/blog/context-window-is-the-constraint.mdx‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,25 @@ a dashboard, a lead-conversion flow, permission sets, an action, translations.
3838

3939
| | |
4040
| :--- | :--- |
41-
| Files | 31 |
42-
| Lines | 1,929 |
43-
| Approximate tokens | ~18,500 |
41+
| Files | 30 |
42+
| Lines | 1,844 |
43+
| Approximate tokens | ~17,500 |
4444

4545
That's the **whole example app**. Not a module of it — the data model, the
4646
UI, the automation, the access rules, all of it. It fits in about 9% of a
4747
200k-token context window.
4848

49-
The Todo example is ~24.5k tokens. The kitchen-sink showcase app — which
50-
deliberately exercises every metadata type in the protocol, 91 files of it — is
51-
~174k. Even that one, the maximalist case, still fits in a 200k-token window —
49+
The Todo example is ~25k tokens. The kitchen-sink showcase app — which
50+
deliberately exercises every metadata type in the protocol, 90 files of it — is
51+
~175k. Even that one, the maximalist case, still fits in a 200k-token window —
5252
about 87% of it, leaving about 13% free for the actual work.
5353

54+
These figures were measured at commit
55+
[`7a6ba0310`](https://github.com/objectstack-ai/objectstack/tree/7a6ba03109dbb7e91359eb0f7f3e64dd1263bca8/examples)
56+
over the non-test `.ts` files in each example's `src/`, with tokens estimated
57+
at four bytes each. The examples keep changing, so today's counts will differ a
58+
little.
59+
5460
Measure your own:
5561

5662
```bash

‎content/blog/the-ontology-is-the-software.mdx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ pages that is parsed into a UI tree and never executed as code.
116116
**The whole system becomes small enough to be held.** The bundled example CRM in
117117
this repository — accounts, contacts, leads, opportunities, activities, views, a
118118
dashboard, a lead-conversion flow, permission sets, actions, translations — is
119-
31 files and roughly 18,500 tokens. That is the whole application, not
120-
a module of it. An agent can load it end to end, answer *what breaks if I change
119+
30 files and roughly 17,500 tokens, measured at commit
120+
[`7a6ba0310`](https://github.com/objectstack-ai/objectstack/tree/7a6ba03109dbb7e91359eb0f7f3e64dd1263bca8/examples/app-crm).
121+
That is the whole application, not a module of it. An agent can load it end to end, answer *what breaks if I change
121122
this*, and refactor across data, API, UI, and permissions in a single change.
122123
We wrote about why that number is the one that matters in
123124
[The Constraint Isn't Typing Speed. It's the Context Window.](/blog/context-window-is-the-constraint)

‎content/docs/concepts/metadata-driven.mdx‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,15 @@ actions, translations):
228228

229229
| | |
230230
| :--- | :--- |
231-
| Files | 31 |
232-
| Lines | 1,929 |
233-
| Approximate tokens | ~18,500 |
231+
| Files | 30 |
232+
| Lines | 1,844 |
233+
| Approximate tokens | ~17,500 |
234234

235235
That's the **whole example app** — about 9% of a 200k-token context window.
236-
Count it yourself:
236+
These figures were measured at commit
237+
[`7a6ba0310`](https://github.com/objectstack-ai/objectstack/tree/7a6ba03109dbb7e91359eb0f7f3e64dd1263bca8/examples/app-crm),
238+
with tokens estimated at four bytes each. The example keeps changing, so count
239+
it yourself for today's numbers:
237240

238241
```bash
239242
find examples/app-crm/src -name '*.ts' -not -name '*.test.ts' | xargs cat | wc -l

‎content/docs/getting-started/how-ai-development-works.mdx‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ build the thing I actually meant?*
3434
A typical enterprise app spreads CRUD, forms, queries, permissions, and API glue
3535
across dozens of files. ObjectStack keeps only the part that's yours: the bundled
3636
example CRM — six objects, views, a dashboard, a lead-conversion flow,
37-
permission sets, actions, translations — is **1,929 lines across 31 files, about
38-
18.5k tokens**. That's the whole example app, not a module of it.
37+
permission sets, actions, translations — is **1,844 lines across 30 files, about
38+
17.5k tokens** (measured at commit
39+
[`7a6ba0310`](https://github.com/objectstack-ai/objectstack/tree/7a6ba03109dbb7e91359eb0f7f3e64dd1263bca8/examples/app-crm)).
40+
That's the whole example app, not a module of it.
3941

4042
The point isn't lines of code; it's **fit in an agent's context window.** When the
4143
entire business system is small, typed, and declarative, an agent can load it

‎packages/platform-objects/src/apps/setup-copy-vocabulary.test.ts‎

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
* 2. every leaf of the four committed `objects` bundles;
2424
* 3. the type-level `label` / `description` of the four `metadataForms`
2525
* 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;
26+
* Permission Sets) shows under its title, plus the six form leaves named
27+
* in `FORM_HELP_LEAVES` (the Permission Sets and Positions help texts and
28+
* the view form's End-user controls description). The other section
29+
* descriptions and field `helpText` of those forms are the spec's form
30+
* copy and are not judged here;
2931
* 4. `SETUP_APP` and this package's `SETUP_NAV_CONTRIBUTIONS`, and the
3032
* hand-authored `apps.setup` subtree of each locale.
3133
*
@@ -172,6 +174,55 @@ describe('Setup copy carries no design-record vocabulary', () => {
172174
expect(offenders(strings)).toEqual([]);
173175
});
174176

177+
// The help texts an admin reads on Setup's Permission Sets and Positions edit
178+
// forms, and the view form's End-user controls section. Each one carried a
179+
// decision-record reference until the spec form source moved it into the
180+
// comment beside the row; `en` is regenerated from that source, so judging
181+
// the four bundles judges the source too.
182+
const FORM_HELP_LEAVES = [
183+
['permission', 'fields', 'isDefault', 'helpText'],
184+
['permission', 'fields', 'managedBy', 'helpText'],
185+
['permission', 'fields', 'packageId', 'helpText'],
186+
['permission', 'fields', 'adminScope', 'helpText'],
187+
['position', 'fields', 'delegatable', 'helpText'],
188+
['view', 'sections', 'end_user_controls', 'description'],
189+
] as const;
190+
191+
function formHelpLeaves(bundle: unknown, locale: string): Array<[string, string]> {
192+
return FORM_HELP_LEAVES.map((path) => {
193+
const value = path.reduce<unknown>((node, key) => (node as Record<string, unknown> | undefined)?.[key], bundle);
194+
const at = `${locale}.metadataForms.${path.join('.')}`;
195+
expect(value, `${at} is in the population`).toBeTypeOf('string');
196+
return [at, value as string];
197+
});
198+
}
199+
200+
it.each(Object.keys(FORM_BUNDLES))('the Permission Set, Position and view form help texts of the %s metadataForms bundle', (locale) => {
201+
const strings = formHelpLeaves(FORM_BUNDLES[locale as keyof typeof FORM_BUNDLES], locale);
202+
expect(strings).toHaveLength(FORM_HELP_LEAVES.length);
203+
expect(offenders(strings)).toEqual([]);
204+
});
205+
206+
it('the form help-text assertion fires on the prose it replaced', () => {
207+
// Dark leg: the same walk over a bundle carrying the replaced wording must
208+
// name every leaf, so a walk that reaches nothing cannot pass above.
209+
const replaced = {
210+
permission: { fields: {
211+
isDefault: { helpText: 'App baseline for the everyone position (ADR-0090 D5): an app-level set is auto-bound at boot.' },
212+
managedBy: { helpText: 'Record provenance (ADR-0086 D3): who owns this set across upgrades.' },
213+
packageId: { helpText: 'Owning package id for a package-shipped set (ADR-0086 D3).' },
214+
adminScope: { helpText: 'Delegated administration (ADR-0090 D12): lets holders of this set administer one business-unit subtree.' },
215+
} },
216+
position: { fields: {
217+
delegatable: { helpText: 'Holders may delegate this position themselves, time-boxed and with a reason (ADR-0091 D3).' },
218+
} },
219+
view: { sections: {
220+
end_user_controls: { description: 'What end users can do on this view (ADR-0047, Airtable Interface parity).' },
221+
} },
222+
};
223+
expect(offenders(formHelpLeaves(replaced, 'replaced'))).toHaveLength(FORM_HELP_LEAVES.length);
224+
});
225+
175226
it('the Setup app, its nav contributions, and every locale\'s apps.setup translations', () => {
176227
const strings: Array<[string, string]> = [];
177228
copyStrings(SETUP_APP, 'SETUP_APP', strings);

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ export const enMetadataForms: NonNullable<TranslationData['metadataForms']> = {
10191019
},
10201020
end_user_controls: {
10211021
label: "End-user controls",
1022-
description: "What end users can do on this view — quick filters, filter tabs, visualization switching (ADR-0047, Airtable Interface parity)."
1022+
description: "What end users can do on this view — quick filters, filter tabs, visualization switching."
10231023
},
10241024
navigation_sharing: {
10251025
label: "Navigation & sharing",
@@ -2330,23 +2330,23 @@ export const enMetadataForms: NonNullable<TranslationData['metadataForms']> = {
23302330
},
23312331
isDefault: {
23322332
label: "Is Default",
2333-
helpText: "App baseline for the everyone position (ADR-0090 D5): an app-level set is auto-bound at boot; a package-level set becomes an install-time suggestion an admin confirms. Default false."
2333+
helpText: "Gives this set to everyone who signs in, through the built-in everyone position. A set the app itself declares is granted at startup; a set from an installed package becomes a suggestion an admin confirms in Setup. A set with high-privilege permissions is never granted this way. Default false."
23342334
},
23352335
managedBy: {
23362336
label: "Managed By",
2337-
helpText: "Record provenance (ADR-0086 D3): who owns this set across upgrades."
2337+
helpText: "Who owns this set: Package means it ships with a package and package upgrades update it; Platform and User mean it was created in this environment and upgrades leave it alone."
23382338
},
23392339
packageId: {
23402340
label: "Package Id",
2341-
helpText: "Owning package id for a package-shipped set (ADR-0086 D3). Leave empty for an environment-authored set."
2341+
helpText: "The package that ships this set; a value naming any other package is refused. Leave empty for a set created in this environment."
23422342
},
23432343
systemPermissions: {
23442344
label: "System Permissions",
23452345
helpText: "List of system capability keys"
23462346
},
23472347
adminScope: {
23482348
label: "Admin Scope",
2349-
helpText: "Delegated administration (ADR-0090 D12): lets holders of this set administer one business-unit subtree. businessUnit is the subtree root (sys_business_unit.name) and is required, non-blank; includeSubtree defaults to true; manageAssignments defaults to false and lets the holder assign people to positions, and grant sets directly, inside that subtree; a delegate may hand out only the sets named in assignablePermissionSets. Leave empty for a set that delegates nothing."
2349+
helpText: "Delegated administration: lets holders of this set administer one business-unit subtree. businessUnit is the subtree root (sys_business_unit.name) and is required, non-blank; includeSubtree defaults to true; manageAssignments defaults to false and lets the holder assign people to positions, and grant sets directly, inside that subtree; a delegate may hand out only the sets named in assignablePermissionSets. Leave empty for a set that delegates nothing."
23502350
},
23512351
objects: {
23522352
label: "Objects",
@@ -2391,7 +2391,7 @@ export const enMetadataForms: NonNullable<TranslationData['metadataForms']> = {
23912391
},
23922392
delegatable: {
23932393
label: "Delegatable",
2394-
helpText: "Holders may delegate this position themselves, time-boxed and with a reason (ADR-0091 D3). Default false — delegation is admin-only."
2394+
helpText: "Holders may delegate this position themselves, time-boxed and with a reason. Default false — delegation is admin-only."
23952395
}
23962396
}
23972397
},

‎packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ export const esESMetadataForms: NonNullable<TranslationData['metadataForms']> =
10191019
},
10201020
end_user_controls: {
10211021
label: "Controles de usuario final",
1022-
description: "Lo que los usuarios finales pueden hacer en esta vista: filtros rápidos, pestañas de filtro, cambio de visualización (ADR-0047, paridad con Airtable Interface)."
1022+
description: "Lo que los usuarios finales pueden hacer en esta vista: filtros rápidos, pestañas de filtro, cambio de visualización."
10231023
},
10241024
navigation_sharing: {
10251025
label: "Navegación y uso compartido",
@@ -2330,23 +2330,23 @@ export const esESMetadataForms: NonNullable<TranslationData['metadataForms']> =
23302330
},
23312331
isDefault: {
23322332
label: "Predeterminado",
2333-
helpText: "Línea base de la aplicación para la posición everyone (ADR-0090 D5): un conjunto de nivel de aplicación se vincula automáticamente al arrancar; uno de nivel de paquete se convierte en una sugerencia que el administrador confirma al instalar. false por defecto."
2333+
helpText: "Concede este conjunto a todos los que inician sesión, mediante la posición integrada everyone. Un conjunto que declara la propia aplicación se concede al arrancar; uno de un paquete instalado se convierte en una sugerencia que un administrador confirma en Setup. Un conjunto con permisos de alto privilegio nunca se concede así. false por defecto."
23342334
},
23352335
managedBy: {
23362336
label: "Gestionado por",
2337-
helpText: "Procedencia del registro (ADR-0086 D3): quién es el propietario de este conjunto entre actualizaciones."
2337+
helpText: "Quién es el propietario de este conjunto: Package indica que se distribuye con un paquete y que las actualizaciones del paquete lo modifican; Platform y User indican que se creó en este entorno y que las actualizaciones no lo tocan."
23382338
},
23392339
packageId: {
23402340
label: "ID de paquete",
2341-
helpText: "Id del paquete propietario de un conjunto distribuido con un paquete (ADR-0086 D3). Déjalo vacío para un conjunto creado en el entorno."
2341+
helpText: "El paquete que distribuye este conjunto; un valor que nombra otro paquete se rechaza. Déjalo vacío para un conjunto creado en este entorno."
23422342
},
23432343
systemPermissions: {
23442344
label: "Permisos del sistema",
23452345
helpText: "Lista de claves de capacidades del sistema"
23462346
},
23472347
adminScope: {
23482348
label: "Ámbito de administración delegada",
2349-
helpText: "Administración delegada (ADR-0090 D12): permite a quienes tienen este conjunto administrar un subárbol de unidades de negocio. businessUnit es la raíz del subárbol (sys_business_unit.name), es obligatorio y no puede estar en blanco; includeSubtree vale true por defecto; manageAssignments vale false por defecto y permite al titular asignar personas a puestos, y conceder conjuntos directamente, dentro de ese subárbol; un delegado solo puede asignar los conjuntos nombrados en assignablePermissionSets. Déjalo vacío en un conjunto que no delega nada."
2349+
helpText: "Administración delegada: permite a quienes tienen este conjunto administrar un subárbol de unidades de negocio. businessUnit es la raíz del subárbol (sys_business_unit.name), es obligatorio y no puede estar en blanco; includeSubtree vale true por defecto; manageAssignments vale false por defecto y permite al titular asignar personas a puestos, y conceder conjuntos directamente, dentro de ese subárbol; un delegado solo puede asignar los conjuntos nombrados en assignablePermissionSets. Déjalo vacío en un conjunto que no delega nada."
23502350
},
23512351
objects: {
23522352
label: "Permisos de objeto",
@@ -2391,7 +2391,7 @@ export const esESMetadataForms: NonNullable<TranslationData['metadataForms']> =
23912391
},
23922392
delegatable: {
23932393
label: "Delegable",
2394-
helpText: "Quienes la ocupan pueden delegar esta posición por sí mismos, con un plazo y un motivo (ADR-0091 D3). false por defecto: la delegación es solo para administradores."
2394+
helpText: "Quienes la ocupan pueden delegar esta posición por sí mismos, con un plazo y un motivo. false por defecto: la delegación es solo para administradores."
23952395
}
23962396
}
23972397
},

0 commit comments

Comments
 (0)