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
19 changes: 19 additions & 0 deletions .changeset/action-execute-ledger-dead.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
---
'@objectstack/spec': patch
---

liveness ledger: re-classify `action.execute` `live` → `dead` (#13036)

The entry claimed a `.transform` that lowers `execute` → `target` and drops the
alias. No such transform exists: `packages/spec/src/ui/action.zod.ts` has exactly
two `.transform` calls and both are `lowerRequiresFeature`. The alias and its
lowering were removed together in protocol 17 (#3855, landed 2026-07-28); the key
has been a `retiredKey` tombstone ever since, and `packages/cli/src/utils/lower-callables.ts`
declines to bind a function-valued `execute` on purpose so the tombstone fires.

Data-only: no schema, no runtime, no authoring surface changes — authoring
`execute` already failed `tsc` and the parse before this, and still does. The row
STAYS, per the `rls.priority` precedent a `retiredKey()` tombstone keeps the key
in the walked shape, so deleting the row would report UNCLASSIFIED. `liveness/` is
in this package's `files` array, so these ledgers ship in the npm tarball and this
is published data.
10 changes: 8 additions & 2 deletions packages/spec/liveness/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -282,11 +282,17 @@ as `live`, 10 were wrong** — a 77% error rate for the preview-renderer standar

| Verdict | Properties |
|---|---|
| `live`, evidence corrected to the real reader | `action.execute` (the spec transform's parse-time lowering — the second reader, objectui's ActionRunner, resolved the `target`/`execute` pair in the *opposite* direction; aligned and the alias dropped from the parsed output in #3713), `action.disabled` (six render surfaces), `flow.status` (engine gates binding + execution since `497bda853`) |
| `live`, evidence corrected to the real reader | `action.execute` (the spec transform's parse-time lowering — the second reader, objectui's ActionRunner, resolved the `target`/`execute` pair in the *opposite* direction; aligned and the alias dropped from the parsed output in #3713), `action.disabled` (six render surfaces), `flow.status` (engine gates binding + execution since `497bda853`) |
| corrected to `dead` + `authorWarn` | `action.shortcut`, `action.bulkEnabled`, `flow.active`, `skill.triggerPhrases`, `tool.category`, `tool.requiresConfirmation`, `tool.active`, `tool.builtIn`, `skill.permissions`*, `agent.knowledge` |

\* `skill.permissions` was subsequently pruned outright — it was never enforced.

† `action.execute` did not survive the correction either: the parse-time lowering
this row credits was removed with the alias in protocol 17 (#3855), and the entry
is `dead` since #13036. The tally above stands as the record of what the 2026-07
sweep found; it is not a current-state claim, which is why this row gets a
footnote rather than a rewrite.

Note the two failure directions the sweep exposed. Most entries **overstated**
liveness. But `flow.status` was *understated*: the file-level note still said
"status/active gate nothing", true when written and falsified a month later by
Expand DownExpand Up@@ -806,7 +812,7 @@ marker where the Notes cell goes, never a guess at what belongs there.
| object | aspirational tier (versioning/softDelete/search/recordName/keyPrefix) + tags/active/abstract REMOVED (#2377) — tombstoned in UNKNOWN_KEY_GUIDANCE; `enable.trash`/`mru` REMOVED (#2377 close-out) — tombstoned in the now-`.strict()` ObjectCapabilities; `isSystem` + `enable.searchable` CORRECTED to live (#2377 — sharing default-model + global-search opt-out; 2026-06 audit missed both readers); `tenancy.strategy`/`crossTenantAccess` REMOVED post-15.0 (#2763) |
| field | healthy — full dead set (vectorConfig/fileAttachmentConfig/dependencies, then referenceFilters/columnName/index) REMOVED (#2377); columnName also dropped the ADR-0062 D7 lint + StorageNameMapping column helpers |
| flow | dead count = **5 tombstone entries** + the kept docs field: `active`/`template`/nodes.`outputSchema`/errorHandling.`fallbackNodeId` REMOVED 2026-07-30 (#3896 close-out sweep — `active: false` never stopped a flow, `status` is the enforced lifecycle; faults route via per-node fault edges), plus errorHandling.`retryDelayMs` RENAMED to `backoffMs` 2026-08-04 (#4964). The rename is why the dead column moved while live did not: a rename is a removal on this ledger, so the old spelling is tombstoned (`retiredKey` keeps it in the walked shape) and the new spelling enters as its own `live` row. Read it beside the four above as the one entry here that cost an author nothing — the block was a THIRD encoding of the retry policy #4661 converged, invisible to that pass because it is an anonymous inline block with no exported name, and #4964 spelled its base delay `backoffMs` to match `job.retryPolicy` and a `try_catch` node's `retry`. Remaining dead = `description`, KEPT deliberately: docs-shaped, exempt from enforce-or-remove |
| action | `type:'form'` CORRECTED to live (objectui ActionRunner.executeForm, #2377); dead `timeout` REMOVED (#2377); `disabled` live since objectui#2863; `undoable` CORRECTED to live (#3714); `shortcut` + `bulkEnabled` REMOVED 2026-07-30 (#3896 close-out sweep — no keydown path dispatches shortcuts; the multi-select toolbar reads the view's bulkActions), and they are still the whole dead set. **#7367** (PR #7430) adds `description` as an authorable key, `live` on arrival — the only row this type has gained since that sweep |
| action | `type:'form'` CORRECTED to live (objectui ActionRunner.executeForm, #2377); dead `timeout` REMOVED (#2377); `disabled` live since objectui#2863; `undoable` CORRECTED to live (#3714); `shortcut` + `bulkEnabled` REMOVED 2026-07-30 (#3896 close-out sweep — no keydown path dispatches shortcuts; the multi-select toolbar reads the view's bulkActions). **#7367** (PR #7430) adds `description` as an authorable key, `live` on arrival — the only row this type has gained since that sweep. **#13036** makes the dead set three: `execute` joins it, re-classified `live` → `dead` 2026-08-29 with no key added or removed. Its `live` verdict rested on a `.transform` lowering `execute` → `target` that protocol 17 (#3855) removed along with the alias; the key has been a `retiredKey` tombstone since 2026-07-28, so the row stays (the `rls.priority` precedent) while the verdict does not. The rot was invisible to every citation check — the pointer was in range, in the right file, and the file names the key — and the entry carried no `verifiedAt`, so nothing ever re-asked |
| hook | model-healthy; label/description dead but KEPT deliberately (2026-07-30 sweep) — docs-shaped annotation fields, exempt from enforce-or-remove |
| permission | CRUD/FLS/RLS live; dead `contextVariables` REMOVED (ADR-0105 D11 — RLS resolves only the `current_user.*` built-ins plus runtime-staged `rlsMembership` sets). 2026-07-30 security-subset re-verification (all 33 entries `verifiedAt`-stamped): `rowLevelSecurity.enabled` was live-with-wrong-evidence and UNREAD — a disabled policy kept contributing its OR-branch grant; ENFORCED same day in rls-compiler (`getApplicablePolicies`), the `positions` ADR-0049 resolution repeated. `rowLevelSecurity.priority` CORRECTED to dead+authorWarn — semantically void under OR-combination (no conflict exists to order), a REMOVE candidate. `rls.label`/`description`/`tags` CORRECTED to dead (benign display, no consumer in either repo). `tabPermissions` was UNDERSTATED ("only hidden read" → the rank merge reads all four values; me-apps dogfood test exercises it). `allowExport` re-verified TRUE end-to-end (server-side 403 gate, not just the /me projection). `objects.allowRestore`/`allowPurge` REMOVED 2026-08-26 (#12497, ADR-0049 — the `restore`/`purge` ops never existed; the 2026-07-30 'live' verdict cited only the evaluator pre-mapping, retired in the same batch; `retiredKey` tombstones, keys return with M2 per the #1883 ruling) |
| position | (role's ADR-0090 successor) fully live; all 4 `verifiedAt`-stamped 2026-07-30 |
Expand Down
6 changes: 3 additions & 3 deletions packages/spec/liveness/action.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,9 +54,9 @@
"note": "server script (L1/L2) via engine.executeAction→body-runner. 2026-08-26: REPOINTED — the evidence cited packages/runtime/src/http-dispatcher.ts, which reads this key nowhere. Its 68 word-`body` occurrences are the inbound HTTP request body — the `body: any` parameter threaded through the handleX delegates (:890, :961, :1732, :1969 …) and the result envelope at :728 — plus the file's own \"Thin delegate — body extracted to ./domains/…\" extraction comments, where `body` means a function body. The consumer this note already NAMED in prose (body-runner) is where the read has always been; the surrounding action path was extracted into domains/actions.ts + action-execution.ts, and http-dispatcher.ts now only delegates (handleActions → handleActionsRequest at :1969-1970). WHY THE GATE COULD NOT SEE THE ROT: `body` is both a common English word and the name of the HTTP request member this dispatcher is built around, so the word-bounded key-mention check added in #11457 anchors on 68 unrelated hits and passes — the designed, honest limit of that signal, which is why this needed a hand call-graph read. Note the shape the repoint exposes: the NOTE's pointer (\"via engine.executeAction→body-runner\") stayed true the whole time while the EVIDENCE pointer rotted — the same split recorded on `requiredPermissions`, one layer over. 2026-08-28: RE-ANCHORED (#13003) — re-closed by hand against c459da6bc; both consumers stand where the 08-26 repoint put them, so the lines had not yet rotted and this is the grammar migration, not a second repair. The anchor is what makes that claim re-testable next time: `actionBodyRunnerFactory` is the symbol the header already calls the ONE choke point, so a consumer that moves inside this 798-line file keeps the pointer true and one that is deleted turns it red."
},
"execute": {
"status": "live",
"evidence": "packages/spec/src/ui/action.zod.ts:581 — the .transform lowers execute -> target and DROPS the alias, so authoring it changes what the runtime dispatches; `target` is the one slot every consumer reads",
"note": "RE-VERIFIED 2026-07 (#3686 preview-claim sweep): the prior `live` verdict cited only a metadata-admin PREVIEW panel, which echoes what the author typed. Verdict stands, but the real reader is the parse-time lowering, not a second field reader. DIVERGENCE RESOLVED in #3713: the alias is now consumed at parse time and removed from the output, so the 'both declared' conflict is unrepresentable rather than merely agreed-upon (mirrors agent.knowledge.topics -> sources, #1891). Before that fix three readers disagreed in two directions — this transform kept `target`, objectui ActionRunner did `execute || target`, and the CLI compile step (packages/cli/src/utils/lower-callables.ts) preferred a function on `execute`; all now prefer `target`. Note the server runtime never read `execute` at all (runtime/src/action-execution.ts gates on `target || body` and dispatches on `target`/`name`), which is why lowering is the whole of this property's liveness."
"status": "dead",
"verifiedAt": "2026-08-29",
"note": "REMOVED 2026-07-28 in protocol 17 (#3855, PR #3883) — tombstoned at the schema (retiredKey carries the prescription; authoring it is a tsc error and a parse error) and renamed out of sources by the protocol-17 conversion `action-execute-to-target`. The entry stays because retiredKey keeps the key in the walked shape (the rls.priority precedent); use `target`, the only handler slot — rename the key, the value (a handler / flow / URL ref) is unchanged, and `os migrate meta --from 16` lists the mechanical edits. The tombstone is packages/spec/src/ui/action.zod.ts#execute, and packages/cli/src/utils/lower-callables.ts#lowerActionCallable deliberately declines to bind a function-valued `execute` so the tombstone fires instead of the alias silently working in one authoring style and being rejected in every other. LEDGER CORRECTED 2026-08-29 (#13036) — the VERDICT was falsified, not the citation. This row read `live` on the claim that a .transform lowers execute -> target and DROPS the alias; no such transform exists. action.zod.ts has exactly two .transform calls (:526 and :1668) and both are lowerRequiresFeature, and the docblock above `target` (:559-562) says the alias was removed in protocol 17. The old pointer packages/spec/src/ui/action.zod.ts:581 was IN RANGE in an 1802-line file that names the key, so existence, line bound and key-mention were all green on it — what :581 holds today is a comment about the `global_nav` enum-VALUE retirement's declaration style, unrelated in every respect — and the entry carried no verifiedAt, so the re-verification clock never asked (the #12516 class in its purest form). HISTORY PRESERVED, because it is the argument for `target` being the single handler slot: DIVERGENCE RESOLVED in #3713 — before that fix three readers disagreed in two directions, the parse kept `target`, objectui ActionRunner did `execute || target`, and the CLI compile step (packages/cli/src/utils/lower-callables.ts) preferred a function on `execute`; #3713 made all three prefer `target`, and protocol 17 then removed the alias outright, so the both-declared conflict is unrepresentable rather than merely agreed-upon (mirrors agent.knowledge.topics -> sources, #1891). The server runtime never read `execute` at all — packages/runtime/src/action-execution.ts:525 gates on `target || body` and dispatches on `target`/`name` — so with the parse-time lowering gone there is no reader on any layer."
},
"params": {
"status": "live",
Expand Down
4 changes: 2 additions & 2 deletions packages/spec/liveness/state-counts.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,7 +30,7 @@ for both corollaries.
| `object` | 51 | 0 | 0 | 1 | 52 |
| `field` | 89 | 0 | 0 | 2 | 91 |
| `flow` | 34 | 0 | 6 | 0 | 40 |
| `action` | 42 | 0 | 2 | 2 | 46 |
| `action` | 41 | 0 | 3 | 2 | 46 |
| `hook` | 18 | 0 | 2 | 0 | 20 |
| `permission` | 36 | 0 | 6 | 0 | 42 |
| `position` | 12 | 0 | 0 | 0 | 12 |
Expand DownExpand Up@@ -58,4 +58,4 @@ for both corollaries.
| `capability` | 12 | 0 | 0 | 0 | 12 |
| `qa` | 4 | 0 | 5 | 0 | 9 |
| `manifest` | 22 | 0 | 21 | 0 | 43 |
| **total** | **821** | **5** | **78** | **10** | **914** |
| **total** | **820** | **5** | **79** | **10** | **914** |
Loading