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
14 changes: 14 additions & 0 deletions .changeset/18801-sharing-rule-note-quotation-rot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@objectstack/spec": patch
---

`liveness/sharing_rule.json` — the file `_note` stops quoting the `declarative-rbac-seeding` proof-registry entry VERBATIM, so the pointer it hands a reader survives the next rewrite of that entry's prose (#18801).

The ledgers ship inside this package, so this is a pointer a consumer can actually follow. The note said the entry's `blockedReason` "reads" a specific sentence and quoted it. PR #18797 (`ac720a9865`) rewrote that reason — correctly, because #18587 had made its premise false — and the quoted sentence stopped existing in the very file the note sends a reader to. Measured repo-wide with a fold-proof predicate (whitespace folds and TypeScript `' + '` concatenation seams dissolved before matching, because the registry splits every reason across source literals mid-phrase): the quoted string read **0** on `main`, while the entry id `declarative-rbac-seeding` read **18** in the same run.

- **The judgement was never wrong; the quotation was.** The seeding does falsify the entry's original premise, and the rewritten reason on the entry now records exactly that — as a real ADR-0054 §3 binding candidate held back by the adoption act. The note still asserts it, in its own words.
- **What replaces the quote is an id, not a better sentence.** `declarative-rbac-seeding` is the entry's key: exactly **1** of the registry's **42** `id:` declarations spells it, and it reads 6 occurrences across 5 lines of `scripts/liveness/proof-registry.mts` — so a reader who greps it lands on the entry rather than on nothing. Quoting prose that changes is what rotted; an id does not rot on someone else's schedule. ⚠️ Measured, not assumed: nothing *asserts* those ids unique — the one other declaration of this id in the tree is `packages/qa/dogfood/test/authz-conformance.matrix.ts`, which names the same proof on purpose.
- **The old premise is paraphrased, deliberately not re-quoted.** A paraphrase of a premise that has already been retired cannot rot: the text it describes is frozen in history and nothing will rewrite it again.
- **The two sibling ledgers already wrote it this way.** `liveness/api.json` and `liveness/qa.json` cite `proof-registry.mts` by name and claim, and quote none of its prose.

