Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/20287-connector-actions-and-app-areas-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@objectstack/spec": patch
---

Liveness ledger: `connector.actions.description`, `connector.actions.outputSchema` and `app.areas.description` are now `live`, not `dead`. Studio reads each of them at the `.objectui-sha` pin, and each row cites that reader and its producer. Ledger data, two README Notes cells and the regenerated count shards only. ⛔ No schema, parse, `.describe()` or accept-set change.

The ledgers ship inside this package (`files[]` includes `liveness`), and `@objectstack/lint` reads them to decide which authored keys draw an advisory warning. None of the three rows sets `authorWarn`, so the set of warnings does not change.

- `connector.actions.description`: the flow designer's Action picker on a `connector_action` node shows each action's description beside its label.
- `connector.actions.outputSchema`: the flow designer offers a `connector_action` node's downstream references from the top-level `properties` of its action's `outputSchema`.
- `app.areas.description`: the Studio app preview lists each area, with its description beneath it when one is authored.
- Both connector rows are fed from the plugin and provider door, as their sibling `actions.*` rows are: the `actions` an author writes on a metadata connector entry never reach the registry the designer reads.
- The regenerated count shards: `connector` has 31 live and 23 dead (was 29 and 25), and `app` has 50 live and 8 dead (was 49 and 9).
4 changes: 2 additions & 2 deletions packages/spec/liveness/README.md

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions packages/spec/liveness/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,12 @@
"note": "2026-09-27 (#20146): REPOINTED off objectui's `AppSidebar.tsx` — deprecated, never mounted (the console renders `UnifiedSidebar`), and removed from objectui main by objectui PR #10617 — to the mounted reader(s) above, each re-read at the `.objectui-sha` pin f8a9d0fb and unchanged at objectui main fb91ac9b0."
},
"description": {
"status": "dead",
"verifiedAt": "2026-08-01",
"note": "display annotation no surface renders. Benign — docs-shaped, kept, not warned (hook.label precedent). VERDICT RE-TESTED AND UPHELD 2026-08-10 (#7427) under the previews ruling (#7131; README, 'Designer previews count as consumers'): 'no surface renders' is exactly the claim that ruling put back on the table for display keys, so it was measured instead of trusted. At objectui @e9ab52f9 AppPreview IS registered (previews/index.ts:40) and reachable (ResourceEditPage.tsx:949), and it contains ZERO occurrences of `areas` — it reads the app label at AppPreview.tsx:193 and walks `navigation` items, never the area collection. The area-level description reaches no human there."
"status": "live",
"verifiedAt": "2026-09-30",
"evidenceScope": "cross-repo",
"evidence": "objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/previews/AppPreview.tsx#readAreas (resolves each area's `description` through `resolveI18nLabel` in the designer locale; unauthored stays undefined and draws nothing); objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/previews/AppPreview.tsx#AppPreview (draws it under the area's label in the preview's Areas list, in read and design mode)",
"producer": "objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/previews/index.ts#registerBuiltinPreviews (registers AppPreview for `app`); objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx#MetadataResourceEditPageImpl (`app` registers no custom EditPage, so the generic edit route resolves `getMetadataPreview('app')` and hands it the draft); framework: packages/rest/src/meta-item-read-gate.ts#filterAppForUserWithReason (the served app keeps every key of each area it serves)",
"note": "RE-GRADED dead → live 2026-09-30 (#20299) under the #7131 previews ruling (README, 'Designer previews count as consumers'): for a display key, being shown to a human is the whole claimed effect. objectui#11027, read at the `.objectui-sha` pin db11afd4967, added the Areas list; the superseded note measured AppPreview at @e9ab52f9 with zero `areas` reads. UNCHANGED: still docs-shaped, deliberately KEPT (ADR-0033) and not authorWarn'd."
},
"navigation": {
"status": "live",
Expand All @@ -232,7 +235,7 @@
"note": "the active area's tree replaces the top-level navigation. Since #4722 area trees ARE server-side gated: filterAppForUser (packages/rest/src/rest-server.ts:1870) runs the SAME filterNav over every `areas[].navigation`, so an item's `requiredPermissions` / `requiresService` is enforced identically in both trees and a gated entry (with its objectName/pageName/componentRef target) never reaches the browser. An area emptied BY the gate is dropped, mirroring the top-level group collapse; an area authored empty is passed through. Still client-only at both levels: `visible` (CEL — needs a bound user context the read layer lacks) and `requiresObject`. The area-LEVEL keys stay retired (#4651) — this enforces the items inside, not a revived area gate. 2026-09-27 (#20146): REPOINTED off objectui's `AppSidebar.tsx` — deprecated, never mounted (the console renders `UnifiedSidebar`), and removed from objectui main by objectui PR #10617 — to the mounted reader(s) above, each re-read at the `.objectui-sha` pin f8a9d0fb and unchanged at objectui main fb91ac9b0. The `AppSchemaRenderer` leg is unchanged by this re-point."
}
},
"note": "Drilled because the gating keys diverged sharply from the live identity/tree keys — and they are gone: `visible` and `requiredPermissions` were RETIRED in 17.0.0 (#4651), rows DELETED because NavigationAreaSchema is strict, so the keys left the walked shape and retained rows would report ORPHAN. Keep drilling: `description` is the surviving benign dead key, and the drill is what would catch a new gate being added here."
"note": "Drilled because the gating keys diverged sharply from the live identity/tree keys — and they are gone: `visible` and `requiredPermissions` were RETIRED in 17.0.0 (#4651), rows DELETED because NavigationAreaSchema is strict, so the keys left the walked shape and retained rows would report ORPHAN. Keep drilling: the drill is what would catch a new gate being added here."
},
"contextSelectors": {
"children": {
Expand Down
20 changes: 13 additions & 7 deletions packages/spec/liveness/connector.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,28 @@
"note": "Display-shaped and settled by the #7131 split — the designer's action picker IS the claimed effect. REQUIRED, so there is no empty state."
},
"description": {
"status": "dead",
"verifiedAt": "2026-09-17",
"note": "Projected onto the wire and read by nobody. `engine.ts#getConnectorDescriptors` copies `description: a.description` into the `GET /api/v1/automation/connectors` payload, and no consumer in either repo reads it back: objectui's three connector-descriptor consumers take `name`/`label`/`origin` (`connectorsToOptions`), `key`/`label` (`connectorActionsToOptions`) and `key`/`inputSchema` (`connectorActionInputSchema`), and nothing in this repo reads a projected action's description. The lit control for that scan is `inputSchema` in the same projection, which IS read (see that row). Being on a machine-readable surface is not a consumer — the `view.label` precedent."
"status": "live",
"verifiedAt": "2026-09-30",
"evidenceScope": "cross-repo",
"evidence": "packages/services/service-automation/src/engine.ts#getConnectorDescriptors — `description: a.description` on each projected action, the `GET /api/v1/automation/connectors` payload; objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/inspectors/FlowReferenceField.tsx#connectorActionsToOptions (a non-blank string `description` becomes the action option's `hint`, fed by `useConnectorActionOptions` off that payload); objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/inspectors/FlowReferenceField.tsx#ReferenceCombobox (draws each option as `label — hint` in the `connector_action` node's Action picker)",
"producer": "packages/connectors/connector-slack/src/slack-connector.ts#createSlackConnector — a `description` on each of its three actions; packages/connectors/connector-openapi/src/openapi-connector.ts#createOpenApiConnector — `description: op.description`; packages/connectors/connector-mcp/src/mcp-connector.ts#createMcpConnector — the server's tool description verbatim; objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts#FLOW_NODE_CONFIG (the `connector_action` node's `actionId` field is a `connector-action` reference, which is what mounts that picker). Same two-door caveat as `actions.key`.",
"note": "RE-GRADED dead → live 2026-09-30 (#20287): objectui#11028, read at the `.objectui-sha` pin db11afd4967, shows it beside the action's label in the flow designer's Action picker. Display-shaped, so the picker IS the claimed effect (the #7131 split), as for `actions.label`. The superseded note — no consumer in either repo reads it back — was true until objectui#11028."
},
"inputSchema": {
"status": "live",
"verifiedAt": "2026-09-17",
"evidenceScope": "cross-repo",
"evidence": "packages/services/service-automation/src/engine.ts#getConnectorDescriptors — `inputSchema: a.inputSchema` on the projected action; objectui @dda8f3815 packages/app-shell/src/views/metadata-admin/inspectors/connector-input-fields.ts#connectorActionInputSchema finds the committed action in that payload and returns its `inputSchema`, and `FlowNodeInspector.tsx` types the connector node's whole Input section from it (`connectorInputFields(connectorActionInputSchema(...))`, objectui #4305) — an action that declares none falls back to the generic key/value repeater, which is the observable difference.",
"producer": "packages/connectors/connector-mcp/src/mcp-connector.ts — the MCP tool's own JSON Schema is passed straight through ('The MCP inputSchema is already JSON Schema'); packages/connectors/connector-openapi/src/openapi-connector.ts derives it from the operation's parameters. Same two-door caveat as `actions.key`.",
"note": "The one action key with a structural (not display) consumer, and it is cross-repo: the designer builds a typed form from it. Declared `z.record(z.string(), z.unknown())` — JSON Schema by convention, unvalidated here — so it has no child shape and nothing rides on a blanket verdict."
"note": "A structural (not display) consumer, cross-repo like `outputSchema`'s: the designer builds a typed form from it. Declared `z.record(z.string(), z.unknown())` — JSON Schema by convention, unvalidated here — so it has no child shape and nothing rides on a blanket verdict."
},
"outputSchema": {
"status": "dead",
"verifiedAt": "2026-09-17",
"note": "The twin of `inputSchema`, projected the same way and consumed by nothing — which is exactly what makes this row falsifiable rather than a guess. `engine.ts#getConnectorDescriptors` publishes `outputSchema: a.outputSchema`; the census over both repos finds no reader, while the identically-projected `inputSchema` one line above returns objectui's `connectorActionInputSchema` in the same scan. A flow node's downstream references are typed from the RUN's actual output (`nodeOutputRefs`), not from this declaration. ⛔ Not an ADR-0049 sweep candidate on this reading: the honest repair is to type the node's output refs from it, which is a feature decision, not a deletion."
"status": "live",
"verifiedAt": "2026-09-30",
"evidenceScope": "cross-repo",
"evidence": "packages/services/service-automation/src/engine.ts#getConnectorDescriptors — `outputSchema: a.outputSchema` on each projected action, the `GET /api/v1/automation/connectors` payload; objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/inspectors/flow-scope.ts#nodeOutputRefs (a committed `connector_action` node offers one `nodeId.key` reference per top-level `properties` key of its action's `outputSchema`, through `connectorActionOutputSchema` and `connectorActionOutputKeys`; no schema, no references); objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/inspectors/flow-scope.ts#resolveFlowScope (hands those references to every downstream node's and edge's data picker)",
"producer": "objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/inspectors/connector-input-fields.ts#useConnectorRegistry (reads that payload); objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.tsx#FlowNodeInspector and objectui @db11afd4967: packages/app-shell/src/views/metadata-admin/inspectors/FlowEdgeInspector.tsx#FlowEdgeInspector (each reads the registry when the flow holds a committed connector action and passes it to `useFlowScope` — the input the read depends on); framework: packages/connectors/connector-slack/src/slack-connector.ts#createSlackConnector — `outputSchema: slackOutputSchema()` on every action; packages/connectors/connector-openapi/src/openapi-connector.ts#buildOutputSchema; packages/connectors/connector-mcp/src/mcp-connector.ts#createMcpConnector — the tool's `outputSchema` when the server declares one. Same two-door caveat as `actions.key`.",
"note": "RE-GRADED dead → live 2026-09-30 (#20287): objectui#11028, read at the `.objectui-sha` pin db11afd4967, types a connector node's downstream references from it — the repair the superseded note named. The engine stores each top-level key of a node's `output` as `nodeId.key`, so the offered references are the ones a run writes. The designer offers them and stops flagging them as out of scope; nothing validates a reference against the schema."
},
"effect": {
"status": "live",
Expand Down
4 changes: 2 additions & 2 deletions packages/spec/liveness/permission.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,13 @@
"status": "dead",
"evidenceScope": "cross-repo",
"verifiedAt": "2026-08-10",
"note": "CORRECTED 2026-07-30 (was live with no evidence): no consumer in either repo. VERDICT RE-TESTED AND UPHELD 2026-08-10 (#7427) against the maintainer ruling that a designer preview rendering a key to a human is a runtime consumer (2026-08-10, #7131; README, 'Designer previews count as consumers'). This row is the closest structural twin of the four rows that ruling re-graded — a display `label` marked dead — so it was measured rather than assumed, and it comes out the other way. THE MEASUREMENT, at objectui @e9ab52f9: PermissionPreview IS registered for `permission` (previews/index.ts:71) and IS reachable (ResourceEditPage.tsx:949), so the preview lookup runs; but PermissionPreview.tsx:111 reads `rowLevelSecurity` only as an ARRAY and PermissionPreview.tsx:164 renders `${rls.length} RLS rules` — a COUNT. It never indexes a policy, never reads `.label`, and no policy field reaches a human through it. The 2026-07-30 wording 'PermissionPreview counts them' was exact, and counting is not rendering: the ruling turns on the VALUE being shown to a person, which is precisely what a length does not do. The other measured surface is PermissionAdvancedFacets.tsx:192-193 (reads `draft.rowLevelSecurity`, strips retired keys) and :264 (writes it back) — an authoring FORM, the 'authoring surface echoing input' the 2026-07 correction rejected, and the new ruling names previews, not edit forms. So both halves of the original closure survive it. Benign display metadata — deliberately NOT authorWarn'd. To re-open this row, the thing to look for is a preview that renders the policy's label text, not another surface that counts policies."
"note": "No reader reaches it, measured at objectui @db11afd4967. PermissionPreview.tsx#readPolicies reads each policy's `label`, and `PermissionPreview` draws it in its Row-Level Security list, but no route mounts that preview for `permission`. ResourceEditPage.tsx#MetadataResourceEditPage hands every non-create `permission` item to the custom EditPage that services/builtinComponents.tsx registers, `PermissionMatrixEditPage`. That page renders no preview, and its RLS form `PermissionAdvancedFacets` reads no policy label. Create mode previews only object, report and dataset. The other `getMetadataPreview` callers (`EmbeddedItemEditor`, `StudioDesignSurface`, the dev-only preview gallery) never open a `permission`. A preview no route mounts is a read point that never runs (README, 'Designer previews count as consumers'). Benign display metadata, deliberately NOT authorWarn'd. To re-open: a mounted surface that draws the policy's label."
},
"description": {
"status": "dead",
"evidenceScope": "cross-repo",
"verifiedAt": "2026-08-10",
"note": "CORRECTED 2026-07-30 (was live with no evidence): same closure as label. RE-TESTED AND UPHELD 2026-08-10 (#7427) with `label`, same measurement at objectui @e9ab52f9 — the permission preview counts RLS policies (PermissionPreview.tsx:164) and renders no field of any individual policy. Benign — not authorWarn'd."
"note": "Same closure as `label`, at objectui @db11afd4967: `PermissionPreview` draws each policy's `description` beneath its row, but no route mounts it for `permission`. `PermissionMatrixEditPage` takes the item, and its RLS form reads no description. Benign, not authorWarn'd."
},
"object": {
"status": "live",
Expand Down
2 changes: 1 addition & 1 deletion packages/spec/liveness/state-counts/app.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ committed anywhere: `check:liveness` sums the shards when it reads them.

| Type | live | exp | elsewhere | dead | planned | classified |
|---|---|---|---|---|---|---|
| `app` | 49 | 0 | 0 | 9 | 1 | 59 |
| `app` | 50 | 0 | 0 | 8 | 1 | 59 |
2 changes: 1 addition & 1 deletion packages/spec/liveness/state-counts/connector.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ committed anywhere: `check:liveness` sums the shards when it reads them.

| Type | live | exp | elsewhere | dead | planned | classified |
|---|---|---|---|---|---|---|
| `connector` | 29 | 0 | 0 | 25 | 1 | 55 |
| `connector` | 31 | 0 | 0 | 23 | 1 | 55 |
Loading
Loading