Skip to content

Commit b78a69b

Browse files
chore: version packages (rc)
1 parent 868718e commit b78a69b

153 files changed

Lines changed: 12195 additions & 83 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/pre.json

Lines changed: 109 additions & 1 deletion
Large diffs are not rendered by default.

examples/app-crm/CHANGELOG.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,224 @@
11
# @objectstack/example-crm
22

3+
## 4.0.92-rc.2
4+
5+
### Patch Changes
6+
7+
- e533b0b: feat(spec)!: retire `datasource.capabilities` — eleven flags nothing read, one of them a safety claim (#4583)
8+
9+
`DatasourceCapabilities` declared eleven booleans — `transactions`, seven `query*`
10+
flags, `joins`, `fullTextSearch`, `readOnly`, `dynamicSchema` — all strict-guarded,
11+
all read by nothing. Pushdown is decided by the runtime driver's own `supports.*`
12+
object, a different mechanism entirely, so a datasource declaring
13+
`queryAggregations: false` never once changed which engine path ran. The block is
14+
removed rather than bridged: there was nothing on the other side to connect it to.
15+
16+
**`readOnly` is why this is not tidy-up.** It reads as a safety property and was
17+
authored as one — the shipped CRM example labelled a datasource "CRM Analytics Read
18+
Replica" on the strength of it, while the datasource accepted writes exactly like the
19+
primary. The key had already been MOVED twice toward somewhere it might be enforced,
20+
out of `config` in #4410 and into `capabilities` in #4465, and was inert at every
21+
address. This removes it instead of moving it a third time.
22+
23+
**Removing it does not hand you a working replacement, and the rejection says so.**
24+
The one enforced datasource-wide write gate is `external.allowWrites: false`, and it
25+
applies only to a FEDERATED datasource — `assertWriteAllowed` returns early for a
26+
`managed` (or unset-`schemaMode`) datasource, so that key would be equally inert for a
27+
local database. **A managed datasource has no read-only gate at all**; that gap is
28+
#4584, deliberately not invented here. Until it is answered, enforce read-only where
29+
it is real: grant the connection SELECT-only at the database.
30+
31+
FROM → TO:
32+
33+
```ts
34+
// before — parsed cleanly, changed nothing
35+
defineDatasource({
36+
name: 'analytics', driver: 'sqlite', config: { filename: ':memory:' },
37+
capabilities: { readOnly: true, queryAggregations: true },
38+
})
39+
40+
// after — delete the block; for a FEDERATED datasource the enforced gate is:
41+
defineDatasource({
42+
name: 'warehouse', driver: 'postgres', config: { … },
43+
schemaMode: 'external',
44+
external: { allowWrites: false },
45+
})
46+
```
47+
48+
`os migrate meta --from 16` rewrites it automatically (ADR-0087 conversion
49+
`datasource-capabilities-removed`). Both `DatasourceSchema` and
50+
`DriverDefinitionSchema` are `.strict()`, so a leftover key is a loud rejection
51+
carrying the prescription — never a silent strip.
52+
53+
Also fixed: `READ_ONLY_BELONGS_ON_DATASOURCE`, the prescription every SQL driver
54+
shares for a `readOnly` written inside `config`, was still sending authors _to_ the
55+
removed key. It now names the enforced gate and states plainly where that gate does
56+
not apply — a prescription that lands on an inert key manufactures exactly the belief
57+
it was meant to correct.
58+
59+
The `datasource` liveness ledger drops from 20 dead properties to 9 (remaining:
60+
`healthCheck` ×3, `retryPolicy` ×4, `external` ×2 — batches B/C/D of #4583).
61+
62+
- 5293114: fix(automation): a decision's three declared ways to route a branch are now one working model (#4414)
63+
64+
A `decision` node advertised three mechanisms for splitting a path and only one
65+
of them did anything. The other two were the ADR-0049 `declared ≠ enforced`
66+
shape, and the pair of them shipped a guard that does not guard in
67+
`examples/app-crm`.
68+
69+
| mechanism | before | now |
70+
| :--------------------------------------------------- | :----------------------------------------------------------------------------------------------------- | :---------------------------------------------------- |
71+
| `edge.condition` | ✅ the only one that worked | unchanged |
72+
| `edge.isDefault` | **zero readers** anywhere but the schema declaration | BPMN default flow, enforced in `traverseNext` |
73+
| `decision.config.conditions[].label``branchLabel` | matched **0** out-edge labels across every example app, then fell back to the full edge set in silence | routes; an unclaimable label is logged, not swallowed |
74+
75+
## What was broken, end to end
76+
77+
`crm_convert_lead_wizard` means "already converted → abort screen; otherwise →
78+
the wizard". It ran **both**: an already-converted lead got
79+
"This lead has already been converted" and then walked straight into the
80+
conversion wizard behind it. Four independent silences stacked up:
81+
82+
1. the decision's first condition was authored `{lead_record.status} ==
83+
'converted'` — braces in a slot declared bare CEL, so it was string-compared
84+
and never true;
85+
2. the second (`'true'`) therefore won, yielding `branchLabel: 'No — proceed'`;
86+
3. no out-edge carried that label (they were `'Yes'` / `'No'`), so traversal
87+
discarded the branch and considered every out-edge;
88+
4. `e3b` was unconditional, so it ran regardless — and the natural fix, marking
89+
it `isDefault: true`, was a dead key.
90+
91+
## The model
92+
93+
`branchLabel` narrows the edge set → `condition` gates each edge → `isDefault`
94+
catches whatever is left. Concretely:
95+
96+
- **`isDefault` is enforced.** A default edge is traversed only when no
97+
conditional sibling of the same source node matched, and it is no longer part
98+
of the unconditional parallel fan-out — that distinction is the whole point of
99+
the marker. Passed over because a real branch won, its target records the same
100+
`skipped` step a closed gate does (#4354).
101+
- **An unclaimable branch label warns.** Traversal still falls back to the full
102+
edge set (a run mid-flight must not die on a metadata error) but says so,
103+
naming the computed branch and the out-edge labels that exist.
104+
- **A decision that declares no `conditions` reports no branch.** It used to
105+
report `'default'` unconditionally — a label no out-edge in the repo ever
106+
carried — which is why every decision node fell back to the full edge set.
107+
The `'default'` sentinel survives for the case it actually describes (declared
108+
conditions, none matched) and is now claimed by the `isDefault` edge as well
109+
as by an edge literally labelled `'default'`.
110+
- **`conditions[].expression` is evaluated as the bare CEL it is declared to
111+
be.** The raw string went to the legacy `{var}` template path, where
112+
`lead.status == 'converted'` cannot resolve and the branch is decided by
113+
string comparison. Unlike `edge.condition` this slot carries no
114+
`ExpressionInput` envelope — the decision descriptor is deliberately
115+
schemaless — so the executor supplies the dialect. A brace-in-CEL predicate
116+
now fails loudly (ADR-0032 §1c) instead of deciding `false`.
117+
118+
## Caught at authoring time too
119+
120+
Four new `os build` / `os validate` warnings, because a wrong route is silent at
121+
run time by nature (Prime Directive #12):
122+
123+
`flow-branch-label-unmatched` (the shipped shape),
124+
`flow-decision-unconditional-branch` (a guarded decision with an unconditional
125+
sibling — the actual hole), `flow-default-edge-with-condition` and
126+
`flow-multiple-default-edges`.
127+
128+
Both of the first two fire on the pre-fix `convert-lead.flow.ts` and are silent
129+
after it.
130+
131+
## Effect on flows that already exist
132+
133+
Enforcing `isDefault` changes how a **stored** flow behaves, and the flows it
134+
changes are mostly Studio's own. `objectui`'s flow edge inspector has always
135+
written `isDefault: true` when you bind an out-edge to a decision's default/else
136+
branch — into a key with zero readers, so that edge ran unconditionally, in
137+
parallel with whichever branch actually matched. Those flows now take exactly
138+
one branch. That is the fix, but it is a behaviour change on existing data
139+
rather than only on newly authored metadata, so it is worth knowing before
140+
upgrading: a flow that quietly ran two paths will now run one.
141+
142+
Nothing changes for an edge that never carried the marker — `isDefault` defaults
143+
to `false`, and an ordinary unconditional out-edge still fans out in parallel
144+
exactly as before.
145+
146+
## The example app
147+
148+
`crm_convert_lead_wizard`'s guard is now a plain exclusive gateway: the
149+
redundant `config.conditions` is gone and `e3b` carries `isDefault: true`. One
150+
mechanism per decision, and exactly one branch runs.
151+
152+
Verified: 11 new engine/executor tests (including the reported repro in both
153+
directions), 12 new linter tests; `@objectstack/service-automation` 577 tests
154+
and `@objectstack/cli` 652 tests green, all three example apps build with no new
155+
findings.
156+
157+
- Updated dependencies [80334c7]
158+
- Updated dependencies [a7163ea]
159+
- Updated dependencies [e6e9379]
160+
- Updated dependencies [e6b1b69]
161+
- Updated dependencies [2826d1e]
162+
- Updated dependencies [5a84d41]
163+
- Updated dependencies [20b1a9e]
164+
- Updated dependencies [4820f55]
165+
- Updated dependencies [462d9c4]
166+
- Updated dependencies [5b843fb]
167+
- Updated dependencies [b4487aa]
168+
- Updated dependencies [67bf2e2]
169+
- Updated dependencies [6117f7b]
170+
- Updated dependencies [e533b0b]
171+
- Updated dependencies [cdf4d9a]
172+
- Updated dependencies [63b33e6]
173+
- Updated dependencies [9ca2d85]
174+
- Updated dependencies [a52e2ef]
175+
- Updated dependencies [5293114]
176+
- Updated dependencies [ff17642]
177+
- Updated dependencies [20bc357]
178+
- Updated dependencies [2382580]
179+
- Updated dependencies [3c7bcc0]
180+
- Updated dependencies [4b6cac7]
181+
- Updated dependencies [7631964]
182+
- Updated dependencies [ac471a0]
183+
- Updated dependencies [60ae58e]
184+
- Updated dependencies [ce92674]
185+
- Updated dependencies [07a4e26]
186+
- Updated dependencies [ec975f1]
187+
- Updated dependencies [eb4204b]
188+
- Updated dependencies [4f13be2]
189+
- Updated dependencies [ce92674]
190+
- Updated dependencies [cf2c9b7]
191+
- Updated dependencies [0f9faa2]
192+
- Updated dependencies [7cf42fe]
193+
- Updated dependencies [8aacf94]
194+
- Updated dependencies [a2cd18a]
195+
- Updated dependencies [4638aaa]
196+
- Updated dependencies [0222d3c]
197+
- Updated dependencies [7bba90b]
198+
- Updated dependencies [061406d]
199+
- Updated dependencies [9c93465]
200+
- Updated dependencies [ebb209c]
201+
- Updated dependencies [63b33e6]
202+
- Updated dependencies [2a44c1d]
203+
- Updated dependencies [f3141d8]
204+
- Updated dependencies [5a84d41]
205+
- Updated dependencies [fd3013a]
206+
- Updated dependencies [e5e7ee0]
207+
- Updated dependencies [800bdb0]
208+
- Updated dependencies [04f1182]
209+
- Updated dependencies [38f7e4f]
210+
- Updated dependencies [c57f3cf]
211+
- Updated dependencies [97faca3]
212+
- Updated dependencies [ad5fe25]
213+
- Updated dependencies [ea90179]
214+
- Updated dependencies [ce92674]
215+
- Updated dependencies [5ef0b5b]
216+
- Updated dependencies [48fbacb]
217+
- Updated dependencies [355e951]
218+
- Updated dependencies [dadb43f]
219+
- @objectstack/spec@17.0.0-rc.2
220+
- @objectstack/runtime@17.0.0-rc.2
221+
3222
## 4.0.92-rc.1
4223

5224
### Patch Changes

examples/app-crm/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@objectstack/example-crm",
3-
"version": "4.0.92-rc.1",
3+
"version": "4.0.92-rc.2",
44
"description": "Minimal CRM example — a smoke-test workspace that exercises the metadata loading pipeline (objects → views → app → dashboard → hook → flow → seed). For a full-featured enterprise CRM see https://github.com/objectstack-ai/hotcrm.",
55
"license": "Apache-2.0",
66
"private": true,

examples/app-showcase/CHANGELOG.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,137 @@
11
# @objectstack/example-showcase
22

3+
## 0.3.14-rc.2
4+
5+
### Patch Changes
6+
7+
- d449b0c: fix(cli): gate the two decision-routing shapes that can never work, and flag the inert `config.condition` (#4414)
8+
9+
Two follow-ups to #4440, both about metadata that reads like a guard and is not
10+
one.
11+
12+
## Two rules promoted to `error`
13+
14+
`flow-branch-label-unmatched` and `flow-default-edge-with-condition` now FAIL the
15+
build instead of warning. The bar for that — restated at the top of
16+
`lint-flow-patterns.ts`, because the old one no longer described the set — is
17+
**no reading of the author's metadata does what it says, deterministically, on
18+
every run**. Both qualify: a branch label no out-edge carries cannot route, and
19+
an edge that is both `isDefault` and conditional always lets the condition win,
20+
so the marker routes nothing. Neither _fails_; both are wrong every time and
21+
silently, which is worse.
22+
23+
The other two stay advisory on purpose, and the policy now says why:
24+
`flow-decision-unconditional-branch` is usually a guard that does not guard, but
25+
one guarded plus one unconditional out-edge is also a legal "maybe notify,
26+
always continue" fan-out, and `flow-multiple-default-edges` can genuinely mean
27+
"when nothing matched, do both". The bar is about _provability_, not severity of
28+
consequence — failing a customer's build on a shape we cannot prove wrong is the
29+
worse trade.
30+
31+
No wiring change was needed: `lintFlowPatterns` is already registered as
32+
`tier: 'gating'` across all three commands (#4409), which is exactly the seam
33+
`authoring-rule-wiring.test.ts` exists to guard.
34+
35+
## New rule: `flow-inert-node-condition`
36+
37+
`config.condition` is the trigger gate on a `start` node and is read by **no
38+
other node type** — the engine parse-validates it everywhere (so a malformed one
39+
is caught) and then ignores it. On a `decision` the name makes it read as the
40+
branch predicate, which is exactly how it got authored.
41+
42+
Three of the three bundled apps had one. `app-todo`'s `check_recurring` and
43+
`app-showcase`'s `needs_exec` both carried a predicate their out-edges were
44+
already enforcing — a third copy doing nothing. The showcase even had a comment
45+
next to it saying the node condition "is not evaluated by the engine", and kept
46+
it anyway; that is the residue this rule exists to stop accumulating. Both are
47+
now plain exclusive gateways.
48+
49+
Advisory, not gating: the surrounding edges usually still route correctly, so
50+
this is dead weight rather than a provable misroute. The node-type list is a
51+
closed set of builtins we have actually read, not "everything that isn't
52+
`start`" — ADR-0018 keeps `node.type` open and a plugin executor may legitimately
53+
declare and read its own `config.condition`.
54+
55+
## Studio
56+
57+
`objectstack-ai/objectui` carries the matching help-text fixes: the branch editor
58+
said a `true` branch **is** the default/else path (it is how you _ask_ for one —
59+
the marker goes on the out-edge), and the legacy single `Condition` field said
60+
"prefer Branches above", which reads as "this works, but the other is better".
61+
It does not work at all.
62+
63+
- Updated dependencies [80334c7]
64+
- Updated dependencies [a7163ea]
65+
- Updated dependencies [e6e9379]
66+
- Updated dependencies [e6b1b69]
67+
- Updated dependencies [2826d1e]
68+
- Updated dependencies [5a84d41]
69+
- Updated dependencies [20b1a9e]
70+
- Updated dependencies [4820f55]
71+
- Updated dependencies [462d9c4]
72+
- Updated dependencies [5b843fb]
73+
- Updated dependencies [b4487aa]
74+
- Updated dependencies [67bf2e2]
75+
- Updated dependencies [6117f7b]
76+
- Updated dependencies [e533b0b]
77+
- Updated dependencies [cdf4d9a]
78+
- Updated dependencies [63b33e6]
79+
- Updated dependencies [9ca2d85]
80+
- Updated dependencies [a52e2ef]
81+
- Updated dependencies [5293114]
82+
- Updated dependencies [ff17642]
83+
- Updated dependencies [20bc357]
84+
- Updated dependencies [2382580]
85+
- Updated dependencies [3c7bcc0]
86+
- Updated dependencies [4b6cac7]
87+
- Updated dependencies [7631964]
88+
- Updated dependencies [ac471a0]
89+
- Updated dependencies [60ae58e]
90+
- Updated dependencies [ce92674]
91+
- Updated dependencies [07a4e26]
92+
- Updated dependencies [ec975f1]
93+
- Updated dependencies [eb4204b]
94+
- Updated dependencies [4f13be2]
95+
- Updated dependencies [ce92674]
96+
- Updated dependencies [cf2c9b7]
97+
- Updated dependencies [0f9faa2]
98+
- Updated dependencies [7cf42fe]
99+
- Updated dependencies [8aacf94]
100+
- Updated dependencies [a2cd18a]
101+
- Updated dependencies [4638aaa]
102+
- Updated dependencies [0222d3c]
103+
- Updated dependencies [7bba90b]
104+
- Updated dependencies [061406d]
105+
- Updated dependencies [9c93465]
106+
- Updated dependencies [ebb209c]
107+
- Updated dependencies [63b33e6]
108+
- Updated dependencies [2a44c1d]
109+
- Updated dependencies [f3141d8]
110+
- Updated dependencies [5a84d41]
111+
- Updated dependencies [fd3013a]
112+
- Updated dependencies [e5e7ee0]
113+
- Updated dependencies [800bdb0]
114+
- Updated dependencies [04f1182]
115+
- Updated dependencies [38f7e4f]
116+
- Updated dependencies [c57f3cf]
117+
- Updated dependencies [97faca3]
118+
- Updated dependencies [ad5fe25]
119+
- Updated dependencies [ea90179]
120+
- Updated dependencies [ce92674]
121+
- Updated dependencies [5ef0b5b]
122+
- Updated dependencies [48fbacb]
123+
- Updated dependencies [355e951]
124+
- Updated dependencies [dadb43f]
125+
- @objectstack/spec@17.0.0-rc.2
126+
- @objectstack/runtime@17.0.0-rc.2
127+
- @objectstack/service-datasource@17.0.0-rc.2
128+
- @objectstack/driver-sql@17.0.0-rc.2
129+
- @objectstack/cloud-connection@17.0.0-rc.2
130+
- @objectstack/connector-mcp@17.0.0-rc.2
131+
- @objectstack/connector-openapi@17.0.0-rc.2
132+
- @objectstack/connector-rest@17.0.0-rc.2
133+
- @objectstack/connector-slack@17.0.0-rc.2
134+
3135
## 0.3.14-rc.1
4136

5137
### Patch Changes

examples/app-showcase/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@objectstack/example-showcase",
3-
"version": "0.3.14-rc.1",
3+
"version": "0.3.14-rc.2",
44
"description": "Kitchen-sink showcase workspace — exercises every metadata type, every view type, every chart type, and the major end-to-end capability chains (security, automation, analytics). Built for demonstration, debugging, and coverage-driven verification.",
55
"license": "Apache-2.0",
66
"private": true,

0 commit comments

Comments
 (0)