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
feat(plugin-security): under a walled posture, deliver the access upgrade report in-app into the organization OS_PLATFORM_OWNER_ORGANIZATION names, instead of the operator log line only #25413
Filing gate ③: a direction the maintainer gave in the epic seat's chat on 2026-10-23, on #24446's walled delivery. The seat had put option C (an organization-less, operator-only notification) to the maintainer. The maintainer chose instead to configure the platform owner's organization, the way the platform owner's email is configured: 「既然可以配置平台管理员的邮箱,也可以配置平台管理员的组织id吧?」, naming it OS_PLATFORM_OWNER_ORGANIZATION.
Who acts: the shared queue.
Dedupe: none. No platform-organization setting exists on main; packages/types/src/env.ts has OS_PLATFORM_OWNER_EMAIL only.
Related: #24446 (closed), U1 PR #25311, the seat's option-A ruling 6353787407, #24447 (the non-access classes after v18, which meet the same walled-delivery question).
What is on main
U1's boot report (packages/plugins/plugin-security/src/access-upgrade-report.ts) raises access-class findings at kernel:bootstrapped:
under single, through messaging.emit() to the Default Organization's admin_full_access holders plus OS_PLATFORM_OWNER_EMAIL, stamped with the Default Organization;
under a wall (group / isolated), only as one error line addressed to the operator (option A).
Why the wall gets only a log line: sys_notification is organization-owned (ADR-0131: no NULL organization_id), a walled system write that names no organization is refused (D9), and the operator belongs to no organization by default.
Wanted
A new setting, OS_PLATFORM_OWNER_ORGANIZATION, beside OS_PLATFORM_OWNER_EMAIL in packages/types/src/env.ts:
its value is the organization's id or slug, resolved at boot;
it is read only under a walled posture; single keeps the Default Organization.
Delivery under a wall when it is set: U1's report emits the same security.access_upgrade notification, with the same dedupKey per finding set, stamped with that organization and addressed to the operator or operators (OS_PLATFORM_OWNER_EMAIL). The error log line stays beside it, as it does under single.
Fail loud, never fall back silently:
set but naming no organization: one boot error naming the value and the fix, and the log-line delivery;
set, but the operator is not a member of that organization: a warn that the in-app copy will not be visible to them.
A dedicated organization. The findings are deployment-level and can name other organizations' ids and sharing-rule names, so any administrator of the named organization can read them in Setup, Diagnostics, Notification Events. Document that the organization must hold operators only. Measure whether a boot warn can cheaply flag an administrator of it who is not a configured operator, and add it if so.
Under isolated and group, with the setting naming a dedicated organization the operator belongs to: a vendor rename produces one notification in that organization, visible in the operator's inbox, and none in any other organization. It deduplicates on the next boot.
An unknown value, and the setting left unset, behave as in Wanted 3 and 5. Each is pinned, with a CONTROL.
single is unchanged.
The changeset declares Clause-②: yes (a new setting) and Metadata-protocol: none, at patch. The env docs list the setting next to OS_PLATFORM_OWNER_EMAIL.
R1–R4 hold, with R4 measured under isolated and group.
Claim: card thread · domain:services seat 1 (seat post #6021, project run by the Sales account) · p3 · the whole card · 2026-10-23T14:59Z
Session: session_01XHebWJmL3ZgbVpjM6JERNA
Account: os-sales (the seat's linked user; the card's assignee)
Branch: claude/project-thread-mfvys8 (the harness-pinned branch for this session; it names no issue, so the Duplicate Fix Guard's branch-name hint will not match — this claim is the identity record). This card's PR lands first on it; #24447 (claimed beside this one, same session) follows on the same branch after this PR merges, because its report calls the delivery helper this card adds.
Worktree: objectstack-issue-24447
Domain: domain:services
Seat: domain:services#1 (seat post #6021)
File surface (read on origin/mainb2c07529; stop on a breach and explain it in the report):
packages/plugins/plugin-security/src/upgrade-report-delivery.ts (new): the walled/single delivery of an upgrade report. Single posture unchanged. Walled with the variable unset unchanged (the operator error line). Walled with it set: resolve sys_organization by id, then by slug; found ⇒ emit the same topic and dedupKey stamped with that organization, to the configured operators, with the operator line beside it; not found ⇒ one error naming the value and the fix, then the operator line; a configured operator who is not a member of that organization ⇒ warn; an owner/admin of it who is not a configured operator ⇒ warn.
packages/plugins/plugin-security/src/access-upgrade-report.ts: reportAccessUpgrade hands its findings to the helper; the comparison, the log lines and the single branch are unchanged.
Tests in packages/plugins/plugin-security (helper cases plus the existing U1 wiring test).
content/docs/deployment/environment-variables.mdx: one row beside OS_PLATFORM_OWNER_EMAIL.
One patch changeset for @objectstack/types and @objectstack/plugin-security.
{
"issue": 25413,
"status": "done",
"branch": "claude/project-thread-mfvys8",
"pr": "https://github.com/objectstack-ai/objectstack/pull/25489",
"session": "session_01XHebWJmL3ZgbVpjM6JERNA",
"premise_still_valid": true,
"summary": "Under group and isolated, OS_PLATFORM_OWNER_ORGANIZATION (an id or slug, read only under a wall; PLATFORM_OWNER_ORGANIZATION_ENV and resolvePlatformOwnerOrganization() in @objectstack/types beside the email pair) now raises the access upgrade report in-app: the same security.access_upgrade notification with the same dedupKey, stamped with that organization and addressed to the OS_PLATFORM_OWNER_EMAIL operators, with the operator log line kept beside it. A value naming no organization logs one error naming the value and the fix and raises nothing in-app (no fallback); a configured operator who is not a verified member, and an administrator of that organization who is not a configured operator, each get a warn. The single and walled delivery now lives in one helper, plugin-security's upgrade-report-delivery.ts, which #24447 calls next; reportAccessUpgrade hands its finding set to it, and single is byte-identical. security-plugin.ts, packages/core, packages/spec and service-messaging are not touched.",
"tests": "plugin-security pnpm test: exit 0, 215 files, 4485 passed, 45 skipped. New upgrade-report-delivery.test.ts: 17 cases, each with a CONTROL (id, slug, trimmed value; unset and blank; unknown value; unreadable sys_organization; no messaging; refused emit; no operator; non-member, no-account and unverified operators; administrator by grade and by grant; unreadable sys_member; single with the setting set and unset). access-upgrade-report.wiring.test.ts on a real ObjectQL + SqlDriver + SecurityPlugin: isolated and group with the setting (one emit, organizationId = the owner organization, audience [operator], operator line beside it, same dedupKey on the next boot) and isolated with an unknown value; the existing cases pass unchanged. types env.test.ts: 58 passed. Ablations (committed source mutated with scripts/ablation-replace.mjs, restored, git diff HEAD empty): walled branch forced to the unset path = 16 red; membership warn off = 2 red; admin grade not read = 1 red; slug lookup off = 4 red. R1: showcase dev boot logs the access report's clean info line, 0 ERROR. R4: production os serve of the showcase on persistent SQLite under isolated and group (clean, CONTROL, rename with the setting naming a dedicated r4-platform-ops organization, rename again), plus isolated with an unknown value, unset, an admin member added, and the setting pointing at a tenant. On the rename boot there is one sys_notification in org_r4_platform (dedup security.access_upgrade:a9b33319418033cf427003ea5c64528e), one delivery and one sys_inbox_message for the operator, and none in any other organization; the next boot dedups. The table is in the PR body.",
"gates": "Local: all 100 commands dispatch-gates --commands derived, exit 0, reconciled with --ran. Two needed a second run: check-plugin-teardown-shape --self-test exited 3 in a shallow clone and exits 0 after git fetch --unshallow; check:where-matcher flagged the new double, which now refuses a combinator, and exits 0. check-governed-merges --branch: not governed. PR check-runs on head 07d0ee18, all success: Build Core, Build Docs, Test Core 1/6 to 6/6 and the Test Core aggregate, TypeScript Type Check, Type Check · workspace, source gates, consumer gates, debt ledger, Lint & Repo Gates, Lint · ESLint, Lint · repo & tooling gates, Lint · CI, release & engine gates, Lint · PM dispatch-gates, Lint · docs & code guards, Lint · scoped (tooling self-tests, query-options erasure, slot lookup & corpus), Dogfood Regression Gate, Spec property liveness, Governed Surface Queue Guard, Check Changeset, Check PR Size, Check Documentation Links, Flag docs affected by code changes, the three claim and single-writer guards, Part-of PR must not also close its card, Auto Label; the opt-in and matrix jobs skipped by design.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "28 — reads only: issue_read 11, pull_request_read 7, list_pull_requests 4, list_issues 3, search_issues 3 (this session, both cards); no write tool",
"api_writes": "0 direct REST writes. Every GitHub write went through the scripts/pm fleet-write relay: post-stamped.mjs for the claim 6367880115, label-write.mjs for the assignee and the pm:dispatched label, and fleet-write/dispatch.mjs pr_create for #25489 (opened as a draft)",
"open_questions": [],
"out_of_scope_findings": []
}
MERGED through the queue at 2026-10-23T17:02:49Z (TIER_DEFAULT record PASS and the seat's ACCEPT are on the PR), head 07d0ee185b
origin/main
carries 915e940499
State: Fixes #25413 closed the card. pm:dispatched is now off and the assignee is cleared. The delivery helper upgrade-report-delivery.ts is on main, and #24447's services half (PR #25512) calls it.
Activity
objectstack-fleet commentedon Oct 23, 2026
Claim: card thread ·
domain:servicesseat 1 (seat post #6021, project run by the Sales account) · p3 · the whole card · 2026-10-23T14:59ZSession:
session_01XHebWJmL3ZgbVpjM6JERNAAccount:
os-sales(the seat's linked user; the card's assignee)Branch:
claude/project-thread-mfvys8(the harness-pinned branch for this session; it names no issue, so the Duplicate Fix Guard's branch-name hint will not match — this claim is the identity record). This card's PR lands first on it; #24447 (claimed beside this one, same session) follows on the same branch after this PR merges, because its report calls the delivery helper this card adds.Worktree:
objectstack-issue-24447Domain:
domain:servicesSeat:
domain:services#1(seat post #6021)File surface (read on
origin/mainb2c07529; stop on a breach and explain it in the report):packages/types/src/env.ts:PLATFORM_OWNER_ORGANIZATION_ENV+resolvePlatformOwnerOrganization()beside theOS_PLATFORM_OWNER_EMAILpair (same trim/blank rule).packages/plugins/plugin-security/src/upgrade-report-delivery.ts(new): the walled/single delivery of an upgrade report. Single posture unchanged. Walled with the variable unset unchanged (the operatorerrorline). Walled with it set: resolvesys_organizationby id, then by slug; found ⇒ emit the same topic and dedupKey stamped with that organization, to the configured operators, with the operator line beside it; not found ⇒ oneerrornaming the value and the fix, then the operator line; a configured operator who is not a member of that organization ⇒warn; an owner/admin of it who is not a configured operator ⇒warn.packages/plugins/plugin-security/src/access-upgrade-report.ts:reportAccessUpgradehands its findings to the helper; the comparison, the log lines and the single branch are unchanged.packages/plugins/plugin-security(helper cases plus the existing U1 wiring test).content/docs/deployment/environment-variables.mdx: one row besideOS_PLATFORM_OWNER_EMAIL.patchchangeset for@objectstack/typesand@objectstack/plugin-security.security-plugin.ts(the [maintainer] refactor(plugin-security): splitsrc/security-plugin.ts(10,746 lines, +2,803 in 30 days) along itsSecurityPluginseams, one move-only slice per PR #25223 split series), notpackages/core, notpackages/spec, not the ADR.Container & model:
M, card thread (in-session executor),model: default tier(dispatch-gates --tier: no path-derived mandate),effort: highClause-②: yes (widening)
Metadata-protocol: none
Basis for the Clause-② line: a new optional environment variable; with it unset every posture behaves exactly as on main.
Responsibility:
n/a — not a defect cardThread-read: none
Serial constraints cleared: refactor(plugin-security): move the read filters, field readers and object admissions out of security-plugin.ts (#25223 cut 9) #25456 ([maintainer] refactor(plugin-security): split
src/security-plugin.ts(10,746 lines, +2,803 in 30 days) along itsSecurityPluginseams, one move-only slice per PR #25223 cut 9, draft) editssecurity-plugin.ts, which this card does not touch; no open PR or in-flight claim declaresaccess-upgrade-report.tsorpackages/types/src/env.ts; upgrade-impact comparison after v18: report the non-access classes to the administrator, and retire the zero-consumer package-upgrade.zod.ts #24447 (same session) follows on the same branch.Resume-from: none
Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
os-dev-report
{ "issue": 25413, "status": "done", "branch": "claude/project-thread-mfvys8", "pr": "https://github.com/objectstack-ai/objectstack/pull/25489", "session": "session_01XHebWJmL3ZgbVpjM6JERNA", "premise_still_valid": true, "summary": "Under group and isolated, OS_PLATFORM_OWNER_ORGANIZATION (an id or slug, read only under a wall; PLATFORM_OWNER_ORGANIZATION_ENV and resolvePlatformOwnerOrganization() in @objectstack/types beside the email pair) now raises the access upgrade report in-app: the same security.access_upgrade notification with the same dedupKey, stamped with that organization and addressed to the OS_PLATFORM_OWNER_EMAIL operators, with the operator log line kept beside it. A value naming no organization logs one error naming the value and the fix and raises nothing in-app (no fallback); a configured operator who is not a verified member, and an administrator of that organization who is not a configured operator, each get a warn. The single and walled delivery now lives in one helper, plugin-security's upgrade-report-delivery.ts, which #24447 calls next; reportAccessUpgrade hands its finding set to it, and single is byte-identical. security-plugin.ts, packages/core, packages/spec and service-messaging are not touched.", "tests": "plugin-security pnpm test: exit 0, 215 files, 4485 passed, 45 skipped. New upgrade-report-delivery.test.ts: 17 cases, each with a CONTROL (id, slug, trimmed value; unset and blank; unknown value; unreadable sys_organization; no messaging; refused emit; no operator; non-member, no-account and unverified operators; administrator by grade and by grant; unreadable sys_member; single with the setting set and unset). access-upgrade-report.wiring.test.ts on a real ObjectQL + SqlDriver + SecurityPlugin: isolated and group with the setting (one emit, organizationId = the owner organization, audience [operator], operator line beside it, same dedupKey on the next boot) and isolated with an unknown value; the existing cases pass unchanged. types env.test.ts: 58 passed. Ablations (committed source mutated with scripts/ablation-replace.mjs, restored, git diff HEAD empty): walled branch forced to the unset path = 16 red; membership warn off = 2 red; admin grade not read = 1 red; slug lookup off = 4 red. R1: showcase dev boot logs the access report's clean info line, 0 ERROR. R4: production os serve of the showcase on persistent SQLite under isolated and group (clean, CONTROL, rename with the setting naming a dedicated r4-platform-ops organization, rename again), plus isolated with an unknown value, unset, an admin member added, and the setting pointing at a tenant. On the rename boot there is one sys_notification in org_r4_platform (dedup security.access_upgrade:a9b33319418033cf427003ea5c64528e), one delivery and one sys_inbox_message for the operator, and none in any other organization; the next boot dedups. The table is in the PR body.", "gates": "Local: all 100 commands dispatch-gates --commands derived, exit 0, reconciled with --ran. Two needed a second run: check-plugin-teardown-shape --self-test exited 3 in a shallow clone and exits 0 after git fetch --unshallow; check:where-matcher flagged the new double, which now refuses a combinator, and exits 0. check-governed-merges --branch: not governed. PR check-runs on head 07d0ee18, all success: Build Core, Build Docs, Test Core 1/6 to 6/6 and the Test Core aggregate, TypeScript Type Check, Type Check · workspace, source gates, consumer gates, debt ledger, Lint & Repo Gates, Lint · ESLint, Lint · repo & tooling gates, Lint · CI, release & engine gates, Lint · PM dispatch-gates, Lint · docs & code guards, Lint · scoped (tooling self-tests, query-options erasure, slot lookup & corpus), Dogfood Regression Gate, Spec property liveness, Governed Surface Queue Guard, Check Changeset, Check PR Size, Check Documentation Links, Flag docs affected by code changes, the three claim and single-writer guards, Part-of PR must not also close its card, Auto Label; the opt-in and matrix jobs skipped by design.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "28 — reads only: issue_read 11, pull_request_read 7, list_pull_requests 4, list_issues 3, search_issues 3 (this session, both cards); no write tool", "api_writes": "0 direct REST writes. Every GitHub write went through the scripts/pm fleet-write relay: post-stamped.mjs for the claim 6367880115, label-write.mjs for the assignee and the pm:dispatched label, and fleet-write/dispatch.mjs pr_create for #25489 (opened as a draft)", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Landed ·
domain:servicesseat 1 (seat post #6021) ·os-sales·session_016g7nYP9wdNx1GDa5XDr7Uy· 2026-10-23T17:40Z07d0ee185borigin/main915e940499State:
Fixes #25413closed the card.pm:dispatchedis now off and the assignee is cleared. The delivery helperupgrade-report-delivery.tsis onmain, and #24447's services half (PR #25512) calls it.Generated by Claude Code