Skip to content

Commit 5ab3507

Browse files
hotlongclaude
andauthored
docs(qa): re-ground the activation-ledger checklist items on the tenantless table (#15251)
`sys_metadata_activation` dropped its reserved `organization_id` column before it ever shipped (#15024): the object declares `systemFields: { tenant: false }`, the declared index is `unique: 'global'` over `(metadata_type, name)`, and `ObjectStoreMetadataActivationStore` no longer filters reads to NULL-organization rows or skips org-carrying ones. Three legs of `platform-core.activation-ledger-row-contract` were written around that column. - Step 2 asserted five declared columns with `organization_id` NULL on every row. It now asserts the column is ABSENT from the row's key set. The value spelling passes vacuously once the column is gone (`row.organization_id ?? null` is `null` either way), which is why the dogfood pin was inverted into a key-set assertion rather than carried forward. - Step 6 (uniqueness) still works and still refuses; only its stated mechanism was wrong. It now names the plain `unique: 'global'` over two required key parts, with ADR-0120 D3's COALESCE collapse recorded as history that is no longer reachable here. - Step 7 INSERTed a row carrying `organization_id`, so the leg could not be run at all. It is REPLACED by a no-tenant-column probe — `PRAGMA table_info` plus an INSERT naming the column, refused, bracketed by a control INSERT that lands without it — not retired, because ADR-0131 D7 makes "this ledger has no organization column" a load-bearing platform property. `access-security.activation-write-operator-gate` changes only its two ledger read-backs; the operator gate and its unit pins are untouched. ADR-0126 §5's operator-gate half stands, and the source citation now says so, so the next reader does not infer the gate moved with the withdrawn column bullet. Both items bump `revision` and append a `history` entry, per the checklist's change lifecycle. Fixes #15154 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 4dd5041 commit 5ab3507

2 files changed

Lines changed: 40 additions & 25 deletions

File tree

‎docs/qa/platform-checklist/areas/access-security.json‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2099,7 +2099,7 @@
20992099
"title": "Activation-ledger write authority (ADR-0126 §5): the manage_metadata tier refuses first on every posture, and the shared operator gate — INERT on stock `single` — demands the platform_admin POSITION in walled postures, at both the flow and action doors",
21002100
"since": "v17",
21012101
"status": "active",
2102-
"revision": 1,
2102+
"revision": 2,
21032103
"priority": "P1",
21042104
"surface": "api",
21052105
"personas": [
@@ -2128,7 +2128,7 @@
21282128
"as the plain member again: repeat the flow toggle with a deliberately INVALID body (e.g. {\"enabled\": \"false\"}) — the refusal must still be the 403, not a 400 body-validation answer (the gate runs before body validation, automation.ts; activation-gate.ts)",
21292129
"GET /api/v1/data/sys_metadata_activation (reads are open — sys-metadata-activation.object.ts) and confirm no row for either artifact was written by the refusals",
21302130
"author the scratch manage_metadata permission set, grant it to a fresh member, and prove server-side that the member's positions do NOT include platform_admin (session row / GET /auth/get-session — never the grant gesture)",
2131-
"as that member: POST /api/v1/automation/showcase_urgent_task_alert/toggle {\"enabled\": false} — expect 200; read the ledger row back (metadata_type 'flow', active false, organization_id NULL); then re-enable ({\"enabled\": true}) to restore the fixture",
2131+
"as that member: POST /api/v1/automation/showcase_urgent_task_alert/toggle {\"enabled\": false} — expect 200; read the ledger row back (metadata_type 'flow', active false, and NO organization_id key on the row — the ledger carries no tenant column at all, #15024 / ADR-0131 D7); then re-enable ({\"enabled\": true}) to restore the fixture",
21322132
"as the same member: POST /api/v1/actions/_activation/showcase_task/showcase_mark_done {\"enabled\": false} — expect 200 + the metadata_type 'action' row; re-enable to restore",
21332133
"walled-posture legs: BLOCKED on stock fixtures (see knownGaps) — the group/isolated matrix (org admin with manage_metadata refused naming the posture and the per-artifact remedy; platform_admin POSITION admitted; no row on refusal) is pinned at unit level by automated.ref"
21342134
],
@@ -2152,9 +2152,9 @@
21522152
"evidence": "the ledger reads + the invalid-body trace"
21532153
},
21542154
{
2155-
"clause": "the §5 gate is INERT on `single`, not satisfied: a caller holding manage_metadata but NOT the platform_admin POSITION succeeds at BOTH doors, and each write lands one install-level ledger row (organization_id NULL) — install-level and org-level are the same scope on one logical tenant (activation-gate.ts,141-147)",
2155+
"clause": "the §5 gate is INERT on `single`, not satisfied: a caller holding manage_metadata but NOT the platform_admin POSITION succeeds at BOTH doors, and each write lands one deployment-level ledger row — install-level and org-level are the same scope on one logical tenant (activation-gate.ts,141-147), and the ledger carries no tenant column to say otherwise",
21562156
"oracle": "api",
2157-
"verify": "the scratch-set member's positions are proven server-side to exclude platform_admin (BUILTIN_IDENTITY_PLATFORM_ADMIN = 'platform_admin', packages/spec/src/identity/eval-user.zod.ts), then both toggles answer 200 and GET /api/v1/data/sys_metadata_activation shows the metadata_type 'flow' and 'action' rows with active false, organization_id NULL; re-enable restores active true",
2157+
"verify": "the scratch-set member's positions are proven server-side to exclude platform_admin (BUILTIN_IDENTITY_PLATFORM_ADMIN = 'platform_admin', packages/spec/src/identity/eval-user.zod.ts), then both toggles answer 200 and GET /api/v1/data/sys_metadata_activation shows the metadata_type 'flow' and 'action' rows with active false and no organization_id key at all; re-enable restores active true. ⛔ Do not score the tenant half from a VALUE read — a check of the shape `row.organization_id ?? null` is `null` for a column that does not exist, so it passes while measuring nothing; read the key set (platform-core.activation-ledger-row-contract owns that probe)",
21582158
"evidence": "the position proof + both 200 traces + the ledger rows"
21592159
},
21602160
{
@@ -2195,15 +2195,21 @@
21952195
"packages/runtime/src/domains/automation.ts#FLOW_ENABLEMENT_DENY_MESSAGE (FLOW_ENABLEMENT_DENY_MESSAGE), (isFlowActivationWrite), (gate ordering ahead of service probe and body checks)",
21962196
"packages/runtime/src/domains/actions.ts (both tiers at the action door)",
21972197
"packages/spec/src/security/tenancy-posture.ts#TenancyPostureSchema (TenancyPostureSchema — the variants source; postureEnforcesWall; the ADR-0105 D12 entitlement note)",
2198-
"docs/adr/0126-packaged-metadata-customization-model.md §5 (D3: install-level rows, operator-gated in multi-org postures)",
2199-
"#12438 (the sweep), #12159 (ADR-0126 flow legs), #10243 (the measured incident the gate makes durable), #12157 / #12160 (the two door cards)"
2198+
"docs/adr/0126-packaged-metadata-customization-model.md §5 (D3: install-level rows, operator-gated in multi-org postures) — ⚠️ the operator gate this item owns STANDS; only §5's separate 'the org column is reserved' bullet was withdrawn (ADR-0131 D7), which is why the ledger read-backs here name no organization_id",
2199+
"#12438 (the sweep), #12159 (ADR-0126 flow legs), #10243 (the measured incident the gate makes durable), #12157 / #12160 (the two door cards), #15154 (the ledger read-back detail re-grounded after #15024 dropped the tenant column — the gate itself and its pins are unchanged)"
22002200
],
22012201
"history": [
22022202
{
22032203
"revision": 1,
22042204
"date": "2026-08-26",
22052205
"change": "new — ADR-0126 §5 write authority had no checklist coverage. Authored with the stock-posture truth stated up front (the §5 gate is INERT on `single`; the D1 refusal is the manage_metadata tier) so a runner never scores the wrong gate, and with the group/isolated legs blocked(fixture) on the enterprise-posture gap (#9334 precedent) instead of faked. Variants pinned to TenancyPostureSchema (verified extractable by the validator's enumSource extractor)",
22062206
"ref": "#12438"
2207+
},
2208+
{
2209+
"revision": 2,
2210+
"date": "2026-09-04",
2211+
"change": "read-back detail only: #15024 dropped sys_metadata_activation's reserved organization_id column, so the two ledger read-backs (step 7 and the inert-gate clause) asked the runner to see a column that is gone. They now read the row's KEY SET instead — a value check of the shape `row.organization_id ?? null` is `null` for a column that does not exist, so carrying the old spelling forward would have left a leg that passes while measuring nothing. ⚠️ The gate itself is UNCHANGED: ADR-0126 §5's operator-gate half stands and its unit pins pass unmodified; only §5's separate 'the org column is reserved' bullet was withdrawn (ADR-0131 D7). The source citation now says so, so the next reader does not infer the gate moved too",
2212+
"ref": "#15154"
22072213
}
22082214
]
22092215
},

0 commit comments

Comments
 (0)