|
| 1 | +--- |
| 2 | +"@objectstack/spec": major |
| 3 | +"@objectstack/cli": patch |
| 4 | +--- |
| 5 | + |
| 6 | +feat(spec)!: retire the last three deprecated authorable aliases (#3855) |
| 7 | + |
| 8 | +Protocol 17 removes the three keys that a schema transform used to fold into a |
| 9 | +canonical slot and drop from the parsed output. Every slot now has exactly one |
| 10 | +spelling. |
| 11 | + |
| 12 | +## Migration |
| 13 | + |
| 14 | +| Removed | Use instead | Value shape | |
| 15 | +|---|---|---| |
| 16 | +| `action.execute` | `action.target` | unchanged — a handler / flow / URL ref | |
| 17 | +| `field.conditionalRequired` | `field.requiredWhen` | unchanged — a CEL predicate | |
| 18 | +| `agent.knowledge.topics` | `agent.knowledge.sources` | unchanged — a list of source tags | |
| 19 | + |
| 20 | +All three are **pure key renames**. Nothing about the value changes, and no |
| 21 | +runtime behaviour changes: each alias was already lowered into its canonical key |
| 22 | +at parse time and erased before any consumer saw it, so what shrinks is the |
| 23 | +authorable surface, not the semantics. |
| 24 | + |
| 25 | +**Run `os migrate meta --from <your current major>`.** It rewrites your source |
| 26 | +mechanically — these renames are registered as protocol-17 chain steps, so the |
| 27 | +tool applies all three (and every earlier step you skipped) in one pass. Manual |
| 28 | +alternative: rename the key. That is the entire fix. |
| 29 | + |
| 30 | +```diff |
| 31 | +- actions: [{ name: 'convert', type: 'script', execute: 'convertHandler' }] |
| 32 | ++ actions: [{ name: 'convert', type: 'script', target: 'convertHandler' }] |
| 33 | + |
| 34 | +- fields: { due_date: { type: 'date', conditionalRequired: 'record.stage == "closed"' } } |
| 35 | ++ fields: { due_date: { type: 'date', requiredWhen: 'record.stage == "closed"' } } |
| 36 | + |
| 37 | +- knowledge: { topics: ['faq', 'policies'], indexes: ['docs'] } |
| 38 | ++ knowledge: { sources: ['faq', 'policies'], indexes: ['docs'] } |
| 39 | +``` |
| 40 | + |
| 41 | +## Why these reject instead of being ignored |
| 42 | + |
| 43 | +None of the three schemas is `.strict()`, so deleting a key outright makes Zod |
| 44 | +**silently strip** it: the metadata would parse clean and the setting would |
| 45 | +simply never take effect — a script action bound to nothing, a field that is |
| 46 | +never required, an agent recruiting no RAG context. `FieldSchema` already |
| 47 | +carries a comment about the last time that happened (`dataQuality` / `cached`, |
| 48 | +#3726 / #3733). |
| 49 | + |
| 50 | +So each removed key is **tombstoned**: it stays declared as `never`, which makes |
| 51 | +writing it a `tsc` error at the authoring site *and* a parse error carrying the |
| 52 | +rename. You cannot lose the setting quietly. |
| 53 | + |
| 54 | +## Where to find this if you missed it |
| 55 | + |
| 56 | +The removal is in the machine-readable change manifest (`spec-changes.json`, |
| 57 | +ADR-0087 D4) as three protocol-17 conversions. Per-major manifests **compose**, |
| 58 | +so jumping several majors at once still yields a single answer rather than N |
| 59 | +changelogs to reconcile — the generated upgrade guide and the `spec_changes` MCP |
| 60 | +tool are both projections of that record. |
| 61 | + |
| 62 | +## Also removed |
| 63 | + |
| 64 | +`lintDeprecatedAliases` and its rule-id exports (`ACTION_TARGET_EXECUTE_CONFLICT`, |
| 65 | +`FIELD_REQUIREDWHEN_CONDITIONALREQUIRED_CONFLICT`, |
| 66 | +`AGENT_KNOWLEDGE_SOURCES_TOPICS_CONFLICT`, `DeprecatedAliasFinding`, |
| 67 | +`formatDeprecatedAliasFinding`). That pass existed to warn when an author |
| 68 | +declared both an alias and its canonical key, because the parse resolved the |
| 69 | +conflict silently. With the aliases gone the parse **rejects** instead, which is |
| 70 | +strictly louder — the rule has no subject left. If you imported any of these, |
| 71 | +delete the import; there is no replacement because the condition it reported can |
| 72 | +no longer occur. |
| 73 | + |
| 74 | +The CLI's inline-handler lowering also stops binding a function on `execute`. It |
| 75 | +runs before the parse, so binding it there would have kept the removed alias |
| 76 | +quietly working for one authoring style while every other style rejected it. |
0 commit comments