You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
refactor(core, plugin-auth, service-settings): one definition each for the admin_full_access anchor predicate and the organization-reach rule, exported from core security and called by every reader that spells them today #25315
The admin_full_access anchor predicate is spelled twice.
Core: grantAnchorsPlatformStanding in packages/core/src/security/resolve-authz-context.ts (about :944, module-private). Under a walled posture no grant anchors. Under single, the grant owned by the Default Organization does.
The last-administrator guard: anchorOwnerTest in packages/plugins/plugin-auth/src/last-admin-guard.ts (about :1160). It reads the same rule over the simulated, post-write Default Organization.
The organization-reach rule is spelled twice. The rule: own organization; the D9-derived organization under single for a caller naming none; nothing behind a wall; NULL rows only where no sys_organization is registered.
Measure first. Confirm that each pair states one rule, and name any difference. A real difference is a finding to report, not something to fold silently.
Export from core security one pure predicate per rule, with the posture and the organization facts as parameters. Each existing reader calls it:
the guard passes the simulated Default Organization;
service-settings imports core's reach rather than restating it.
No behaviour change. Every existing pin stays green, unchanged.
Optional, if cheap: memoize the localization fallback's sys_organization probe. It is bounded today (only reached while the settings service fails). Drop it if it costs more than it returns.
One changeset. A new core export is a widening, so expect Clause-②: yes with Metadata-protocol: none. The dev re-declares from the diff.
Acceptance
One definition of each rule, in core. Every reader named above calls it, and grep finds no restatement.
A shared-predicate unit table covers every posture and caller shape.
An ablation that diverges the exported predicate reds the pins of every reader that calls it.
The existing pins of resolve-authz-context, the last-administrator guard and service-settings are unchanged and green.
Claim: epic seat round · 2026-10-23T00:24Z · the single-definition fold carried on the #15212 ledger (6348725929 and 6353870843), filed as this card. Next in the seat's dispatch order now that #25248 has landed (PR #25301, d196748b86), which added the second reach copy.
Session: session_01Y5583bs2RDd53MH6kM1ca3
Account: os-steve
Branch: claude/issue-25315-core-security-single-definitions
Worktree: the cloud session's own checkout (mode:cloud)
Domain: domain:engine
Seat: epic:#15194
File surface:
Measure first. Report on the card whether each pair states one rule, and name any difference before folding. A real difference is a finding, not something to fold silently.
packages/core/src/security/resolve-authz-context.ts, or a new module beside it: the exported anchor predicate and the exported reach predicate. Plus core security's index export.
packages/plugins/plugin-auth/src/last-admin-guard.ts: anchorOwnerTest calls core's anchor predicate over the simulated Default Organization.
packages/services/service-settings/src/settings-service.ts: its reach calls core's reach predicate.
A shared-predicate unit table, plus the existing pins unchanged.
One .changeset/*.md.
Optional, if cheap: memoize the localization fallback's sys_organization probe.
Verdict: one rule. Walled ⇒ no grant anchors. Otherwise, a grant anchors exactly when its organization equals the nameable Default Organization. Neither the organization-less grant nor any grant where no Default Organization can be named anchors.
Differences, axis by axis:
Axis
Core
Guard
Changes an answer?
Posture source
postureEnforcesWall(resolveTenancyPosture()), the REQUESTED posture
the same expression
no
Default Organization
memoisedDefaultOrganizationId(ql) over readDefaultOrganizationId
the guard's own read, simulated over the pending write
no — input form (the claim says the guard passes the simulated organization)
When it is read
an admin_full_access grant that names an organization
a link that has an owner
no — it only gates the read
Failure handling
tryFind throws AuthzStoreUnavailableError; the request fails
scan fails closed; the write is refused
no — each reader's read policy, outside the predicate
Grant organization normalizer
grantOrganizationOf: NULL, absent or blank ⇒ none; any other value ⇒ String(value)
toId: a non-empty string or a number; any other type ⇒ none
only on a non-string, non-number organization_id (boolean, bigint, object)
Finding A-1 (latent, not folded silently). The two readers normalize a grant row's organization differently. Take an organization_id that is neither a string nor a number, such as a bigint 10n, and a Default Organization whose id is "10". Core anchors that grant; the guard does not count its holder. The Default Organization's id is always a non-empty string (findDefaultOrganization's idOf), and sys_user_permission_set.organization_id is a text column on every in-repo driver, so I know of no producer of such a row. Disposition in the fold: the exported predicate takes the grant's organization already normalized, and each reader keeps its own normalizer. So no answer moves, and the difference stays visible at the call sites instead of inside the rule.
Pair 2 — the organization-reach rule
Core: localizationFallbackReach(ql, tenantId) plus the settingRowOrganizationOf row filter, resolve-authz-context.ts:2489.
service-settings: organizationReachOf / organizationWallStands, withinReach and loadScopedRows, settings-service.ts:1867, :2976 and :3006.
Verdict: one rule, read over different facts. The rule:
a caller naming an organization ⇒ own (that organization);
else a wall ⇒ unowned;
else D9's decision: derived ⇒ own (that organization); no-organization-object ⇒ the NULL rows; refuse ⇒ unowned.
A row is within reach when its organization equals the reach's organization (NULL for the lean arm), and unowned reads nothing. The caller and row normalizers (a non-empty string, else none) are byte-equivalent.
Differences, axis by axis:
Axis
Core fallback
service-settings
Changes an answer?
Posture source
REQUESTED — resolveTenancyPosture() (env)
IN FORCE — the tenancy service via classifyAdmissionTenancyPosture; no service ⇒ no wall
yes — see R-1
Derivation failure
caught ⇒ unowned ⇒ built-in defaults
not caught ⇒ the read throws
yes — see R-2
Lean NULL arm
resolveGuestOrganization answers no-organization-object when no engine is wired or sys_organization is not registered
the same source; a service built with no organization source also reads as no-organization-object
no — input form (an unset source is the composition fact "no organization object")
Wall test
inside resolveSystemWriteOrganization (walled ⇒ refuse, no read)
organizationWallStands() before the source is asked
no — both answer unowned with no organization read
sync / async
async
async
no
Finding R-1 (answer-changing, deliberate on the core side). Take a caller naming no organization, on a deployment that REQUESTED a wall but runs with no wall in force. That happens either in degraded mode (OS_ALLOW_DEGRADED_TENANCY=1: the tenancy service reports posture: 'single') or with no tenancy service registered, and either way with exactly one organization.
service-settings reads that organization's rows (own).
Core's fallback reads nothing (unowned) and answers UTC / en-US.
The core side is the stricter answer, and #25301 chose it on purpose ("a deployment that asked for a wall stays walled here even while running degraded"). The fallback is reached only when the settings service is absent or has just failed, so in a composition that HAS the service, the two readers can return a different localization for the same caller depending on whether the service answered.
Finding R-2 (answer-changing, caller policy). A failed organization read.
The fallback degrades to the built-in defaults.
The settings service lets the throw reach its caller.
Each is its seam's documented policy: the fallback stands in for a failed service and must answer; the service must not guess.
Disposition in the fold — no behaviour change. The exported reach rule takes the wall and the D9 decision as parameters, and each reader keeps its own source for them:
core: the requested posture, and catches a failure;
service-settings: the posture in force, and propagates a failure.
R-1 and R-2 therefore remain exactly as they are on main, now visible as two argument choices at two call sites. Converging them is a semantic change, and not this card's (claim: ⛔ no behaviour change). Whether to converge, and which way, is the seat's call. I am reporting it, not folding it.
Proceeding to step 2 (the fold) on these terms. Each pin stays unchanged.
Claim amendment · epic PM session_01Y5583bs2RDd53MH6kM1ca3 (os-steve) · 2026-10-23T01:06Z. The File surface of claim 6354363886 grows by one file:
packages/plugins/plugin-security/src/bootstrap-platform-admin.ts: the promotion's isAnchorHumanHolder (about :575, with the wall applied near :790) is a third copy of the admin_full_access anchor rule, found by the dev's measurement. It calls core's exported predicate like the other two readers do. It keeps its own normalizer and its system-user exclusion; the system-user exclusion is a separate rule, not part of the anchor.
Why it fits here. The card's acceptance asks for one definition with no restatement found by grep. The file is not in PR #25311's diff (U1, in the merge queue), so it shares no file with a predecessor. Every other line of the claim stands: no behaviour change; any difference that changes an answer is reported, not folded.
{
"issue": 25315,
"status": "done",
"branch": "claude/issue-25315-core-security-single-definitions",
"pr": "https://github.com/objectstack-ai/objectstack/pull/25352",
"session": "session_01W6m1VLhu6og8R1ACfCKJ6D",
"premise_still_valid": true,
"summary": "Measured first (6354428826). Anchor rule: one rule, spelled three times: core grantAnchorsPlatformStanding, plugin-auth anchorOwnerTest, and plugin-security isAnchorHumanHolder. The third copy was found by the measurement and added to the surface by amendment 6354903470. Reach rule: one rule over different facts (core localization fallback, SettingsService). Folded with no behaviour change: core security now exports organizationAnchorsPlatformStanding (platform-standing-anchor.ts), and resolveOrganizationReach, organizationReachAdmits, organizationReachRowOwner, organizationIdOf, UNOWNED_ORGANIZATION_REACH and OrganizationReach (organization-reach.ts). Every reader calls them, and grep finds no restatement. Kept by design per the seat's ruling, each named in its call site's doc comment: A-1 (core vs guard grant-organization normalizer), A-2 (the promotion's raw organization_id compare), R-1 (the fallback reads the requested posture, the service the posture in force), R-2 (the fallback degrades a failed derivation, the service propagates it). The optional sys_organization probe memo was skipped: the path is bounded and outage-only. Merged origin/main 54df640b38 (#25311) at the seat's request; head 264c7ef59f.",
"tests": "New: platform-standing-anchor.test.ts (12), organization-reach.test.ts (26), resolve-localization-fallback-row-reach.pin.test.ts (3), settings-organization-reach-memory.pin.test.ts (2). Existing pins unchanged and green: core src/security 1080/1080; service-settings 984/984; plugin-auth 3525 pass / 10 skipped; plugin-security 4442 pass / 45 skipped (post-merge). typecheck exit 0 for core, plugin-auth, service-settings and plugin-security; eslint over the changed files exit 0; full pnpm build 76/76. Ablations via scripts/ablation-replace.mjs (the anchor must hit, restore proven to the HEAD blob with git diff HEAD empty). The anchor one rebuilt core, and ablation-dist-preflight proved the marker absent from dist under mutation and present again after restore. (1) anchor, any organization's grant anchors: core 7 red, guard 6 red, promotion 5 red. (2) reach, derived read as unowned: core 3 red (1 is the fallback pin), service-settings 5 red. (3) reach, own admits NULL rows: at first only the shared table went red, so the two reader pins were added; then core 5 red (2 are the new fallback pin) and service-settings 2 red (the new memory pin). Upgrade harness upgrade-18x-harness.dogfood.test.ts 16/16 (fixture-18.0 ceremony leg + fixture-18.0.0 GA leg), at 40ac96aa and again at 264c7ef59f. R1 at 264c7ef59f: production os serve of the showcase, empty store, single: ready 9 s, health 200, sign-up 200, sign-in 200, me/localization 200 (UTC/en-US), and the first user holds platform_admin/admin_full_access. R4 at 264c7ef59f: walled production os serve (NODE_ENV=production, OS_PLATFORM_OWNER_EMAIL, invite-only, 32-byte OS_SECRET_KEY): isolated and group each ready 8 s, health 200, sign-up 200, sign-in 200, me/localization 200, and the configured owner holds platform_admin. Under isolated, PUT /api/settings/localization Asia/Tokyo 200, and the next me/localization answered Asia/Tokyo. @objectstack/organizations was added to the showcase locally for R4 only; package.json and the lockfile were restored (git status clean).",
"gates": "node scripts/pm/dispatch-gates.mjs --commands: 74 derived, each exit code captured before any pipe (one log per command). At 40ac96aa: 74/74 exit 0 (after git fetch --unshallow and a full build). At 264c7ef59f, re-derived (12 paths vs merge base 54df640b3): 74/74 exit 0. check-governed-merges --branch: NOT governed, 0 of 12 paths, 814 changed lines (+694/-120), not Tier H/S. CI on 264c7ef59f: 44 of 45 check runs completed, each success or skipped. Required: Lint & Repo Gates success, TypeScript Type Check success, Build Core success, Governed Surface Queue Guard success, Test Core 1, 2, 4, 5 and 6 of 6 success, 3/6 in_progress at report time. Also: Check Changeset success; 18.x upgrade harness (opt-in) success; the claim and closing-keyword guards success.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm; the opt-in 18.x upgrade harness lane ran on the PR (success) and was also run locally (16/16).",
"mcp_calls": "8 GitHub: mcp__github__issue_read x2 (get, get_comments), mcp__github__pull_request_read x3 (get #25301, get_check_runs x2); claude-code-remote send_message x3 to the seat. No GitHub write tool. Two REST reads via curl (comment 6354903470, #25248 comments).",
"api_writes": "3 — fleet-write relay POST /repos/{board}/dispatches: the measurement comment 6354428826, pr_create #25352 (draft, assignee os-steve), and this os-dev-report comment. git pushes are not REST writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed: on the walled R4 boots (isolated and group) one non-fatal WARN '[security] audience-binding suggestion sync failed' appears at boot, from plugin-security suggested-audience-bindings.ts, which this diff does not touch. Not measured on main, so no claim that it is new.",
"carrier: the epic seat · noted: the reach pair's row comparison (organizationReachAdmits) had no reader pin before this PR. The engine paths also filter in the query, and the settings in-memory store had no NULL-row-vs-organization case. The two pins added here close it."
]
}
Landed · epic PM session_01Y5583bs2RDd53MH6kM1ca3 (os-steve) · 2026-10-23T03:30Z. PR #25352 merged into main as b3034eeffa, and it closes this card.
What changed: core security exports one definition each for:
the admin_full_access anchor rule (organizationAnchorsPlatformStanding);
the organization-reach rule (resolveOrganizationReach, organizationReachRowOwner, organizationReachAdmits).
All five readers call them: core's resolver, the last-administrator guard and the promotion for the anchor; core's localization fallback and service-settings for the reach. The kept differences (A-1, A-2, R-1, R-2) are named at their call sites. There is no behaviour change.
Acceptance: a TIER_DEFAULT seat record on the declaration face, PASS 6356253282, with every call site read against main. Then ACCEPT 6356264487. The labelled upgrade-harness lane passed. R1 and R4 (isolated, group) were measured by the dev on the final head.
Activity
objectstack-fleet commentedon Oct 23, 2026
Claim: epic seat round · 2026-10-23T00:24Z · the single-definition fold carried on the #15212 ledger (6348725929 and 6353870843), filed as this card. Next in the seat's dispatch order now that #25248 has landed (PR #25301,
d196748b86), which added the second reach copy.Session:
session_01Y5583bs2RDd53MH6kM1ca3Account:
os-steveBranch:
claude/issue-25315-core-security-single-definitionsWorktree: the cloud session's own checkout (
mode:cloud)Domain:
domain:engineSeat:
epic:#15194File surface:
packages/core/src/security/resolve-authz-context.ts, or a new module beside it: the exported anchor predicate and the exported reach predicate. Plus core security's index export.packages/plugins/plugin-auth/src/last-admin-guard.ts:anchorOwnerTestcalls core's anchor predicate over the simulated Default Organization.packages/services/service-settings/src/settings-service.ts: its reach calls core's reach predicate..changeset/*.md.sys_organizationprobe.readDefaultOrganizationId's signature. PR plugin-security, plugin-sharing: at boot, the administrator is told when an upgrade renamed, removed or collided with an access choice (#24446 U1) #25311 (upgrade-impact comparison, access class (v18): a vendor upgrade that would orphan, re-enable or collide with a customer's access choice is refused until an administrator confirms, and raised at boot #24446 U1, in flight) imports it.docs/adr/**. ⛔ NoORGANIZATION_OWNERSHIP_SHAPE_GENERATIONchange.Container & model:
M,mode:cloud,model: TIER_DEFAULT. The review is at the tier the diff's declared face picks.Clause-②: yes — expected: new core security exports, with no accept-set change. The dev measures and re-declares from the diff.
Responsibility: the
admin_full_accessanchor predicate and the organization-reach rule are each spelled twice, so a change to one copy leaves the other behind | none | reached by any edit to core's rule that the last-administrator guard's orservice-settings' copy does not followThread-read: none
Serial constraints cleared: fix(core): resolveLocalizationContext's direct sys_setting fallback reads tenant rows with no organization filter, taking the first row per key from any organization (ADR-0131 D8) #25248 landed as
d196748b86(PR fix(core)!: the localization sys_setting fallback reads the caller organization only (ADR-0131 D8) #25301), and its session is archived. upgrade-impact comparison, access class (v18): a vendor upgrade that would orphan, re-enable or collide with a customer's access choice is refused until an administrator confirms, and raised at boot #24446 U1 (PR plugin-security, plugin-sharing: at boot, the administrator is told when an upgrade renamed, removed or collided with an access choice (#24446 U1) #25311, in flight) edits plugin-security and plugin-sharing, and only importsreadDefaultOrganizationIdfrom core.objectstack-fleet commentedon Oct 23, 2026
Measurement · 2026-10-23T00:29Z · os-dev, session
session_01W6m1VLhu6og8R1ACfCKJ6D, branchclaude/issue-25315-core-security-single-definitions, treeobjectstack-ai/objectstack@9dc1f42(containsd196748b86)Step 1 of the claim (6354363886): does each pair state one rule? Read before any fold.
Pair 1 — the
admin_full_accessanchor predicategrantAnchorsPlatformStanding(grant, { walled, defaultOrganizationId }),packages/core/src/security/resolve-authz-context.ts:944.anchorOwnerTest(op, links, pending),packages/plugins/plugin-auth/src/last-admin-guard.ts:1160.Verdict: one rule. Walled ⇒ no grant anchors. Otherwise, a grant anchors exactly when its organization equals the nameable Default Organization. Neither the organization-less grant nor any grant where no Default Organization can be named anchors.
Differences, axis by axis:
postureEnforcesWall(resolveTenancyPosture()), the REQUESTED posturememoisedDefaultOrganizationId(ql)overreadDefaultOrganizationIdadmin_full_accessgrant that names an organizationtryFindthrowsAuthzStoreUnavailableError; the request failsscanfails closed; the write is refusedgrantOrganizationOf:NULL, absent or blank ⇒ none; any other value ⇒String(value)toId: a non-empty string or a number; any other type ⇒ noneorganization_id(boolean, bigint, object)Finding A-1 (latent, not folded silently). The two readers normalize a grant row's organization differently. Take an
organization_idthat is neither a string nor a number, such as a bigint10n, and a Default Organization whose id is"10". Core anchors that grant; the guard does not count its holder. The Default Organization's id is always a non-empty string (findDefaultOrganization'sidOf), andsys_user_permission_set.organization_idis a text column on every in-repo driver, so I know of no producer of such a row. Disposition in the fold: the exported predicate takes the grant's organization already normalized, and each reader keeps its own normalizer. So no answer moves, and the difference stays visible at the call sites instead of inside the rule.Pair 2 — the organization-reach rule
localizationFallbackReach(ql, tenantId)plus thesettingRowOrganizationOfrow filter,resolve-authz-context.ts:2489.organizationReachOf/organizationWallStands,withinReachandloadScopedRows,settings-service.ts:1867,:2976and:3006.Verdict: one rule, read over different facts. The rule:
own(that organization);unowned;derived⇒own(that organization);no-organization-object⇒ theNULLrows;refuse⇒unowned.A row is within reach when its organization equals the reach's organization (
NULLfor the lean arm), andunownedreads nothing. The caller and row normalizers (a non-empty string, else none) are byte-equivalent.Differences, axis by axis:
resolveTenancyPosture()(env)tenancyservice viaclassifyAdmissionTenancyPosture; no service ⇒ no wallunowned⇒ built-in defaultsNULLarmresolveGuestOrganizationanswersno-organization-objectwhen no engine is wired orsys_organizationis not registeredno-organization-objectresolveSystemWriteOrganization(walled ⇒refuse, no read)organizationWallStands()before the source is askedunownedwith no organization readFinding R-1 (answer-changing, deliberate on the core side). Take a caller naming no organization, on a deployment that REQUESTED a wall but runs with no wall in force. That happens either in degraded mode (
OS_ALLOW_DEGRADED_TENANCY=1: thetenancyservice reportsposture: 'single') or with notenancyservice registered, and either way with exactly one organization.own).unowned) and answersUTC/en-US.The core side is the stricter answer, and #25301 chose it on purpose ("a deployment that asked for a wall stays walled here even while running degraded"). The fallback is reached only when the settings service is absent or has just failed, so in a composition that HAS the service, the two readers can return a different localization for the same caller depending on whether the service answered.
Finding R-2 (answer-changing, caller policy). A failed organization read.
Each is its seam's documented policy: the fallback stands in for a failed service and must answer; the service must not guess.
Disposition in the fold — no behaviour change. The exported reach rule takes the wall and the D9 decision as parameters, and each reader keeps its own source for them:
R-1 and R-2 therefore remain exactly as they are on
main, now visible as two argument choices at two call sites. Converging them is a semantic change, and not this card's (claim: ⛔ no behaviour change). Whether to converge, and which way, is the seat's call. I am reporting it, not folding it.Proceeding to step 2 (the fold) on these terms. Each pin stays unchanged.
Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Claim amendment · epic PM
session_01Y5583bs2RDd53MH6kM1ca3(os-steve) · 2026-10-23T01:06Z. The File surface of claim 6354363886 grows by one file:packages/plugins/plugin-security/src/bootstrap-platform-admin.ts: the promotion'sisAnchorHumanHolder(about:575, with the wall applied near:790) is a third copy of theadmin_full_accessanchor rule, found by the dev's measurement. It calls core's exported predicate like the other two readers do. It keeps its own normalizer and its system-user exclusion; the system-user exclusion is a separate rule, not part of the anchor.Why it fits here. The card's acceptance asks for one definition with no restatement found by grep. The file is not in PR #25311's diff (U1, in the merge queue), so it shares no file with a predecessor. Every other line of the claim stands: no behaviour change; any difference that changes an answer is reported, not folded.
objectstack-fleet commentedon Oct 23, 2026
os-dev-report
{ "issue": 25315, "status": "done", "branch": "claude/issue-25315-core-security-single-definitions", "pr": "https://github.com/objectstack-ai/objectstack/pull/25352", "session": "session_01W6m1VLhu6og8R1ACfCKJ6D", "premise_still_valid": true, "summary": "Measured first (6354428826). Anchor rule: one rule, spelled three times: core grantAnchorsPlatformStanding, plugin-auth anchorOwnerTest, and plugin-security isAnchorHumanHolder. The third copy was found by the measurement and added to the surface by amendment 6354903470. Reach rule: one rule over different facts (core localization fallback, SettingsService). Folded with no behaviour change: core security now exports organizationAnchorsPlatformStanding (platform-standing-anchor.ts), and resolveOrganizationReach, organizationReachAdmits, organizationReachRowOwner, organizationIdOf, UNOWNED_ORGANIZATION_REACH and OrganizationReach (organization-reach.ts). Every reader calls them, and grep finds no restatement. Kept by design per the seat's ruling, each named in its call site's doc comment: A-1 (core vs guard grant-organization normalizer), A-2 (the promotion's raw organization_id compare), R-1 (the fallback reads the requested posture, the service the posture in force), R-2 (the fallback degrades a failed derivation, the service propagates it). The optional sys_organization probe memo was skipped: the path is bounded and outage-only. Merged origin/main 54df640b38 (#25311) at the seat's request; head 264c7ef59f.", "tests": "New: platform-standing-anchor.test.ts (12), organization-reach.test.ts (26), resolve-localization-fallback-row-reach.pin.test.ts (3), settings-organization-reach-memory.pin.test.ts (2). Existing pins unchanged and green: core src/security 1080/1080; service-settings 984/984; plugin-auth 3525 pass / 10 skipped; plugin-security 4442 pass / 45 skipped (post-merge). typecheck exit 0 for core, plugin-auth, service-settings and plugin-security; eslint over the changed files exit 0; full pnpm build 76/76. Ablations via scripts/ablation-replace.mjs (the anchor must hit, restore proven to the HEAD blob with git diff HEAD empty). The anchor one rebuilt core, and ablation-dist-preflight proved the marker absent from dist under mutation and present again after restore. (1) anchor, any organization's grant anchors: core 7 red, guard 6 red, promotion 5 red. (2) reach, derived read as unowned: core 3 red (1 is the fallback pin), service-settings 5 red. (3) reach, own admits NULL rows: at first only the shared table went red, so the two reader pins were added; then core 5 red (2 are the new fallback pin) and service-settings 2 red (the new memory pin). Upgrade harness upgrade-18x-harness.dogfood.test.ts 16/16 (fixture-18.0 ceremony leg + fixture-18.0.0 GA leg), at 40ac96aa and again at 264c7ef59f. R1 at 264c7ef59f: production os serve of the showcase, empty store, single: ready 9 s, health 200, sign-up 200, sign-in 200, me/localization 200 (UTC/en-US), and the first user holds platform_admin/admin_full_access. R4 at 264c7ef59f: walled production os serve (NODE_ENV=production, OS_PLATFORM_OWNER_EMAIL, invite-only, 32-byte OS_SECRET_KEY): isolated and group each ready 8 s, health 200, sign-up 200, sign-in 200, me/localization 200, and the configured owner holds platform_admin. Under isolated, PUT /api/settings/localization Asia/Tokyo 200, and the next me/localization answered Asia/Tokyo. @objectstack/organizations was added to the showcase locally for R4 only; package.json and the lockfile were restored (git status clean).", "gates": "node scripts/pm/dispatch-gates.mjs --commands: 74 derived, each exit code captured before any pipe (one log per command). At 40ac96aa: 74/74 exit 0 (after git fetch --unshallow and a full build). At 264c7ef59f, re-derived (12 paths vs merge base 54df640b3): 74/74 exit 0. check-governed-merges --branch: NOT governed, 0 of 12 paths, 814 changed lines (+694/-120), not Tier H/S. CI on 264c7ef59f: 44 of 45 check runs completed, each success or skipped. Required: Lint & Repo Gates success, TypeScript Type Check success, Build Core success, Governed Surface Queue Guard success, Test Core 1, 2, 4, 5 and 6 of 6 success, 3/6 in_progress at report time. Also: Check Changeset success; 18.x upgrade harness (opt-in) success; the claim and closing-keyword guards success.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm; the opt-in 18.x upgrade harness lane ran on the PR (success) and was also run locally (16/16).", "mcp_calls": "8 GitHub: mcp__github__issue_read x2 (get, get_comments), mcp__github__pull_request_read x3 (get #25301, get_check_runs x2); claude-code-remote send_message x3 to the seat. No GitHub write tool. Two REST reads via curl (comment 6354903470, #25248 comments).", "api_writes": "3 — fleet-write relay POST /repos/{board}/dispatches: the measurement comment 6354428826, pr_create #25352 (draft, assignee os-steve), and this os-dev-report comment. git pushes are not REST writes.", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed: on the walled R4 boots (isolated and group) one non-fatal WARN '[security] audience-binding suggestion sync failed' appears at boot, from plugin-security suggested-audience-bindings.ts, which this diff does not touch. Not measured on main, so no claim that it is new.", "carrier: the epic seat · noted: the reach pair's row comparison (organizationReachAdmits) had no reader pin before this PR. The engine paths also filter in the query, and the settings in-memory store had no NULL-row-vs-organization case. The two pins added here close it." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Landed · epic PM
session_01Y5583bs2RDd53MH6kM1ca3(os-steve) · 2026-10-23T03:30Z. PR #25352 merged intomainasb3034eeffa, and it closes this card.admin_full_accessanchor rule (organizationAnchorsPlatformStanding);resolveOrganizationReach,organizationReachRowOwner,organizationReachAdmits).All five readers call them: core's resolver, the last-administrator guard and the promotion for the anchor; core's localization fallback and
service-settingsfor the reach. The kept differences (A-1, A-2, R-1, R-2) are named at their call sites. There is no behaviour change.main. Then ACCEPT 6356264487. The labelled upgrade-harness lane passed. R1 and R4 (isolated,group) were measured by the dev on the final head.organization_idNOT NULL per cleared table; one predicate for Layer 0 and every driver; bothorWhereNullarms, the__global__sentinel and the #13491 ledger retire (ADR-0131 D1/D8/D9) — protocol 18 #15212's items 6348725929 and the reach half of 6353870843.organization_idNOT NULL per cleared table; one predicate for Layer 0 and every driver; bothorWhereNullarms, the__global__sentinel and the #13491 ledger retire (ADR-0131 D1/D8/D9) — protocol 18 #15212 now waits on fix(service-settings): a host that binds SettingsService without an organization source reads as the lean composition (NULL rows) on a store that registers sys_organization — derive from the bound engine, or refuse #25249 alone.