Skip to content
Merged
15 changes: 15 additions & 0 deletions .changeset/16094-liveness-dead-warns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@objectstack/lint': minor
---

Authoring a key whose liveness-ledger verdict is `dead` now draws a `liveness-dead-property` warning, and a `live-elsewhere` key a `liveness-live-elsewhere-property` warning, with no per-row `authorWarn` opt-in: the verdict itself is the warning. Before this, both rule ids were exported and never produced, because no shipped `dead` or `live-elsewhere` row opted in.

Clause-②: no

**Which keys warn.** A ledger row warns when its status is `dead`, `live-elsewhere` or `experimental`, or when it sets `authorWarn: true` (still the only way a `planned` row warns). Among authorable keys in the metadata types the rule walks, four are `dead` today: a view container's own `name` and `label` (the `defineView` container, not `list.label`), and a permission set's `rowLevelSecurity[].label` and `rowLevelSecurity[].description`. No walk visits `manifest`, `connectors` or realtime subscriptions, so their rows still warn nobody. That includes `manifest.runtime`, the one `live-elsewhere` row.

**The hint.** A row that warns only because of its `dead` or `live-elsewhere` verdict shows its `authorHint`, else the verdict's default hint: "Remove it — it is declared in the spec but not consumed at runtime." for `dead`. It never shows the ledger's internal `note`. Rows that opt in with `authorWarn`, and `experimental` rows, show exactly the hint they showed before.

**Retired keys.** A `retiredKey` tombstone keeps its `dead` row. Every command that parses (`os validate`, `os build`, the runtime publish gate) still refuses the key first, so it gets no second report. `os lint` does not parse: a config it accepts without `defineStack` that carries a retired key now gets a `liveness-dead-property` warning where it got nothing.

**What changes for a project.** Nothing is refused, and nothing changes without `--strict`. `os lint --strict` and `os validate --strict` now exit 1 instead of 0 on a stack that was otherwise warning-clean and authors a view container `label` or `name`, or a row-level-security policy `label` or `description`. A view container that carries its own `name` and `label` beside its `object` binding is one such shape: it draws two warnings per container, and under `--strict` that flips the exit. Across this repository's example apps, only `app-showcase` gains warnings: two, on one permission set's policy `label` and `description`, and no example's exit code changes. To clear the warning, delete the key: nothing reads it.
9 changes: 7 additions & 2 deletions packages/cli/test/lint-per-package-authoring-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,18 @@ const ordersObjects = [{
account: { name: 'account', type: 'lookup', label: 'Account', reference: 'pp_account' },
},
}];
// The containers bind by \`object\` and carry no \`name\` / \`label\` of their own:
// both keys are \`dead\` in the view ledger, and since #16094 each draws a
// union-run \`liveness-dead-property\` warning, which would break the "union
// raises NOTHING" premise this fixture exists to hold. The list's own \`label\`
// is live and stays.
const ordersViews = [
{
name: 'pp_account', label: 'Account List', object: 'pp_account',
object: 'pp_account',
list: { label: 'Account List', columns: ['name', 'industry'] },
},
{
name: 'pp_order', label: 'Order List', object: 'pp_order',
object: 'pp_order',
list: { label: 'Order List', columns: ['name', 'account'] },
},
];
Expand Down
6 changes: 3 additions & 3 deletions packages/lint/src/authoring-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1494,9 +1494,9 @@ export const AUTHORING_RULES: readonly AuthoringRule[] = [
})),
},
// The spec-liveness loop on the author side: a property the ledger marks
// dead-and-misleading or experimental is set hopefully and does nothing.
// Ledger-driven (entries opt in via `authorWarn`), so it is high-signal and
// never fatal.
// dead, live-elsewhere or experimental is set hopefully and does nothing
// here. Ledger-driven (those verdicts warn on their own; any other row only
// when it opts in via `authorWarn`), and never fatal.
{
name: 'lintLivenessProperties',
tier: 'advisory',
Expand Down
Loading
Loading