Skip to content

Commit 12a19a8

Browse files
os-zhuangclaude
andauthored
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>
1 parent 4965bfa commit 12a19a8

58 files changed

Lines changed: 1198 additions & 916 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
"@objectstack/spec": major
3+
---
4+
5+
refactor(spec)!: the #3896 close-out sweep — fourteen inert authoring keys leave the surface
6+
7+
The enforce-or-remove worklist across the remaining metadata types, each key
8+
tombstoned at its schema with the prescription (`retiredKey`) and stripped by
9+
a protocol-17 conversion (`os migrate meta` rewrites sources):
10+
11+
- **action** `shortcut` / `bulkEnabled` — no keydown path ever dispatched a
12+
shortcut; the multi-select toolbar reads the view's `bulkActions`.
13+
- **flow** `active` / `template`, node `outputSchema`, errorHandling
14+
`fallbackNodeId``active: false` never stopped a flow (`status` is the
15+
enforced lifecycle; the default even read as disabled while the engine
16+
treated unset as enabled); faults route via per-node fault edges.
17+
- **view** list `responsive` / `performance`, form `defaultSort` / `aria`
18+
no renderer read any of them. List `aria`/`data` stay live, and **form
19+
`data` survived the sweep**: the removal attempt broke the build —
20+
`defineForm` writes `data.provider='schema'` onto every metadata form —
21+
which re-verified the entry; its ledger verdict is corrected instead.
22+
- **dashboard** `aria` / `performance`, widget `performance` (+ the orphaned
23+
`PerformanceConfigSchema`) — no renderer applied them; virtual scrolling is
24+
the live top-level `virtualScroll`.
25+
- **agent** `knowledge` (+ `AIKnowledgeSchema`) — declaring sources/indexes
26+
never scoped retrieval: `search_knowledge` takes `sourceIds` from the LLM's
27+
tool-call arguments. The protocol-17 `topics``sources` rename is absorbed
28+
into the removal pre-release.
29+
- **skill** `triggerPhrases` — phrases were never matched; activation is
30+
`triggerConditions` ∩ the agent's `skills[]` allowlist.
31+
32+
Docs-shaped annotation fields (`hook.label`/`description`, `flow.description`)
33+
are deliberately KEPT and so noted in the ledger — they document intent for
34+
the next reader and are exempt from enforce-or-remove. The stale report
35+
`aria`/`performance` ledger entries (schema already clean) are deleted as
36+
hygiene.

content/docs/ai/agents.mdx

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -258,13 +258,12 @@ Always be professional and data-driven.`,
258258

259259
// Capability comes from skills — the only tool-bearing slot (ADR-0064).
260260
// Each skill names the platform tools and `action_<name>` tools it needs.
261+
// (There is no agent-level `knowledge` block — it was removed in protocol
262+
// 17 (#3896 close-out): declaring sources never scoped retrieval. Restrict
263+
// access at the knowledge-service/source level; describe intended
264+
// grounding in `instructions`.)
261265
skills: ['lead_qualification', 'opportunity_coaching', 'email_drafting'],
262266

263-
// RAG access: sources to recruit knowledge from + vector store indexes.
264-
knowledge: {
265-
sources: ['sales-playbook', 'leads', 'opportunities'],
266-
indexes: ['sales_docs'],
267-
},
268267
});
269268
```
270269

@@ -298,10 +297,6 @@ Always be empathetic and solution-focused.`,
298297
// Protocol). Neither needs a `defineTool` record.
299298
skills: ['case_triage', 'knowledge_search', 'response_drafting'],
300299

301-
knowledge: {
302-
sources: ['support-kb', 'cases'],
303-
indexes: ['support_docs'],
304-
},
305300
});
306301
```
307302

@@ -371,10 +366,6 @@ Use the data tools to query records and aggregate metrics.`,
371366
// names directly — see "Natural Language Queries".
372367
skills: ['revenue_forecasting'],
373368

374-
knowledge: {
375-
sources: ['opportunities', 'pipeline'],
376-
indexes: ['sales_docs'],
377-
},
378369
});
379370
```
380371

