Skip to content

Commit 546a0d6

Browse files
os-zhuangclaude
andauthored
fix(cli): correct os explain object ownership values (#3244) (#3303)
`os explain object` documented the object `ownership` field as the package contribution kind (`"own" | "extend"`, ObjectOwnershipEnum set via registerObject). The real ObjectSchema.ownership field is the record-ownership model — `z.enum(['user', 'org', 'none'])` — a distinct concept the spec explicitly warns not to conflate. The explain catalog now prints the correct allowed values and description. Adds a regression test that pins the documented values to the record-ownership enum so the two concepts can't drift back together. Closes #3244 Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b7eb869 commit 546a0d6

3 files changed

Lines changed: 43 additions & 3 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
"@objectstack/cli": patch
3+
---
4+
5+
fix(cli): `os explain object` documented `ownership` with the wrong allowed values (#3244)
6+
7+
The schema catalog described the object `ownership` field as the package
8+
*contribution* kind (`"own" | "extend"`, the `ObjectOwnershipEnum` set via
9+
`registerObject`). But `ObjectSchema.ownership` is the **record-ownership
10+
model**`z.enum(['user', 'org', 'none'])` — a distinct concept the spec
11+
explicitly warns not to conflate despite the shared word.
12+
13+
`os explain object` now prints:
14+
15+
ownership 'user' | 'org' | 'none' Record-ownership model: user (default,
16+
injects a reassignable owner_id) | org | none (no per-record owner).
17+
Distinct from the package own/extend contribution kind.
18+
19+
A regression test (`packages/cli/test/commands.test.ts`) pins the documented
20+
values to the record-ownership enum so the two concepts can't drift back
21+
together. Found during the #1880 docs implementation-accuracy audit.

packages/cli/src/commands/explain.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ interface SchemaInfo {
2222
docsPath: string;
2323
}
2424

25-
const SCHEMAS: Record<string, SchemaInfo> = {
25+
export const SCHEMAS: Record<string, SchemaInfo> = {
2626
object: {
2727
name: 'Object',
2828
description: 'Defines a data entity in the ObjectStack data model. Objects contain fields, enable capabilities, and form the foundation of the metadata-driven platform.',
@@ -34,7 +34,7 @@ const SCHEMAS: Record<string, SchemaInfo> = {
3434
{ name: 'label', type: 'string', description: 'Human-readable display name' },
3535
{ name: 'pluralLabel', type: 'string', description: 'Plural display name' },
3636
{ name: 'description', type: 'string', description: 'Documentation for the object' },
37-
{ name: 'ownership', type: '"own" | "extend"', description: 'Whether this object is owned or extended' },
37+
{ name: 'ownership', type: "'user' | 'org' | 'none'", description: 'Record-ownership model: user (default, injects a reassignable owner_id) | org | none (no per-record owner). Distinct from the package own/extend contribution kind.' },
3838
{ name: 'enable', type: 'ObjectCapabilities', description: 'Feature flags (trackHistory, apiEnabled, etc.)' },
3939
{ name: 'icon', type: 'string', description: 'Icon identifier for UI display' },
4040
],

packages/cli/test/commands.test.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Info from '../src/commands/info';
1111
import Generate from '../src/commands/generate';
1212
import Lint from '../src/commands/lint';
1313
import Diff from '../src/commands/diff';
14-
import Explain from '../src/commands/explain';
14+
import Explain, { SCHEMAS } from '../src/commands/explain';
1515

1616
describe('CLI Commands (oclif)', () => {
1717
it('should have compile command', () => {
@@ -67,3 +67,22 @@ describe('CLI Commands (oclif)', () => {
6767
expect(Explain.description).toContain('explanation');
6868
});
6969
});
70+
71+
describe('os explain — schema catalog accuracy', () => {
72+
// Regression guard for #3244: `os explain object` used to document the
73+
// `ownership` field as the package-contribution kind (`"own" | "extend"`),
74+
// which is a DISTINCT concept (`ObjectOwnershipEnum`, set via registerObject).
75+
// The real `ObjectSchema.ownership` field is the record-ownership model —
76+
// `z.enum(['user','org','none'])` — see packages/spec/src/data/object.zod.ts.
77+
it('documents object.ownership as the record-ownership model, not the own/extend contribution kind (#3244)', () => {
78+
const ownership = SCHEMAS.object.optional.find((f) => f.name === 'ownership');
79+
expect(ownership, 'object schema should document an `ownership` field').toBeDefined();
80+
81+
// The type string must enumerate exactly the record-ownership enum values.
82+
const tokens = (ownership!.type.match(/'[^']+'|"[^"]+"/g) ?? []).map((t) => t.slice(1, -1));
83+
expect(new Set(tokens)).toEqual(new Set(['user', 'org', 'none']));
84+
85+
// …and must never regress back to the contribution-kind values.
86+
expect(ownership!.type).not.toBe('"own" | "extend"');
87+
});
88+
});

0 commit comments

Comments
 (0)