Skip to content

Commit 022e4c3

Browse files
os-zhuangclaude
andauthored
feat(deps)!: upgrade to @objectstack/spec 17.0.0-rc.1 and retire the wait timeout fields (#3101) (#3178)
* feat(deps)!: upgrade to @objectstack/spec 17.0.0-rc.1 and retire the wait timeout fields (#3101) `waitEventConfig.timeoutMs` / `.onTimeout` became `retiredKey()` tombstones in rc.1 (framework#4158), so a value written there is now REJECTED at load — until this lands, Studio can produce flow metadata the author's own runtime refuses. That hazard opened when rc.1 published, not when this repo bumps, which is why the bump and the field removal ride together. #3101 also requires them together in the other direction: the sibling-block assertion is bidirectional, so deleting the fields against a spec that still declares them fails the reverse check. `wait` never had a timeout. `onTimeout` had zero readers; `timeoutMs`'s only reader used it as the timer DURATION when `timerDuration` was absent, and `timerDuration` accepts a bare number as milliseconds — so the old `timeoutMs: 60000` is `timerDuration: '60000'`, unchanged. The two zh label overrides go with the fields. Everything else here is fallout the bump surfaced, each verified rather than assumed: - `combo` is the sole addition to `ChartTypeSchema` in rc.1 (19 members → 20). It had been renderer-local, so neither surface that classifies a SPEC chart type routed it: a spec-valid combo fell through to the red "Unknown component type" panel on a dashboard and the out-of-spec notice on a report. Both now route it; the renderer-local derivation stays, since that is what makes an authored `type: 'combo'` render rather than merely validate. - `JoinStrategy` / `WindowFunction` / `PerformanceConfig` were removed upstream (framework#4286, #3896). The first two were bound under objectstack#4115's "derive, don't restate" rule; with no enum left to derive from, they are restated locally — verbatim from the last spec that published them — as the objectui query-AST vocabulary they have become. The AST is unchanged. - Three objectstack#4171 inverted pins FIRED: `NavigationItem`, `FormField` and `ConditionalValidation`'s branches are no longer `any`/`unknown` upstream. The assertions are inverted to record that, deliberately WITHOUT the burn-down each asks for — deriving those from the spec touches widely-used public types and does not belong in a version bump. Tracked in #3177. `JoinNode`'s pin is gone outright; the symbol no longer exists. - `dashboard.performance` was retired upstream and the dashboard form derives from the spec's own `dashboardForm`, so the field disappears for free. Its test now pins the absence — if that file ever hardcodes a field list again, a retirement would silently keep offering an input the loader rejects. The bump also arms the reconciliation ledger's `subflow` and `decision` panels, which feature-detect their spec exports and had never actually run (rc.0 predates framework#4278). The `script` panel's full bidirectional check stays skipped by design: rc.1 predates framework#4343, so only the one-directional check is meaningful there. It arms itself on the next rc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ct9NXp2JumjKuARtQnrbPf * fix(deps): reconcile the spec-symbol ledger with rc.1's retirements and additions `check:spec-symbols` runs in CI's Type Check job but not in `turbo run type-check`, so the local run was green while CI was not — my miss, and the reason this is a follow-up commit rather than part of the bump. Two stale DEBT entries: `JoinNode` (@object-ui/types) and `PerformanceConfig` (@object-ui/react) no longer collide with anything, because spec 17.0.0 retired both exports. The guard fails on a ledger entry that outlives the code it excuses, which is the point — removed. Two new collisions, triaged rather than parked in DEBT, because neither is a dialect of the spec's concept: - `@object-ui/types:FieldNode` — the spec's is a bare `string`, a field NAME, after objectstack#4196 narrowed `QueryAST.fields` to names. Ours is a NODE in objectui's own query AST, sibling to `LiteralNode` / `OperatorNode`. Deriving would replace a structured node with a string; there is nothing to import. - `@object-ui/app-shell:InboxNotification` — two layers, like the existing FormField entry. The spec's is the notification SERVICE contract (camelCase, `body`/`read` required). Ours is the materialized inbox ROW the popover groups: snake_case mirroring `sys_notification`, carrying the read-receipt keys the contract has no place for (ADR-0030), nullable where a stored row can be null. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ct9NXp2JumjKuARtQnrbPf --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5cb75b3 commit 022e4c3

35 files changed

Lines changed: 292 additions & 153 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
"@object-ui/app-shell": minor
3+
"@object-ui/types": minor
4+
"@object-ui/plugin-dashboard": patch
5+
"@object-ui/plugin-report": patch
6+
---
7+
8+
Upgrade to `@objectstack/spec@17.0.0-rc.1`, stop offering the retired `wait` timeout fields (#3101), and route the newly-adopted `combo` chart type.
9+
10+
**Breaking for authoring, and the reason to do it now**: the `wait` panel no longer offers
11+
`waitEventConfig.timeoutMs` or `.onTimeout`. Both are `retiredKey()` tombstones as of spec
12+
17.0.0-rc.1 (framework#4158), which means a value written there is **rejected at load**
13+
so until this lands, Studio can produce flow metadata the author's own runtime refuses.
14+
That hazard opened the moment rc.1 published, independent of when this repo bumps.
15+
16+
`wait` never had a timeout: `onTimeout` had zero readers, so neither `'fail'` nor
17+
`'continue'` ever happened, and `timeoutMs`'s only reader used it as the timer **duration**
18+
when `timerDuration` was absent. Use **Duration** — it accepts a bare number as
19+
milliseconds, making the old `timeoutMs: 60000` and `timerDuration: '60000'` the same wait.
20+
Stored flows are converted by framework's D2 conversion; the designer simply stops offering
21+
the entry. The two `zh` label overrides go with the fields.
22+
23+
#3101 asked for this to ride along with the bump rather than land alone, and that is
24+
load-bearing: the sibling-block assertion is **bidirectional**, so deleting the fields
25+
against a spec that still declares them fails in the other direction.
26+
27+
**`combo` is now a spec chart type** — the sole addition to `ChartTypeSchema` in rc.1 (19
28+
members → 20). It had been a renderer-local family the chart renderer derived from the
29+
series, so nothing classified it on the two surfaces that route a *spec* chart type: a
30+
spec-valid `combo` fell through to the red "Unknown component type" panel on a dashboard
31+
and to the out-of-spec notice on a report. Both now route it
32+
(`widgetDispatch.SERIES_CHART_TYPES`, `planReportChart`). The renderer-local derivation
33+
stays — it is what makes an authored `type: 'combo'` render rather than merely validate.
34+
35+
**Retired spec exports this repo bound to**, all removed upstream in spec 17.0.0:
36+
37+
- `JoinStrategy` / `WindowFunction` (framework#4286 tombstoned `query.joins` and
38+
`query.windowFunctions`: no engine or driver ever read either on the query path). They
39+
were derived off the spec enums under objectstack#4115's "come off the spec enum, not a
40+
restatement" rule; with no enum left, `data-protocol.ts` now restates the members locally
41+
— verbatim from the last spec that published them — as the objectui query-AST vocabulary
42+
they have become. The AST itself is unchanged.
43+
- `PerformanceConfig`, retired with `dashboard.performance` (framework#3896). Nothing bound
44+
to it — `@object-ui/react`'s `usePerformance` declares its own interface and is untouched.
45+
The dashboard form is derived from the spec's own `dashboardForm`, so the field
46+
disappears from the inspector for free; its test now pins the absence.
47+
48+
**Three inverted pins fired, and are recorded rather than resolved.** objectstack#4171's
49+
tripwires asserted that `NavigationItem`, `FormField` and `ConditionalValidation`'s branches
50+
still erased to `any`/`unknown` upstream — the premise that justified objectui keeping local
51+
declarations. rc.1 types them properly, so the assertions are inverted to state the new
52+
fact. The burn-down each one asks for — deriving those types from the spec — touches
53+
widely-used public types and is deliberately **not** bundled into a version bump; it is
54+
tracked in #3177. `JoinNode`'s pin is gone outright: the symbol no longer exists.
55+
56+
**What the bump arms.** The reconciliation ledger's `subflow` and `decision` panels
57+
feature-detect their spec exports and had never actually run — rc.0 predates the exports
58+
(framework#4278). They now execute and pass. The `script` panel's full bidirectional check
59+
stays deliberately skipped: rc.1 predates framework#4343, so the retired dispatch branches
60+
are still contract keys there, and only the "offers nothing the executor ignores" direction
61+
is meaningful. It arms itself on the next rc.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"devDependencies": {
6565
"@changesets/cli": "^2.31.1",
6666
"@eslint/js": "^10.0.1",
67-
"@objectstack/spec": "^17.0.0-rc.0",
67+
"@objectstack/spec": "^17.0.0-rc.1",
6868
"@playwright/test": "^1.62.0",
6969
"@testing-library/dom": "^10.4.1",
7070
"@testing-library/jest-dom": "^7.0.0",

packages/app-shell/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"@object-ui/types": "workspace:*",
5151
"@objectstack/formula": "^17.0.0-rc.0",
5252
"@objectstack/lint": "^17.0.0-rc.0",
53-
"@objectstack/spec": "^17.0.0-rc.0",
53+
"@objectstack/spec": "^17.0.0-rc.1",
5454
"@sentry/react": "^10.68.0",
5555
"jsonc-parser": "^3.3.1",
5656
"lucide-react": "^1.25.0",

packages/app-shell/src/views/metadata-admin/dashboard-schema.test.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,24 @@ describe('dashboard-schema — getDashboardForm', () => {
4444
expect(declared.has('name')).toBe(false);
4545
});
4646

47-
it('keeps non-owned spec fields (e.g. layout / filters / performance)', () => {
47+
it('keeps non-owned spec fields (e.g. layout / filters), and carries a retirement through', () => {
4848
const form = getDashboardForm();
4949
const declared = new Set<string>();
5050
for (const s of form?.sections ?? []) {
5151
for (const f of s.fields ?? []) {
5252
declared.add(typeof f === 'string' ? f : (f as { field: string }).field);
5353
}
5454
}
55-
// Layout, filter and advanced fields survive the prune.
55+
// Layout and filter fields survive the prune.
5656
expect(declared.has('columns')).toBe(true);
5757
expect(declared.has('globalFilters')).toBe(true);
58-
expect(declared.has('performance')).toBe(true);
58+
// `performance` was RETIRED in spec 17.0.0 (framework#3896 audit close-out):
59+
// no renderer or runtime ever read it. This form is derived from the spec's
60+
// own `dashboardForm`, so the removal arrives here for free — which is the
61+
// point of deriving instead of hand-listing, and worth pinning: were this
62+
// file ever to hardcode a field list again, a retirement would silently
63+
// keep offering an input the loader rejects.
64+
expect(declared.has('performance')).toBe(false);
5965
});
6066

6167
it('drops sections that become empty after pruning', () => {

packages/app-shell/src/views/metadata-admin/i18n.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3516,8 +3516,8 @@ const FLOW_FIELD_ZH: Record<string, Record<string, FlowFieldZh>> = {
35163516
},
35173517
'waitEventConfig.timerDuration': { label: '时长', help: 'ISO 8601 时长(如 PT1H、P3D)。' },
35183518
'waitEventConfig.signalName': { label: '信号名称' },
3519-
'waitEventConfig.timeoutMs': { label: '超时(毫秒)' },
3520-
'waitEventConfig.onTimeout': { label: '超时时', opts: { fail: '失败', continue: '继续' } },
3519+
// `waitEventConfig.timeoutMs` / `.onTimeout` 的覆盖随字段一并移除(#3101):
3520+
// 两个键在 spec 17.0.0-rc.1 已是墓碑,表单不再提供授权入口。
35213521
},
35223522
subflow: {
35233523
flowName: { label: '流程' },

packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -763,15 +763,17 @@ const FLOW_NODE_CONFIG: Record<string, FlowConfigField[]> = {
763763
showWhen: { field: 'waitEventConfig.eventType', equals: ['signal', 'webhook'] },
764764
fallbackPath: ['config', 'signalName'],
765765
}),
766-
at('waitEventConfig', 'timeoutMs', 'Timeout (ms)', 'number', { placeholder: '3600000', fallbackPath: ['config', 'timeoutMs'] }),
767-
at('waitEventConfig', 'onTimeout', 'On timeout', 'select', {
768-
options: [
769-
{ value: 'fail', label: 'Fail' },
770-
{ value: 'continue', label: 'Continue' },
771-
],
772-
defaultValue: 'fail',
773-
fallbackPath: ['config', 'onTimeout'],
774-
}),
766+
// `waitEventConfig.timeoutMs` / `.onTimeout` were REMOVED here (#3101,
767+
// framework#4158): `wait` never had a timeout. `onTimeout` had zero readers
768+
// — neither 'fail' nor 'continue' ever happened — and `timeoutMs`'s only
769+
// reader used it as the timer DURATION when `timerDuration` was absent, so
770+
// it did something, just not what it said. Both are `retiredKey()`
771+
// tombstones on `FlowNodeSchema` since spec 17.0.0-rc.1, so a value written
772+
// here is now REJECTED at load: keeping the fields would let an author
773+
// produce metadata their own runtime refuses. Use `Duration` above — it
774+
// accepts a bare number as milliseconds, making the old `timeoutMs: 60000`
775+
// and `timerDuration: '60000'` the same wait. Stored flows are converted by
776+
// framework's D2 conversion; the designer just stops offering the entry.
775777
],
776778
subflow: [
777779
cfg('flowName', 'Flow', 'reference', { ref: { kind: 'flow' }, placeholder: 'escalation_flow' }),

packages/auth/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
},
3939
"dependencies": {
4040
"@object-ui/types": "workspace:*",
41-
"@objectstack/spec": "^17.0.0-rc.0",
41+
"@objectstack/spec": "^17.0.0-rc.1",
4242
"better-auth": "^1.6.25"
4343
},
4444
"devDependencies": {

packages/components/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
"tailwindcss": "^4.2.1"
9191
},
9292
"devDependencies": {
93-
"@objectstack/spec": "^17.0.0-rc.0",
93+
"@objectstack/spec": "^17.0.0-rc.1",
9494
"@tailwindcss/postcss": "^4.3.3",
9595
"@types/react": "19.2.17",
9696
"@types/react-dom": "19.2.3",

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"dependencies": {
3434
"@object-ui/types": "workspace:*",
3535
"@objectstack/formula": "^17.0.0-rc.0",
36-
"@objectstack/spec": "^17.0.0-rc.0",
36+
"@objectstack/spec": "^17.0.0-rc.1",
3737
"lodash": "^4.18.1",
3838
"zod": "^4.4.3"
3939
},

packages/data-objectstack/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"@objectstack/client": "^17.0.0-rc.0"
3636
},
3737
"devDependencies": {
38-
"@objectstack/spec": "^17.0.0-rc.0",
38+
"@objectstack/spec": "^17.0.0-rc.1",
3939
"tsup": "^8.5.1",
4040
"typescript": "^6.0.3",
4141
"vitest": "^4.1.10"

0 commit comments

Comments
 (0)