You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(spec)!: the #3896 close-out sweep — fourteen inert authoring keys leave the surface (#4054)
* refactor(spec)!: the #3896 close-out sweep — fourteen inert authoring keys leave the surface
The enforce-or-remove worklist across the remaining governed types, each key
tombstoned with its prescription (retiredKey) and stripped by a protocol-17
conversion:
- action shortcut/bulkEnabled — no keydown path dispatches shortcuts; the
multi-select toolbar reads the view's bulkActions.
- flow active/template, node outputSchema, errorHandling.fallbackNodeId —
active:false never stopped a flow (status is the enforced lifecycle; the
default even READ as disabled while the engine treated unset as enabled);
faults route via per-node fault edges.
- view list responsive/performance, form defaultSort/aria — no renderer read
them. List aria/data stay live. form.data SURVIVED: the removal attempt
broke the build (defineForm writes data.provider='schema' onto every
metadata form; metadata-protocol serves it) — the build refuted the
ledger's dead verdict, so the entry is CORRECTED to live instead. The
sweep's method note: a ledger verdict is an input to removal, not a
substitute for the build's own proof.
- dashboard aria/performance + widget performance (+ orphaned
PerformanceConfigSchema) — no renderer applied them; widget.performance
had no ledger entry and was call-graph-closed fresh across both repos.
- agent knowledge (+ orphaned AIKnowledgeSchema) — declaring sources never
scoped retrieval (search_knowledge takes sourceIds from the LLM's
tool-call args). The same-major topics→sources rename is ABSORBED into the
removal pre-release: composed, its effect was unobservable, and the
fixture-disjointness contract of the conversion table enforces exactly
that judgment.
- skill triggerPhrases — never matched; activation is triggerConditions ∩
the agent's skills[] allowlist.
Deliberate keeps, recorded so they are not re-litigated: hook
label/description and flow description are docs-shaped annotation fields,
exempt from enforce-or-remove. Stale report aria/performance ledger entries
(schema already clean) deleted as hygiene.
Kit: 6 conversions + chain step (chain-replay green); retirement pins across
7 test files; forms pruned (action/flow/dashboard/agent/skill); i18n bundles
regenerated (merge mode); baselines edited deliberately (authorable-surface,
json-schema.manifest — AIKnowledge/PerformanceConfig unpublished); the
surface guard's coverage matcher generalized to ' / '-separated multi-key
conversion surfaces (exactly as strict per key); example flows drop
template:true (3 sites, caught by the tombstone's tsc leg); SKILL.md +
agents.mdx stop teaching the removed keys; v17 notes + upgrade checklist +
README ledger rows updated; major changeset.
spec 6932 / objectql 1179 / cli 830 green; all spec gates green; examples +
downstream-contract typecheck clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuViRSR1j6GJjf9qGbnqFX
* fix(liveness,skills): tombstone entries stay in the ledger; the SKILL.md defineSkill example drops triggerPhrases
CI's liveness gate caught the sweep's ledger discipline error: retiredKey
keeps a key in the walked shape, so its entry must STAY (dead + REMOVED
note — the rls.priority precedent), not be deleted (that is the strict-
removal discipline, used for the tool batch where keys left the shape).
All 14 entries restored with verifiedAt + per-key prescriptions; README
counts corrected to match. The local 'pass' before push was a masked exit
code ('| tail -1' swallows the gate's status) — gates now re-run with
explicit exit checks, which also surfaced the SKILL.md defineSkill example
still authoring triggerPhrases (a head-truncated grep miss; the os:check
harness is the authoritative sweeper and is green again).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuViRSR1j6GJjf9qGbnqFX
* docs(flows): the flow reference stops teaching the retired template/fallbackNodeId
Found by the corrected sweep after the SKILL.md catch — flows.mdx's
defineFlow example authored template: false, and the error-handling section
documented fallbackNodeId in both the example and the property table. The
:208 'template' hit is the notify node's email template (a different, live
config key); the sharing-rule and app 'active' hits are live keys on other
types — all three verified before leaving them alone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuViRSR1j6GJjf9qGbnqFX
---------
Co-authored-by: Claude <noreply@anthropic.com>
|**sources**|`string[]`| optional | Knowledge sources/tags to recruit RAG context from. Canonical key consumed by the agent renderer (objectui AgentPreview KnowledgeSummary). |
33
-
|**topics**|`any`| optional |[REMOVED]`knowledge.topics` was removed in @objectstack/spec 17 (#3855) — use `knowledge.sources`. Rename the key; the value (a list of source tags) is unchanged. Run `os migrate meta --from 16` to rewrite it automatically. |
34
-
|**indexes**|`string[]`| ✅ | Vector Store Indexes |
35
-
36
-
37
24
---
38
25
39
26
## AIModelConfig
@@ -67,7 +54,7 @@ const result = AIKnowledge.parse(data);
|**skills**|`string[]`| optional | Skill names to attach (Agent→Skill→Tool architecture) |
69
56
|**tools**|`any`| optional |[REMOVED]`agent.tools` was removed in @objectstack/spec 17 (#3894) — use `skills`. An agent reaches exactly the tools its surface-compatible skills declare (ADR-0064), so move each reference into a skill: a platform tool by its registered name, or `action_<name>` for one of your own AI-exposed Actions. Run `os migrate meta --from 16` to rewrite it automatically. |
|**knowledge**|`any`| optional |[REMOVED]`agent.knowledge` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — declaring knowledge sources/indexes on an agent never scoped retrieval: the `search_knowledge` tool takes `sourceIds` from the LLM's tool-call arguments, not from the agent record. Delete the block. Restrict retrieval at the knowledge-service / source level (per-source permissions), and describe intended grounding in `instructions` so the model asks for the right sources.|
71
58
|**active**|`boolean`| ✅ ||
72
59
|**access**|`string[]`| optional | Who can chat with this agent |
|**instructions**|`string`| optional | LLM instructions when skill is active |
41
41
|**tools**|`string[]`| ✅ | Tool names belonging to this skill (supports trailing wildcard, e.g. `action_*`) |
42
-
|**triggerPhrases**|`string[]`| optional |Phrases that activate this skill |
42
+
|**triggerPhrases**|`any`| optional |[REMOVED]`skill.triggerPhrases` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — phrases were never matched against the user's message; skill activation is `triggerConditions` (AND of context field/operator/value) intersected with the agent's `skills[]`, plus explicit /skill-name pinning. Delete the key. Put routing intent in `triggerConditions`; describe intent in `description`/`instructions` for the LLM.|
|**template**|`any`| optional |[REMOVED]`flow.template` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no designer or engine path ever read it, so flagging a flow as a template/subflow did nothing. Delete the key. Shared logic is invoked via a subflow NODE referencing the flow by name.|
|**active**|`boolean`| optional |Is active (Deprecated: use status)|
110
+
|**active**|`any`| optional |[REMOVED]`flow.active` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never had an effect: the engine arms flows from `status`, and `active: false` did NOT stop a flow (worse, the default read as disabled while the engine treated unset as enabled). Delete the key. Use `status: 'obsolete'` (or 'invalid') to unbind and disable a flow, `status: 'active'` to arm it.|
111
111
|**runAs**|`Enum<'system' \| 'user'>`| optional | Execution identity for the run: system = elevated (bypasses RLS), user = the triggering user (RLS-respecting). A run with no trigger user has no identity to scope to, so under user its data operations are REFUSED — declare system to make the elevation explicit. This covers schedule/time-relative/api triggers AND any record-change flow fired by a write that carried no user. |
|**template**|`any`| optional |[REMOVED]`flow.template` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no designer or engine path ever read it, so flagging a flow as a template/subflow did nothing. Delete the key. Shared logic is invoked via a subflow NODE referencing the flow by name.|
|**active**|`boolean`| optional |Is active (Deprecated: use status)|
60
+
|**active**|`any`| optional |[REMOVED]`flow.active` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never had an effect: the engine arms flows from `status`, and `active: false` did NOT stop a flow (worse, the default read as disabled while the engine treated unset as enabled). Delete the key. Use `status: 'obsolete'` (or 'invalid') to unbind and disable a flow, `status: 'active'` to arm it.|
61
61
|**runAs**|`Enum<'system' \| 'user'>`| optional | Execution identity for the run: system = elevated (bypasses RLS), user = the triggering user (RLS-respecting). A run with no trigger user has no identity to scope to, so under user its data operations are REFUSED — declare system to make the elevation explicit. This covers schedule/time-relative/api triggers AND any record-change flow fired by a write that carried no user. |
|**outputSchema**|`any`| optional |[REMOVED]`flow.nodes[].outputSchema` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it was never validated: the engine does not check node outputs against it, so it documented a contract nothing enforced. Delete the key. Downstream nodes read prior outputs via expressions (`{{nodeId.field}`}) regardless of any declaration.|
|**requiredPermissions**|`string[]`| optional |[ADR-0066 D4] Capabilities required to invoke this action. Enforced with 403 on the platform action route (script/flow/modal + MCP) and mirrored as a UI hide; a `type: api` action pointed at a custom endpoint must re-check it there. |
104
-
|**shortcut**|`string`| optional |Keyboard shortcut to trigger this action (e.g., "Ctrl+S")|
105
-
|**bulkEnabled**|`boolean`| optional |Whether this action can be applied to multiple selected records|
104
+
|**shortcut**|`any`| optional |[REMOVED]`action.shortcut` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never triggered anything: no keydown listener feeds ActionEngine.getShortcuts(), and objectui's keyboard stack (useKeyboardShortcuts) is hand-registered and never consults action metadata. Delete the key. For a real shortcut, register the key in the Console keyboard stack and have its handler invoke the action by name.|
105
+
|**bulkEnabled**|`any`| optional |[REMOVED]`action.bulkEnabled` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — the multi-select toolbar is driven by the LIST VIEW's `bulkActions` / `bulkActionDefs`, never by this flag, so setting it changed nothing. Delete the key and declare the action in the view's `bulkActions` instead.|
106
106
|**ai**|`{ exposed?: boolean; description?: string; category?: Enum<'data' \| 'action' \| 'flow' \| 'integration' \| 'vector_search' \| 'analytics' \| 'utility'>; paramHints?: Record<string, { description?: string; enum?: string \| number[]; examples?: any[] }>; … }`| optional | AI exposure (opt-in). Set ai.exposed=true + ai.description to make this callable by agents. |
107
107
|**recordIdParam**|`string`| optional | Body key to inject the row id into when running from a list_item context. |
108
108
|**recordIdField**|`string`| optional | Row field whose value seeds recordIdParam. Defaults to "id". |
|**aria**|`any`| optional |[REMOVED]`dashboard.aria` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no dashboard renderer ever applied it, so declared ARIA attributes silently did not reach the DOM. Delete the key.|
43
+
|**performance**|`any`| optional |[REMOVED]`dashboard.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; dashboard performance tuning was never implemented. Delete the key.|
0 commit comments