From 8d7571de106b972fa40bc1f20187b424d24559b7 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 23 Oct 2026 00:54:41 +0000 Subject: [PATCH 1/2] docs(qa): re-author access-security.platform-owner-email-anchor for the Default Organization grant The item's clause 6 named its own re-author trigger (#11979, Choice 4B), which PR #24373 landed: the single first-user promotion now writes its admin_full_access grant owned by the Default Organization (ADR-0131 D5), and PR #24872 retired the organization-less row's single-posture anchor. Six texts that still named the organization-less row as the live door now name the Default Organization's grant; clause 6's verify and automated.ref cite the [ADR-0131 D5] describe. Revision 7 -> 8 with one history entry. No clause verdict changes. Claude-Session: https://claude.ai/code/session_01JDXz1o5fLjTiZcUdKvNKJN Co-authored-by: Claude --- .../areas/access-security.json | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/qa/platform-checklist/areas/access-security.json b/docs/qa/platform-checklist/areas/access-security.json index 8de998a80cd..84cd7634712 100644 --- a/docs/qa/platform-checklist/areas/access-security.json +++ b/docs/qa/platform-checklist/areas/access-security.json @@ -2919,11 +2919,11 @@ "title": "OS_PLATFORM_OWNER_EMAIL platform-admin anchor: only a VERIFIED stored-email match confers PLATFORM_ADMIN — unset, unverified match, non-match and malformed lists each confer nothing, fail closed", "since": "v17", "status": "active", - "revision": 7, + "revision": 8, "priority": "P1", "surface": "api", "personas": [ - "admin (seeded dev admin — its address is seed-stamped verified per #11343. Under single, the posture this item boots, it is grant-anchored via the unscoped admin_full_access row that first-registrant promotion writes, the ADR-0068 D2 contrast; under a walled posture no such row is written and an existing one confers no platform-admin standing (#11663 L5), so it would stand only if OS_PLATFORM_OWNER_EMAIL named its address)", + "admin (seeded dev admin — its address is seed-stamped verified per #11343. Under single, the posture this item boots, it is grant-anchored via the admin_full_access grant that first-registrant promotion writes, owned by the Default Organization (ADR-0131 D5), the ADR-0068 D2 contrast; an organization-less admin_full_access row anchors nothing on any posture; under a walled posture no such grant is written and an existing one confers no platform-admin standing (#11663 L5), so it would stand only if OS_PLATFORM_OWNER_EMAIL named its address)", "fresh member M (the config-anchor subject; a fresh sign-up's sys_user row is UNVERIFIED, which is exactly the unverified-match fixture)" ], "fixtures": { @@ -2933,7 +2933,7 @@ "a manage_platform_settings-floor probe route: GET /api/v1/datasources answers 401/403 BEFORE any service resolution (packages/services/service-datasource/src/admin-routes.ts; DATASOURCE_ADMIN_CAPABILITY), and admin_full_access carries that capability (packages/spec/src/identity/eval-user.zod.ts) — so the probe discriminates platform-admin standing cleanly" ], "knownGaps": [ - "the ENTITLED live leg needs a VERIFIED second account, and no stock HTTP path verifies one: email_verified is statically readonly at the user-context API (stripped — the write-path-guards class), a fresh sign-up reads unverified, and the seeded dev admin — whose address IS stamped verified at seed time (#11343, auth-plugin.ts) — also holds the unscoped admin_full_access grant under single (the posture this item boots), so its 200s can never attribute to the config anchor. Verify M's address via a verification-enabled boot with mail capture (identity-auth.email-verification-loop's fixture, itself a knownGap there) or a system-context stamp through the same isSystem doorway the seed itself uses; without either, clause 5's live leg scores blocked(fixture) and the entitled side rests on the unit pin. Measured on main c91af8ed6: POST /api/v1/auth/admin/update-user {userId, data: {emailVerified: true}} answers the seeded dev admin 403 YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS, so the HTTP lane has no verifying door; the run stamped M's email_verified directly on its own scratch database with the server stopped (a system-level write, never on a shared database) and records that it did" + "the ENTITLED live leg needs a VERIFIED second account, and no stock HTTP path verifies one: email_verified is statically readonly at the user-context API (stripped — the write-path-guards class), a fresh sign-up reads unverified, and the seeded dev admin — whose address IS stamped verified at seed time (#11343, auth-plugin.ts) — also holds the Default Organization's admin_full_access grant under single (the posture this item boots; ADR-0131 D5), so its 200s can never attribute to the config anchor. Verify M's address via a verification-enabled boot with mail capture (identity-auth.email-verification-loop's fixture, itself a knownGap there) or a system-context stamp through the same isSystem doorway the seed itself uses; without either, clause 5's live leg scores blocked(fixture) and the entitled side rests on the unit pin. Measured on main c91af8ed6: POST /api/v1/auth/admin/update-user {userId, data: {emailVerified: true}} answers the seeded dev admin 403 YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS, so the HTTP lane has no verifying door; the run stamped M's email_verified directly on its own scratch database with the server stopped (a system-level write, never on a shared database) and records that it did" ] }, "steps": [ @@ -2946,7 +2946,7 @@ ], "acceptance": [ { - "clause": "unset = ZERO config-derived administrators, and under single the ADR-0068 D2 unscoped-grant anchor stays the only door: M's datasource probe is refused server-side (401/403 per identity, never 200) and M's systemPermissions lacks manage_platform_settings, while the seeded admin's identical probe answers 200 (both sides of the gate)", + "clause": "unset = ZERO config-derived administrators, and under single the ADR-0068 D2 stored-grant anchor — the Default Organization's admin_full_access grant (ADR-0131 D5) — stays the only door: M's datasource probe is refused server-side (401/403 per identity, never 200) and M's systemPermissions lacks manage_platform_settings, while the seeded admin's identical probe answers 200 (both sides of the gate)", "oracle": "api", "verify": "M's GET /api/v1/datasources >=400 with the declared code; M's /auth/me/permissions systemPermissions array excludes manage_platform_settings; admin's same GET is 200", "evidence": "both personas' traces" @@ -2976,9 +2976,9 @@ "evidence": "test output (and, when the fixture exists, M's entitled traces)" }, { - "clause": "the legacy grant is an anchor under single ONLY, and silently so (#11663 L5): under single, standing resting on the unscoped admin_full_access grant alone still resolves PLATFORM_ADMIN (clauses 1 and 3 observe it live); under a walled posture — postureEnforcesWall, i.e. every posture except single, read from the REQUESTED posture — the same row confers no PLATFORM_ADMIN standing (the held set still grants its own capabilities; only the rung and the built-in platform_admin position go), while the config anchor keeps conferring on that same walled rig; and the request path logs nothing about the row on any posture", + "clause": "the legacy grant is an anchor under single ONLY, and silently so (#11663 L5): under single, standing resting on the admin_full_access grant first-registrant promotion writes — owned by the Default Organization (ADR-0131 D5) — alone still resolves PLATFORM_ADMIN (clauses 1 and 3 observe it live as the seeded admin's 200); an organization-less admin_full_access row anchors nothing on any posture; under a walled posture — postureEnforcesWall, i.e. every posture except single, read from the REQUESTED posture — the same grant confers no PLATFORM_ADMIN standing (the held set still grants its own capabilities in its own organization; only the rung and the built-in platform_admin position go), while the config anchor keeps conferring on that same walled rig; and the request path logs nothing about the row on any posture", "oracle": "test", - "verify": "packages/core/src/security/resolve-authz-context.platform-admin-config.test.ts — the '[#11663 L5] the legacy grant row is an anchor under `single`, and NOWHERE else', '[#11663 L5] the legacy anchor confers only on the rigs Choice 4A keeps it for' and '[#11663 L5] standing across postures' describes; packages/core/src/security/platform-admin.test.ts — '[#11663 L5] the legacy-grant deprecation pointer is retired' (both pointer symbols absent from the module and from the @objectstack/core security entry, with positive controls). The single half's own fate is #11979's (Choice 4B): if that lands, this clause is re-authored, not read as a regression", + "verify": "packages/core/src/security/resolve-authz-context.platform-admin-config.test.ts — the '[#11663 L5] the legacy grant row is an anchor under `single`, and NOWHERE else', '[#11663 L5] the legacy anchor confers only on the rigs Choice 4A keeps it for' and '[#11663 L5] standing across postures' describes, and the '[ADR-0131 D5] under `single` the Default Organization's admin_full_access grant is the anchor' describe (the Default Organization's grant confers with no config; another organization's grant, a walled rig and the organization-less row a pre-D5 promotion wrote anchor nothing); packages/core/src/security/platform-admin.test.ts — '[#11663 L5] the legacy-grant deprecation pointer is retired' (both pointer symbols absent from the module and from the @objectstack/core security entry, with positive controls). The single half's fate was #11979's (Choice 4B): it landed (PR #24373), and this clause was re-authored for it at revision 8 rather than read as a regression", "evidence": "test output" } ], @@ -2995,7 +2995,7 @@ "non-match (nothing)", "comma-separated list — duplicates collapsed, trim+lowercase normalization (platform-admin.ts)", "malformed entry (whole-variable refusal, loud once)", - "walled posture — the unscoped admin_full_access grant alone confers no PLATFORM_ADMIN standing (unit pin, clause 6)" + "walled posture — the Default Organization's admin_full_access grant alone confers no PLATFORM_ADMIN standing, and an organization-less row anchors nothing on any posture (unit pins, clause 6)" ], "traps": [ "wrong-persona", @@ -3003,12 +3003,13 @@ ], "automated": { "kind": "unit", - "ref": "packages/core/src/security/resolve-authz-context.platform-admin-config.test.ts (the acceptance criterion, all four fail-closed arms, the ⭐ stored-row-not-seed pin, the #11663 L5 posture split of the legacy grant anchor) + packages/core/src/security/platform-admin.test.ts (parse/refusal/memo) + packages/core/src/security/admin-standing-surface.test.ts. STILL MANUAL: the live-HTTP arms over a real boot (clauses 1-4; clause 6 is test-only) — the pins run the derivation in-process; this item's live legs prove the same verdicts through the mounted server" + "ref": "packages/core/src/security/resolve-authz-context.platform-admin-config.test.ts (the acceptance criterion, all four fail-closed arms, the ⭐ stored-row-not-seed pin, the #11663 L5 posture split of the legacy grant anchor, the '[ADR-0131 D5] under `single` the Default Organization's admin_full_access grant is the anchor' describe) + packages/core/src/security/platform-admin.test.ts (parse/refusal/memo) + packages/core/src/security/admin-standing-surface.test.ts. STILL MANUAL: the live-HTTP arms over a real boot (clauses 1-4; clause 6 is test-only) — the pins run the derivation in-process; this item's live legs prove the same verdicts through the mounted server" }, "source": [ "packages/core/src/security/resolve-authz-context.ts#hasPlatformAdminStanding (§6b-config — the config anchor inside the ONE derivation site; additive, never subtractive) + (hasPlatformAdminStanding, the id-shaped projection)", "packages/core/src/security/platform-admin.ts#parsePlatformAdminEmails (parsePlatformAdminEmails whole-variable refusal, resolvePlatformAdminEmails loud-once resolve, matchesConfiguredPlatformAdmin verified-only)", - "packages/core/src/security/resolve-authz-context.ts#grantAnchorsPlatformStanding (#11663 L5 — the unscoped admin_full_access row derives PLATFORM_ADMIN only when the requested posture enforces no wall)", + "packages/core/src/security/resolve-authz-context.ts#grantAnchorsPlatformStanding (ADR-0131 D5 + #11663 L5 — the Default Organization's admin_full_access grant derives PLATFORM_ADMIN only when the requested posture enforces no wall; an organization-less row anchors nothing)", + "packages/plugins/plugin-security/src/bootstrap-platform-admin.ts#readPromotionGrantOwner (ADR-0131 D5 — the single first-user promotion writes its admin_full_access grant owned by the Default Organization, never with a NULL organization)", "packages/spec/src/security/tenancy-posture.ts#postureEnforcesWall (walled = every posture except single)", "packages/core/src/security/admin-standing-surface.ts (the env declared a non-table derivation input — no break-glass write can reach it)", "packages/types/src/env.ts#PLATFORM_OWNER_EMAIL_ENV + packages/types/src/env.ts#resolvePlatformOwnerEmail (the variable's name, and its live per-call read)", @@ -3058,6 +3059,12 @@ "date": "2026-10-21", "change": "Respelled — fixtures.knownGaps[0]: 'its own isolated scratch database' → 'its own scratch database'. PR #25003's out-of-scope finding (round 17 of wave anchor #24579; ACCEPT 6304389370, landing record 6304641541): 22 non-history texts in 17 items named the own-port boot or its DB with 'isolated' in other words, the phrasing round 12 found a runner reading as the `isolated` tenancy posture (OS_TENANCY_POSTURE=isolated). The new spelling names the boot or the DB by what it is, the run's own port and DB (RUNNER.md's trap-table counter: own port/DB, skill §0), and names no posture. Read at base 93e6c1a5f8. steps[0]'s 'a walled posture (group / isolated)' names the posture and is left as written. No clause changed", "ref": "#25018" + }, + { + "revision": 8, + "date": "2026-10-23", + "change": "Re-authored for the Default Organization grant — clause 6's own re-author trigger fired. #11979 (Choice 4B) landed by PR #24373 (b2e78701f7): the single first-user promotion writes its admin_full_access grant owned by the Default Organization (ADR-0131 D5, bootstrap-platform-admin.ts). PR #24872 (94842bad2a) then retired the organization-less row's single-posture anchor: grantAnchorsPlatformStanding answers yes for the Default Organization's grant only. Six texts still named the organization-less row as the live door — personas[0], fixtures.knownGaps[0], acceptance[0], acceptance[5], variants[6], source[2]; each now names the Default Organization's grant, and personas[0], acceptance[5], variants[6] and source[2] add that an organization-less row anchors nothing on any posture. Clause 6's verify and automated.ref cite the '[ADR-0131 D5] under `single` the Default Organization's admin_full_access grant is the anchor' describe; source gains bootstrap-platform-admin.ts#readPromotionGrantOwner. PR #24463 had re-pointed source[2]'s anchor at grantAnchorsPlatformStanding and left the revision at 3. Read at base 9dc1f42d50. No clause verdict changed: M is refused, the seeded admin answers 200, the walled grant confers no standing, the config anchor confers", + "ref": "#24465" } ] }, From 14056c9b5114ec871fa0cd7908d034be05f3912a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 23 Oct 2026 01:06:48 +0000 Subject: [PATCH 2/2] docs(qa): name the legacy grant in platform-owner-email-anchor clause 6 Seat review nit on the re-author: clause 6 opened with "the legacy grant is an anchor under single ONLY" and then said an organization-less row anchors nothing, which reads as a contradiction. The clause now names the legacy grant as the admin_full_access grant first-registrant promotion writes, owned by the Default Organization, as opposed to the config anchor. Claude-Session: https://claude.ai/code/session_01JDXz1o5fLjTiZcUdKvNKJN Co-authored-by: Claude --- docs/qa/platform-checklist/areas/access-security.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/qa/platform-checklist/areas/access-security.json b/docs/qa/platform-checklist/areas/access-security.json index 84cd7634712..9c6c9e2bb23 100644 --- a/docs/qa/platform-checklist/areas/access-security.json +++ b/docs/qa/platform-checklist/areas/access-security.json @@ -2976,7 +2976,7 @@ "evidence": "test output (and, when the fixture exists, M's entitled traces)" }, { - "clause": "the legacy grant is an anchor under single ONLY, and silently so (#11663 L5): under single, standing resting on the admin_full_access grant first-registrant promotion writes — owned by the Default Organization (ADR-0131 D5) — alone still resolves PLATFORM_ADMIN (clauses 1 and 3 observe it live as the seeded admin's 200); an organization-less admin_full_access row anchors nothing on any posture; under a walled posture — postureEnforcesWall, i.e. every posture except single, read from the REQUESTED posture — the same grant confers no PLATFORM_ADMIN standing (the held set still grants its own capabilities in its own organization; only the rung and the built-in platform_admin position go), while the config anchor keeps conferring on that same walled rig; and the request path logs nothing about the row on any posture", + "clause": "the legacy grant — the admin_full_access grant first-registrant promotion writes, owned by the Default Organization (ADR-0131 D5), as opposed to the config anchor — is an anchor under single ONLY, and silently so (#11663 L5): under single, standing resting on that grant alone still resolves PLATFORM_ADMIN (clauses 1 and 3 observe it live as the seeded admin's 200); an organization-less admin_full_access row anchors nothing on any posture; under a walled posture — postureEnforcesWall, i.e. every posture except single, read from the REQUESTED posture — the same grant confers no PLATFORM_ADMIN standing (the held set still grants its own capabilities in its own organization; only the rung and the built-in platform_admin position go), while the config anchor keeps conferring on that same walled rig; and the request path logs nothing about the row on any posture", "oracle": "test", "verify": "packages/core/src/security/resolve-authz-context.platform-admin-config.test.ts — the '[#11663 L5] the legacy grant row is an anchor under `single`, and NOWHERE else', '[#11663 L5] the legacy anchor confers only on the rigs Choice 4A keeps it for' and '[#11663 L5] standing across postures' describes, and the '[ADR-0131 D5] under `single` the Default Organization's admin_full_access grant is the anchor' describe (the Default Organization's grant confers with no config; another organization's grant, a walled rig and the organization-less row a pre-D5 promotion wrote anchor nothing); packages/core/src/security/platform-admin.test.ts — '[#11663 L5] the legacy-grant deprecation pointer is retired' (both pointer symbols absent from the module and from the @objectstack/core security entry, with positive controls). The single half's fate was #11979's (Choice 4B): it landed (PR #24373), and this clause was re-authored for it at revision 8 rather than read as a regression", "evidence": "test output"