Repository navigation
Commit f66fdc7
Part of #19939
Clause-②: no (narrowing)
Pass 4, stage S1 of #19939 (stage plan `6096263424`, claim
`6096277270`), under ruling D on #11182 and ADR-0032 Decisions 2 and 3.
The maps a flow node hands to a callee become value slots:
`subflow.input.*`, `map.input.*` and `script.inputs.*`. Each value is a
CEL value envelope that the executor evaluates in the calling flow's
scope, or a literal. A single-brace `{…}` token there is refused. #19939
stays open for stages S2 to S7, so this PR uses `Part of`.
## What lands
**The ledger and the contracts (`@objectstack/spec`).**
- `FLOW_NODE_EXPRESSION_PATHS` gains three `value` rows:
`subflow.input.*`, `map.input.*` and `script.inputs.*`. Because the
value-slot judge (`flowNodeValueTemplateRefusals`) walks the ledger, it
refuses a token at these positions at `registerFlow` and at `objectstack
validate` with no second judge. The lint hints
`flow-bare-dollar-reference` and `flow-double-brace-interpolation` ask
that same judge, so they flip at these positions with no lint source
change.
- `SubflowConfigSchema.input`, `ScriptConfigSchema.inputs` and
`MapConfigSchema.input` take `FlowValueSlotSchema` per value. The
executor's contract parse therefore refuses a token as a guard. `map`
joins `LEDGER_DECLARED_NODE_CONFIG_SCHEMAS`, as the CRUD pair did,
because its descriptor declares `input` as `additionalProperties: true`
with no marker. `map.collection` keeps its `flow-template` slot on the
descriptor channel, so no slot is declared twice.
- `dropped-refinements.baseline.json` declares the three new dropped
value refinements (`input.valueType`, `inputs.valueType`), and its
header totals follow the body.
**The callee sentence (the judge).** A whole token that resolved to
nothing handed the callee nothing. A child flow then seeded the variable
from its `defaultValue` (`seedDeclaredVariables` applies the default
only to `undefined`). The guarded form the remedy names hands `null`. A
supplied `null` wins over the default. At a top-level value of a callee
map, the refusal now ends with a sentence that names the child variable
and the two ways to keep the default: write it in the guard's `null`
branch, or leave the key out. For a `script`, it says the function is
handed `null` where it was handed `undefined`. A `$User` path that never
resolved gets the variant "leaving the key out keeps exactly that". The
positions come from the ledger entry, inside the judge module. No new
export was added.
**The executor (`@objectstack/service-automation`).** One per-key
resolver, `resolveValueSlotMap` (`builtin/value-slot-map.ts`), is
generalised from the CRUD `resolveFieldValues`. An envelope goes through
`AutomationEngine.evaluateValueEnvelope` in the parent's scope and run
context. A literal is handed on as before. The subflow, map (once per
item, with the item variable bound) and script executors call it, and so
does the CRUD `fields` map. The dispatch is by shape. No `??` fallback
to the interpolator was added.
**ADR-0087.** The step-18 D3 entry
`18.flow-value-slot-template-dialect-refused` is amended: its surface
widens to the three maps, and its replacement and reason gain the callee
sentence. `registry.ts` is regenerated. There is no D2 entry, because
every whole-path spelling answers differently for an absent value. The
changeset marker is `not-required (already-registered …)`, and
`check-adr-0087-registration` accepts it.
**Sites migrated.** All of these are re-derived at HEAD with the stage-0
census instrument:
- showcase: 5 values in 3 nodes;
- todo: the 3 `computeNextTaskDueDate` inputs, each guarded because each
field may be absent and the function reads `null` as it read the empty
value;
- `flows.mdx`, `runtime-services/examples.mdx` and the
service-automation README;
- 2 dogfood fixtures, and the service-automation test fixtures (map 8,
script 3, subflow 2).
What remains at these positions: the 5 historical fixtures inside
`conversions/registry.ts`, which are conversion inputs and outputs, and
the deliberate refusal fixtures in the new pins. A positive control was
measured: the census rows that carried tokens at base now read as
envelopes.
## Pins and the ablations that turn them red
- `callee-input-value-slots.test.ts` runs 16 pins through the shipped
`AutomationEngine`:
- refusal at `registerFlow` and at the executor's guard, per position;
- evaluation: a list stays a list, a record stays a record, per item on
a `map`, and as `input` on a `script`;
- a fault names its source;
- the callee default: the template handed `undefined` and the default
applied; the guarded form hands `null`, which wins; writing the default
in the guard keeps it, and so does leaving the key out.
- Judge, ledger and contract pins in `@objectstack/spec`, ratchet
coverage in `config-expression-ledger.test.ts`, and the hint flips in
`lint-flow-patterns.test.ts`.
- **Ablations**, through `scripts/ablation-replace.mjs` (anchor hit,
blob changed, restore proven equal to HEAD with `git diff HEAD` empty):
1. The resolver hands envelopes to `interpolate` (at `3d832770e7`): 8 of
the 16 engine pins went red. These were the evaluation and
callee-default pins, and the refusal pins stayed green as expected.
2. The callee-slot table emptied (at `9387cf70ce`): the 6
callee-sentence pins went red.
3. The `subflow.input.*` ledger row renamed (at `9387cf70ce`): 12 judge
and ledger pins went red.
- Not ablated: the service-automation registration pins read
`@objectstack/spec`'s `dist`, and a dist-level ablation was not run.
They call the same judge function that ablations 2 and 3 turned red at
source.
## Measurements
- **Gates** at `9387cf70ce`: `dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 120 commands. All 120 exited 0, and
`--ran` with recorded exit codes reports 120 run, 0 NOT-MEASURED (a
derived zero). This includes `check-adr-0087-registration`,
`check-changeset-no-major`, `check-empty-changeset`, and the spec gates
`check:generated`, `check:api-surface`, `check:export-origins`,
`check:migration-registry`, `check:docs`, `check:skill-examples` and
`check:liveness`.
- **Tests after the second merge of `main`** (at `9387cf70ce`; the
incoming commits touched no file under `spec/src/automation`,
`service-automation` or `lint`):
- service-automation: 185 files, 2368 tests pass;
- spec `src/automation`, `src/migrations` and
`scripts/dropped-refinements.test.ts`: 41 files, 1518 pass;
- lint `lint-flow-patterns` and `validate-expressions*`: 8 files, 780
pass;
- metadata-protocol `reference-sites`: 22 pass.
- **Tests at `7d723c9fc1`/`3d832770e7`**:
- spec full suite: 20159 pass, plus one fail on the dropped-refinements
header totals, which `3d832770e7` corrects; that test file then passed
27 of 27;
- lint full: 135 files, 6240 pass;
- typecheck green for spec, service-automation and lint;
- example-todo typecheck and 238 tests, example-showcase typecheck and
408 tests;
- dogfood typecheck, plus the two touched dogfood tests (8 pass);
- `objectstack validate` on both examples exits 0 with no value-slot
finding.
- **Semver**: `@objectstack/spec` major,
`@objectstack/service-automation` major (pre mode `next`). No lint
source line changed, so there is no lint entry. No `api-surface/**` or
`export-origins/**` file moved. The exported ledger constants gain rows:
`FLOW_NODE_EXPRESSION_PATHS` +3, and
`LEDGER_DECLARED_NODE_CONFIG_SCHEMAS` + `map`, which widens the
`LedgerDeclaredNodeType` union. That is data in existing exports, not a
new export, so the line reads `no (narrowing)`. Flagged here for the
seat.
- **Size**: 38 files, +1099 / −160 against `main`.
## Acceptance notes
- The executor's contract parse judges a value with no position, so its
refusal names the base remedy without the callee sentence. The two build
doors carry the sentence, and this boundary is pinned.
- `packages/lint/src/lint-flow-patterns.ts` (the module comment near
`:659`) still lists `subflow.input` among the single-brace positions and
calls the date macros kept. It is an internal comment and is not
published. Carrier: S7, which deletes that arm.
- `engine.ts`'s `evaluateValueEnvelope` docblock lists only the
assignment and CRUD maps among its callers. The list is now incomplete
but not false. Carrier: S3, which edits `engine.ts`.
- `predicateSlotRefusal`'s message names the assignment and CRUD maps as
the value-role spelling. The list is incomplete but not false.
- `examples/app-todo/src/functions/task.functions.ts` still says no flow
node evaluates a value expression. That has been stale since the value
slots landed, before this pass.
- `validate-flow-template-paths` still path-checks single-brace tokens
at declared value slots, which doubles a finding the judge already
makes. This is the same note passes 1 to 3 carried; S7 removes it.
- The published skill (`skills/objectstack-automation/SKILL.md:268`,
"inputs are interpolated") is carried by #22585. The objectui designer
(`flow-node-config.ts` script inputs and subflow input) is carried by
the companion card. hotcrm's sites at these positions were not measured
and stay on the seat's ledger.
---
_Generated by [Claude
Code](https://claude.ai/code/session_016njDy8ozy9B9Ns5Y8kAWEK)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent b32ee3e commit f66fdc7
38 files changed
Lines changed: 1099 additions & 160 deletions
File tree
- .changeset
- content/docs
- automation
- kernel/runtime-services
- references/automation
- examples
- app-showcase/src/automation/flows
- app-todo/src/flows
- packages
- lint/src
- qa/dogfood/test/fixtures
- services/service-automation
- src
- builtin
- spec
- src
- automation
- migrations
- entries/semantic
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
226 | 226 | | |
227 | 227 | | |
228 | 228 | | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
233 | 236 | | |
234 | 237 | | |
235 | 238 | | |
| |||
282 | 285 | | |
283 | 286 | | |
284 | 287 | | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
285 | 298 | | |
286 | | - | |
287 | | - | |
| 299 | + | |
| 300 | + | |
288 | 301 | | |
289 | 302 | | |
290 | 303 | | |
| |||
399 | 412 | | |
400 | 413 | | |
401 | 414 | | |
402 | | - | |
403 | | - | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
404 | 418 | | |
405 | 419 | | |
406 | 420 | | |
| |||
439 | 453 | | |
440 | 454 | | |
441 | 455 | | |
442 | | - | |
| 456 | + | |
443 | 457 | | |
444 | 458 | | |
445 | 459 | | |
| |||
1210 | 1224 | | |
1211 | 1225 | | |
1212 | 1226 | | |
| 1227 | + | |
1213 | 1228 | | |
1214 | 1229 | | |
1215 | 1230 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
| 85 | + | |
86 | 86 | | |
87 | 87 | | |
88 | 88 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
211 | 211 | | |
212 | 212 | | |
213 | 213 | | |
214 | | - | |
| 214 | + | |
215 | 215 | | |
216 | 216 | | |
217 | 217 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
163 | 163 | | |
164 | 164 | | |
165 | 165 | | |
166 | | - | |
| 166 | + | |
167 | 167 | | |
168 | 168 | | |
169 | 169 | | |
| |||
181 | 181 | | |
182 | 182 | | |
183 | 183 | | |
184 | | - | |
| 184 | + | |
185 | 185 | | |
186 | 186 | | |
187 | 187 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
51 | | - | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
52 | 59 | | |
53 | 60 | | |
54 | 61 | | |
| |||
718 | 725 | | |
719 | 726 | | |
720 | 727 | | |
721 | | - | |
| 728 | + | |
722 | 729 | | |
723 | 730 | | |
724 | 731 | | |
| |||
733 | 740 | | |
734 | 741 | | |
735 | 742 | | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
736 | 747 | | |
737 | | - | |
738 | | - | |
| 748 | + | |
| 749 | + | |
739 | 750 | | |
740 | 751 | | |
741 | 752 | | |
| |||
843 | 854 | | |
844 | 855 | | |
845 | 856 | | |
846 | | - | |
| 857 | + | |
| 858 | + | |
847 | 859 | | |
848 | 860 | | |
849 | 861 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
366 | 366 | | |
367 | 367 | | |
368 | 368 | | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
369 | 375 | | |
370 | | - | |
371 | | - | |
372 | | - | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
373 | 385 | | |
374 | 386 | | |
375 | 387 | | |
| |||
0 commit comments