No verdict moved. Every `status`, `verifiedAt`, `evidence`, `producer` and per-row `note` in the file is byte-identical to `main`; the only changed field is `_note`, and `check:liveness` reports `sharing_rule 17 classified (live 16, planned 1)` before and after.
2 changes: 1 addition & 1 deletion packages/spec/liveness/sharing_rule.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"type": "sharing_rule",
"_note": "SharingRuleSchema (packages/spec/src/security/sharing.zod.ts) — `SharingRuleSchema = CriteriaSharingRuleSchema`, the one authorable rule form. Seeded 2026-09-17 (#18582): the SECOND of the three PENDING_GOVERNANCE debts #18133 declared when PR #18581 widened the governance denominator from the registered kinds to `authorableTypes()`; `connector` and `analytics_cube` are still owed on that card. NOT a registered metadata KIND — it is bound in `UNREGISTERED_KIND_SCHEMAS` (#6245) and reaches this walk through `getMetadataTypeSchema`'s unregistered-kind fallback, so the ledger governs it while `listMetadataTypeSchemaTypes()` still does not enumerate it. THE SHAPE FACT THAT DECIDES EVERY ROW BELOW: the authoring shape is not the enforced shape. ADR-0057 D6 makes the RUNTIME row canonical (`sys_sharing_rule`: `object_name` + `criteria_json` + `recipient_type`/`recipient_id` + `access_level`) and `bootstrapDeclaredSharingRules` TRANSLATES each authored key into it at boot — nothing re-parses `SharingRuleSchema` at enforcement time. So every consumer cited below reads a COLUMN that a producer had to populate, and every row therefore carries a `producer` (#4837) naming the threading site: a consumer citation alone would be the `seed.env` shape, where the mechanism was right and nobody supplied the input. PREVIEW READ POINTS ENUMERATED (the #7131 mechanical rule, objectui @dda8f381): `registerBuiltinPreviews()` in packages/app-shell/src/views/metadata-admin/previews/index.ts registers twenty types and `sharing_rule` is NOT one of them — this type has no registered metadata-admin preview. Recorded rather than skipped, because \"the type has no registered preview\" is the sentence a later sweep needs. What objectui DOES consume is the whole SHAPE: `clientValidation.ts`'s `AUTHOR_SHAPE_ONLY_TYPES` gates the metadata-admin CREATE door on `SharingRuleSchema` itself (the EDIT door is deliberately not gated — a served body carries the `_diagnostics` read decoration this `.strict()` schema rejects), so an authored rule that fails this schema is refused before it is written. DECOY, do not cite it as a consumer: objectui's own `SharingRuleConfig` (objectui packages/types/src/permissions.ts) is a DIFFERENT shape — `{ type: 'role'|'user'|'group'|'public', entity, actions, filter }` — re-exported twice and read by nothing. It matches this type by name only. RUNTIME PROOF THAT ALREADY EXISTS, unbound: packages/qa/dogfood/test/showcase-declarative-rbac-seeding.dogfood.test.ts authors `sharingRules[]` on the showcase stack and asserts the seeded row's `object_name`, `recipient_type`, `recipient_id` and translated `criteria_json` — i.e. it exercises `name`/`object`/`sharedWith.type`/`sharedWith.value`/`condition` end to end. It is registered in ../scripts/liveness/proof-registry.mts as `declarative-rbac-seeding` with `bound: false`, whose `blockedReason` reads \"not on a per-type authorable property\" — a premise this seeding falsifies. ⛔ No `proof` is claimed on any row here: binding a high-risk class is a separate ADR-0054 §3 act, one class at a time, and it is filed rather than slipped in.",
"_note": "SharingRuleSchema (packages/spec/src/security/sharing.zod.ts) — `SharingRuleSchema = CriteriaSharingRuleSchema`, the one authorable rule form. Seeded 2026-09-17 (#18582): the SECOND of the three PENDING_GOVERNANCE debts #18133 declared when PR #18581 widened the governance denominator from the registered kinds to `authorableTypes()`; `connector` and `analytics_cube` are still owed on that card. NOT a registered metadata KIND — it is bound in `UNREGISTERED_KIND_SCHEMAS` (#6245) and reaches this walk through `getMetadataTypeSchema`'s unregistered-kind fallback, so the ledger governs it while `listMetadataTypeSchemaTypes()` still does not enumerate it. THE SHAPE FACT THAT DECIDES EVERY ROW BELOW: the authoring shape is not the enforced shape. ADR-0057 D6 makes the RUNTIME row canonical (`sys_sharing_rule`: `object_name` + `criteria_json` + `recipient_type`/`recipient_id` + `access_level`) and `bootstrapDeclaredSharingRules` TRANSLATES each authored key into it at boot — nothing re-parses `SharingRuleSchema` at enforcement time. So every consumer cited below reads a COLUMN that a producer had to populate, and every row therefore carries a `producer` (#4837) naming the threading site: a consumer citation alone would be the `seed.env` shape, where the mechanism was right and nobody supplied the input. PREVIEW READ POINTS ENUMERATED (the #7131 mechanical rule, objectui @dda8f381): `registerBuiltinPreviews()` in packages/app-shell/src/views/metadata-admin/previews/index.ts registers twenty types and `sharing_rule` is NOT one of them — this type has no registered metadata-admin preview. Recorded rather than skipped, because \"the type has no registered preview\" is the sentence a later sweep needs. What objectui DOES consume is the whole SHAPE: `clientValidation.ts`'s `AUTHOR_SHAPE_ONLY_TYPES` gates the metadata-admin CREATE door on `SharingRuleSchema` itself (the EDIT door is deliberately not gated — a served body carries the `_diagnostics` read decoration this `.strict()` schema rejects), so an authored rule that fails this schema is refused before it is written. DECOY, do not cite it as a consumer: objectui's own `SharingRuleConfig` (objectui packages/types/src/permissions.ts) is a DIFFERENT shape — `{ type: 'role'|'user'|'group'|'public', entity, actions, filter }` — re-exported twice and read by nothing. It matches this type by name only. RUNTIME PROOF THAT ALREADY EXISTS, unbound: packages/qa/dogfood/test/showcase-declarative-rbac-seeding.dogfood.test.ts authors `sharingRules[]` on the showcase stack and asserts the seeded row's `object_name`, `recipient_type`, `recipient_id` and translated `criteria_json` — i.e. it exercises `name`/`object`/`sharedWith.type`/`sharedWith.value`/`condition` end to end. It is registered in ../scripts/liveness/proof-registry.mts as `declarative-rbac-seeding` with `bound: false`; grep that id there for the entry’s current reason — ⛔ it is deliberately NOT quoted here. This note used to quote that reason VERBATIM, #18797 rewrote it, and the quoted string stopped existing in the very file the note sends you to: the id is the durable anchor, the prose is not. The substance is unchanged and now sits on the entry itself — this seeding falsifies the entry’s original premise, that it acted only on the stack-level collections and reached no authorable key of a governed type (#18587 having supplied the per-type coordinate that premise said was missing) — so the registry records the class as a REAL ADR-0054 §3 binding candidate, held back by the adoption act alone. ⛔ No `proof` is claimed on any row here: binding a high-risk class is a separate ADR-0054 §3 act, one class at a time, and it is filed rather than slipped in.",
"props": {
"name": {
"status": "live",
Expand Down
Loading