content/docs/automation/flows.mdx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const approvalFlow = {
1717
type: 'record_change',
1818
version: 1,
1919
status: 'active',
20-
template: false,
2120
runAs: 'system',
2221

2322
variables: [
@@ -74,7 +73,6 @@ const approvalFlow = {
7473
| `version` | `number` | optional | Version number (defaults to `1`) |
7574
| `status` | `enum` | optional | `'draft'`, `'active'`, `'obsolete'`, `'invalid'` (defaults to `'draft'`) |
7675
| `type` | `FlowType` || Flow trigger type (see below) |
77-
| `template` | `boolean` | optional | Is this a reusable subflow template (defaults to `false`) |
7876
| `runAs` | `enum` | optional | `'system'` or `'user'` execution context (defaults to `'user'`) |
7977
| `variables` | `FlowVariable[]` | optional | Input/output variables |
8078
| `nodes` | `FlowNode[]` || Flow nodes |
@@ -670,7 +668,6 @@ errorHandling: {
670668
strategy: 'retry', // 'fail' | 'retry' | 'continue'
671669
maxRetries: 3,
672670
retryDelayMs: 5000,
673-
fallbackNodeId: 'error_handler',
674671
}
675672
```
676673

@@ -679,7 +676,6 @@ errorHandling: {
679676
| `strategy` | `enum` | `'fail'` (stop), `'retry'` (retry), `'continue'` (skip) |
680677
| `maxRetries` | `number` | Maximum retry attempts (0-10) |
681678
| `retryDelayMs` | `number` | Delay between retries (ms) |
682-
| `fallbackNodeId` | `string` | Node to execute on failure |
683679

684680
## Discovery & Registration
685681

content/docs/references/ai/agent.mdx

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,13 @@ AI Model Configuration
1414
## TypeScript Usage
1515

1616
```typescript
17-
import { AIKnowledge, AIModelConfig, Agent, StructuredOutputConfig, StructuredOutputFormat, TransformPipelineStep } from '@objectstack/spec/ai';
18-
import type { AIKnowledge, AIModelConfig, Agent, StructuredOutputConfig, StructuredOutputFormat, TransformPipelineStep } from '@objectstack/spec/ai';
17+
import { AIModelConfig, Agent, StructuredOutputConfig, StructuredOutputFormat, TransformPipelineStep } from '@objectstack/spec/ai';
18+
import type { AIModelConfig, Agent, StructuredOutputConfig, StructuredOutputFormat, TransformPipelineStep } from '@objectstack/spec/ai';
1919

2020
// Validate data
21-
const result = AIKnowledge.parse(data);
21+
const result = AIModelConfig.parse(data);
2222
```
2323

24-
---
25-
26-
## AIKnowledge
27-
28-
### Properties
29-
30-
| Property | Type | Required | Description |
31-
| :--- | :--- | :--- | :--- |
32-
| **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-
3724
---
3825

3926
## AIModelConfig
@@ -67,7 +54,7 @@ const result = AIKnowledge.parse(data);
6754
| **surface** | `Enum<'ask' \| 'build'>` || Product surface this agent binds ('ask' \| 'build') — ADR-0063 §1 |
6855
| **skills** | `string[]` | optional | Skill names to attach (Agent→Skill→Tool architecture) |
6956
| **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. |
70-
| **knowledge** | `{ sources?: string[]; topics?: any; indexes: string[] }` | optional | RAG access |
57+
| **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. |
7158
| **active** | `boolean` || |
7259
| **access** | `string[]` | optional | Who can chat with this agent |
7360
| **permissions** | `string[]` | optional | Required permission-set capabilities |

content/docs/references/ai/skill.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const result = Skill.parse(data);
3939
| **surface** | `Enum<'ask' \| 'build' \| 'both'>` || Agent surface this skill binds to ('ask' \| 'build' \| 'both') — ADR-0063 §3 |
4040
| **instructions** | `string` | optional | LLM instructions when skill is active |
4141
| **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. |
4343
| **triggerConditions** | `{ field: string; operator: Enum<'eq' \| 'neq' \| 'in' \| 'not_in' \| 'contains'>; value: string \| string[] }[]` | optional | Programmatic activation conditions |
4444
| **active** | `boolean` || Whether the skill is enabled |
4545
| **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this skill. |

content/docs/references/api/automation-api.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,12 @@ const result = AutomationApiErrorCode.parse(data);
102102
| **errorMessage** | `string` | optional | Toast shown when a screen flow fails (defaults to the raw error). |
103103
| **version** | `integer` | optional | Version number |
104104
| **status** | `Enum<'draft' \| 'active' \| 'obsolete' \| 'invalid'>` | optional | Deployment status |
105-
| **template** | `boolean` | optional | Is logic template (Subflow) |
105+
| **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. |
106106
| **type** | `Enum<'autolaunched' \| 'record_change' \| 'schedule' \| 'screen' \| 'api'>` || Flow type |
107107
| **variables** | `{ name: string; type: string; isInput?: boolean; isOutput?: boolean }[]` | optional | Flow variables |
108108
| **nodes** | `{ id: string; type: string; label: string; config?: Record<string, any>; … }[]` || Flow nodes |
109109
| **edges** | `{ id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[]` || Flow connections |
110-
| **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. |
111111
| **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. |
112112
| **errorHandling** | `{ strategy?: Enum<'fail' \| 'retry' \| 'continue'>; maxRetries?: integer; retryDelayMs?: integer; backoffMultiplier?: number; … }` | optional | Flow-level error handling configuration |
113113
| **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this flow. |

content/docs/references/automation/flow.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ const result = Flow.parse(data);
5252
| **errorMessage** | `string` | optional | Toast shown when a screen flow fails (defaults to the raw error). |
5353
| **version** | `integer` | optional | Version number |
5454
| **status** | `Enum<'draft' \| 'active' \| 'obsolete' \| 'invalid'>` | optional | Deployment status |
55-
| **template** | `boolean` | optional | Is logic template (Subflow) |
55+
| **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. |
5656
| **type** | `Enum<'autolaunched' \| 'record_change' \| 'schedule' \| 'screen' \| 'api'>` || Flow type |
5757
| **variables** | `{ name: string; type: string; isInput?: boolean; isOutput?: boolean }[]` | optional | Flow variables |
5858
| **nodes** | `{ id: string; type: string; label: string; config?: Record<string, any>; … }[]` || Flow nodes |
5959
| **edges** | `{ id: string; source: string; target: string; condition?: string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }; … }[]` || Flow connections |
60-
| **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. |
6161
| **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. |
6262
| **errorHandling** | `{ strategy?: Enum<'fail' \| 'retry' \| 'continue'>; maxRetries?: integer; retryDelayMs?: integer; backoffMultiplier?: number; … }` | optional | Flow-level error handling configuration |
6363
| **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this flow. |
@@ -103,7 +103,7 @@ const result = Flow.parse(data);
103103
| **position** | `{ x: number; y: number }` | optional | |
104104
| **timeoutMs** | `integer` | optional | Maximum execution time for this node in milliseconds |
105105
| **inputSchema** | `Record<string, { type: Enum<'string' \| 'number' \| 'boolean' \| 'object' \| 'array'>; required: boolean; description?: string }>` | optional | Input parameter schema for this node |
106-
| **outputSchema** | `Record<string, { type: Enum<'string' \| 'number' \| 'boolean' \| 'object' \| 'array'>; description?: string }>` | optional | Output schema declaration for this node |
106+
| **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. |
107107
| **waitEventConfig** | `{ eventType: Enum<'timer' \| 'signal' \| 'webhook' \| 'manual' \| 'condition'>; timerDuration?: string; signalName?: string; timeoutMs?: integer; … }` | optional | Configuration for wait node event resumption |
108108
| **boundaryConfig** | `{ attachedToNodeId: string; eventType: Enum<'error' \| 'timer' \| 'signal' \| 'cancel'>; interrupting: boolean; errorCode?: string; … }` | optional | Configuration for boundary events attached to host nodes |
109109

content/docs/references/ui/action.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ const result = Action.parse(data);
101101
| **requiresFeature** | `Enum<'twoFactor' \| 'passkeys' \| 'magicLink' \| 'organization' \| 'multiOrgEnabled' \| 'degradedTenancy' \| 'oidcProvider' \| 'sso' \| 'ssoEnforced' \| 'deviceAuthorization' \| 'admin' \| 'phoneNumber' \| 'phoneNumberOtp'>` | optional | Public auth feature flag gating this action; lowered into `visible` at parse time. |
102102
| **disabled** | `boolean \| string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | Boolean or predicate (CEL) — action is disabled when TRUE. |
103103
| **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. |
106106
| **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. |
107107
| **recordIdParam** | `string` | optional | Body key to inject the row id into when running from a list_item context. |
108108
| **recordIdField** | `string` | optional | Row field whose value seeds recordIdParam. Defaults to "id". |

content/docs/references/ui/dashboard.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ const result = Dashboard.parse(data);
3939
| **refreshInterval** | `number` | optional | Auto-refresh interval in seconds |
4040
| **dateRange** | `{ field?: string; defaultRange: Enum<'today' \| 'yesterday' \| 'this_week' \| 'last_week' \| 'this_month' \| 'last_month' \| 'this_quarter' \| 'last_quarter' \| 'this_year' \| 'last_year' \| 'last_7_days' \| 'last_30_days' \| 'last_90_days' \| 'custom'>; allowCustomRange: boolean }` | optional | Global dashboard date range filter configuration |
4141
| **globalFilters** | `{ name?: string; field: string; label?: string; type?: Enum<'text' \| 'select' \| 'date' \| 'number' \| 'lookup'>; … }[]` | optional | Global filters that apply to all widgets in the dashboard |
42-
| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes |
43-
| **performance** | `{ lazyLoad?: boolean; virtualScroll?: object; cacheStrategy?: Enum<'none' \| 'cache-first' \| 'network-first' \| 'stale-while-revalidate'>; prefetch?: boolean; … }` | optional | Performance optimization settings |
42+
| **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. |
4444
| **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this dashboard. |
4545
| **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). |
4646
| **_lockReason** | `string` | optional | Human-readable reason shown when a write is refused by _lock. |

0 commit comments

Comments
 (0)