Repository navigation
Description
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
Filing gate: ③ a task on the maintainer's word. For cloud#3668 (Enterprise P2-8) the maintainer selected, verbatim, 「支持按组织(推荐)」 (access policy per organization) and 「可以,按三档做(推荐)」 (an MFA requirement of off / administrators / everyone, where "administrators" means ADR-0090 D12's three kinds). Gaps measured by the cloud#3668 dev (report 6684026104). Platform gaps go to the platform: 「平台的问题应该在平台处理」 (objectstack#30765). Consumer: objectstack-ai/cloud#3668, pm:blocked on this card.
维护者速读
企业版一个数据库里可以有多个组织,但现在 IP 白名单、会话闲置和最长时长、同时在线数这些策略,整个部署只有一份。双重验证也只有全局开关和按组织的「全员必须开」,没有「管理员必须开」这一档。按你的两个决定:这些策略改为每个组织可以各自设置,部署级设置作为默认值和下限;双重验证做成三档,不强制 / 管理员必须开 / 全员必须开,管理员按 ADR-0090 D12 的三类认定。
Measured (objectstack 2ffdb649)
- The whole
authsettings namespace is scopeglobal(packages/services/service-settings/src/manifests/auth.manifest.ts:13).allowed_ip_ranges(:372) feeds oneAuthManagerOptions.allowedIpRanges(auth-manager.ts:6009).- The idle, absolute and concurrent limits (
:334,:344,:354) feed single deployment values (auth-manager.ts:1056-1058), enforced atauth-manager-password-session-policy.ts:616-644.
- MFA:
- a global
auth.mfa_required(auth.manifest.ts:286,auth-plugin.ts:2317); - a per-organization
sys_organization.require_mfa(auth-manager-password-session-policy.ts:183-190); resolveUserAuthGateshas no administrator dimension.
- a global
- objectos-ee runs several organizations in one database under
OS_TENANCY_POSTURE=isolated|group(cloudapps/objectos-ee/objectstack.config.ts:866).
Expected
- Per-organization values. The access-policy keys can be set per organization. The deployment value is the default.
- The deployment value is also the floor: an organization may tighten but not loosen. Narrower IP ranges, shorter timeouts and a stronger MFA level are allowed; the reverse is not.
- The lane states the rule exactly for each key.
- Resolution happens per request against the caller's organization.
- MFA levels:
off|administrators|everyone.administratorscovers ADR-0090 D12's tenant-level, organization-level and delegated administrators, and reuses the existing predicates (⛔ no new admin concept).- Map
require_mfaand the global flag onto the levels, with a migration.
- The last-admin break-glass guard and the existing self-lock-out save guard (
allowed-ip-ranges.ts,GET /admin/client-address) hold per organization. - Spec: whatever settings or schema keys this adds go through the spec rules (
Clause-②judged on the diff).
Acceptance
- Tests:
- two organizations in one deployment with different IP ranges and MFA levels, each enforced on its own members;
- an organization cannot loosen below the deployment floor;
- an
administratorslevel holds an org admin and lets a plain member through.
Suggested-grade: p1 · Enterprise priority (maintainer).
Dedupe (2026-11-06): allowed_ip_ranges per organization → 3 hits (#30302 closed, #2571 closed, #2375 closed); require_mfa role → 5 hits (#24538 closed, #23287 closed, #23335 closed, #10757 closed)
. None covers this gap (the open hits are QA runs or unrelated settings cards).
Activity
objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
Claim: PM loop round R6 · 2026-11-06T11:55Z
Session:
session_01Q4EjjRhUZjdy8VXs6Kkur2Account:
hotlong(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-30922-per-org-access-policyWorktree:
/home/user/w30922/objectstack-issue-30922Domain:
domain:server(claimed by therepo:cloudlane that filed it, on the maintainer's Enterprise priority, verbatim 「cloud 多了几个企业版的任务,优先处理」)Seat:
repo:cloud#3File surface:
packages/services/service-settings/src/manifests/auth.manifest.ts(per-organization scope for the access-policy keys),packages/plugins/plugin-auth(auth-manager.tsoption resolution per request,auth-manager-password-session-policy.tsMFA levels and session limits, the IP allow-list middleware, the self-lock-out and break-glass guards), therequire_mfa/ global-flag migration, spec keys if any, and testsContainer & model:
M,mode:subagent,model: TIER_DEFAULT,effort: highClause-②: yes (widening) — per-organization access-policy settings and an MFA level; also narrows if the global flag's meaning changes; re-judged on the diff and reviewed before the queue
Metadata-protocol: none
Responsibility: per-organization access policy with three MFA levels (cloud#3668 rulings G2/G3) | none | every multi-organization deployment's sign-in policy
Thread-read: none
Premise: holds — measured by the cloud#3668 dev at objectstack
2ffdb649(report 6684026104 on objectstack-ai/cloud#3668)Serial constraints cleared: objectstack#30924 (refusal audit rows) waits on objectstack#30922 because both edit
auth-manager-password-session-policy.ts; #30922 and #30923 touch different packages.Carrier: objectstack.
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p1 kept ·
domain:server· 2026-11-06T12:30Z⛔ Not a claim.
domain:server#4's ask (6684221785). Per-organization access policy (allowed IP ranges, session idle / absolute / concurrent limits, and a three-tier MFA requirement), on the maintainer's words for objectstack-ai/cloud#3668 (「支持按组织(推荐)」, 「可以,按三档做(推荐)」).repo:cloud#3(assigneehotlong) and has a single claim.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Notify: serial · #30924 ↔ #30922 · 2026-11-06T12:52Z · ⛔ Not a claim.
For this card's carrier (repo:cloud#3): #30924 (seat
domain:server#3, branchclaude/project-thread-o1vsm1) opens PR1 now. It adds one member,resolveUserAuthGates, to theDatabaseHooksHostPick union and one forwarding closure inauth-manager.tscomposeDatabaseHooks. That is the same union line your WIP15ec27e3extends withjudgeSessionScoping. Whichever lands second keeps both members, a mechanical one-line resolution. #30924's PR2 (IP-refusal audit rows) waits for this card's PR to merge, and it will also write alogin_failedrow at your per-orgSESSION_SCOPING_REFUSAL. Please tell #30924 when your PR is up.objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
os-dev-report
{ "issue": 30922, "status": "done", "branch": "claude/issue-30922-per-org-access-policy", "pr": "https://github.com/objectstack-ai/objectstack/pull/31013", "session": "session_01Q4EjjRhUZjdy8VXs6Kkur2", "premise_still_valid": true, "summary": "Each organization now sets its own allowed IP ranges, idle/absolute/concurrent session limits and MFA requirement in a new tenant-scoped settings namespace `access_policy` (one sys_setting row per organization, written with setup.write); the deployment's `auth` values are the default and the floor, enforced twice: a weaker value is refused at the save (settings write predicates), and enforcement combines both values (shorter limit, stronger level, both IP lists) so the floor holds whatever is stored. MFA has three levels off/administrators/everyone on both the deployment (`auth.mfa_required`, toggle -> select) and the organization; `administrators` reuses the PLATFORM_ADMIN/TENANT_ADMIN posture rungs of resolveUserAuthzGrants plus a resolved adminScope set (delegated). Which organization's policy applies: the session's active organization; the sign-in request itself is judged by the deployment floor only, and the session's scoping (session.create after ADR-0093 D9 picks the org, and an active-org switch) is refused 403 IP_NOT_ALLOWED from an address the org list does not admit; a platform administrator is held by the deployment list only (per-org break-glass); the self-lock-out save check and the org MFA enrollment refusal hold per organization. Boot-time convergent migrations move a stored `auth.mfa_required` toggle to a level and every `sys_organization.require_mfa = true` to `access_policy.mfa_required = everyone` (column cleared only after the row lands; retired column readonly). Mechanism deviation, measured: ADR-0069 TL;DR 6/D5/D7 name sys_organization.* columns as the per-org store; the dispatch's settings tenant rung was kept because only a settings write predicate receives the saving request's transport (needed for the per-org self-lock-out guard) and it is the store org admins already write; an ADR-0069 status-line amendment is owed (see open_questions).", "tests": "Final local runs at head 4513cb9d42 tree (chain started at e1edf0785a; the two later commits only add collection-time imports to verify pins and were on disk for the verify run): plugin-auth `pnpm --filter @objectstack/plugin-auth test` Test Files 231 passed (231), Tests 4111 passed | 10 skipped; service-settings test Test Files 71 passed, Tests 1367 passed; platform-objects test Test Files 117 passed, Tests 1591 passed; verify held-session pins (3 files) Tests 49 passed. New: organization-access-policy.test.ts (per-key floor rule + two orgs through the real better-auth pipeline: each org's IP ranges admit only its own members 403 IP_NOT_ALLOWED otherwise, refused scoping leaves no session row, platform-admin break-glass, each org's idle timeout ends only its own members' sessions), organization-access-policy-mfa-level.test.ts (administrators level holds an org admin and lets a plain member through; tenant-level and delegated held; judged in the scoped org; two orgs each at own level; cannot go below deployment level), organization-mfa-enrollment-guard.test.ts rewritten on a real SettingsService (enrollment refusal, floor refusals in SETTINGS_VALIDATION envelope, cache drop on change, both migrations incl. failed move). Ablations via scripts/ablation-replace.mjs (anchor x1->x0 / x0->x1 on disk, auto-restore; tests import src so no dist leg): A1 scoping 2 failed, A2 break-glass 1, A3 limit floor 3, A4 range floor 2, A5 MFA floor 2, A6 shorter limit 2, A7 stronger level 7, A8 D12 admin predicate 4, A9 session limits read session org 1, A10 org self-lock-out 1, A11 org enrollment 2, A12 require_mfa move 2, A13 scoping hook 2 (of 23); restore git diff HEAD empty, control 23/23 passed. A10's anchor was later reshaped type-only.", "gates": "Local: `node scripts/pm/dispatch-gates.mjs --commands` (tree 6a149950f9, post-merge) derived 80 families; all 80 run (`--ran` reconciliation: 80 derived, 80 run, 0 UNRUN). Exit codes captured before any pipe: 76 exit 0 on their final run; check:objectql-double-limit 1 -> fixed -> 0; check:slot-lookup 1 -> fixed -> 0; check:test-source-alias 1 -> fixed (two rounds) -> 0; check:engine-double-contract 1 -> ledger written (--write) -> 0. NOT MEASURED: check:type-check-debt (exit 3, its closure build could not take the shared verify lock), check:dual-build-cjs-loads (exit 3, PREREQUISITE NOT MET: a package without dist/). Also: check-adr-0087-registration 0 (runtime-interface-only verified), check-platform-checklist --changed-from origin/main 0 (31 anchors, 0 lost), check:i18n 0, check:i18n-stale-fill 0, typecheck plugin-auth/service-settings/platform-objects/verify 0. CI check-runs: in_progress at report time (not awaited, per contract).", "dogfood_battery": "head tree 4513cb9d42 (chain HEAD e1edf0785a) · os-verify-lock: VERDICT command-exit 0 · `pnpm --filter @objectstack/dogfood test` Test Files 427 passed | 3 skipped (430) · Tests 3556 passed | 41 skipped (3597) · no failures", "mcp_calls": "0", "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches -> pulls #31013, draft, read back identical 13003/13003 bytes) and this os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/30922/comments); plus git pushes (not REST)", "open_questions": [ { "question": "ADR-0069 TL;DR 6, D3 and D7 name `sys_organization.*` columns as the per-organization override store, while this PR (following the dispatch's measured route) keeps per-org policy in the settings tenant rung and retires `sys_organization.require_mfa`. Which record carries that?", "options": [ "A: the seat files a docs-only status-line amendment to ADR-0069 (Tier H, maintainer approval) recording that per-organization access-policy overrides live in the `access_policy` settings namespace (tenant rung, ADR-0007/ADR-0131), the tighten-only rule unchanged; cost: one governed docs PR", "B: rework to sys_organization columns as the ADR text says; cost: the per-org self-lock-out save guard loses the saving request's transport (an engine hook has no client address) and needs new plumbing into ExecutionContext, plus a second store beside settings; roughly this PR again" ], "recommendation": "A, because the decision ADR-0069 makes (tighten-only per-org overrides) is unchanged and the settings tenant rung is the store org admins already write and the only one whose save door carries the request transport the guard needs; the amendment records where, not what." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: cloud · objectstack-ai/cloud `apps/cloud/test/settings-cross-org-doors.test.ts:511` writes `settings.set('auth','mfa_required', true)`; after the framework pin moves past this PR the value is refused by the new option table — rewrite as 'everyone' in the pin-move PR (consumer cloud#3668). noted, not filed", "carrier: none · `ui/packages/app-shell/src/console/organizationMfaNotices.ts` (record-form notices around `require_mfa`) no longer fires, the column being readonly; inert UI code, noted in the PR's Acceptance notes, not filed (dead code, no reach)", "carrier: none · `GET /admin/client-address` stays platform-admin only, so an organization administrator learns the judged address from the save refusal's constraint.clientAddress rather than before saving; noted in Acceptance notes" ] }objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
Ruling: objectstack#30922 · ADR-0069 store wording · maintainer 「修订 ADR 写明存放位置(推荐)」 · 2026-11-06T18:32Z
Provenance: the maintainer, in person, in the
repo:cloud#3seat sessionsession_01Q4EjjRhUZjdy8VXs6Kkur2, on the open question of os-dev report 6691336201.What binds.
access_policysettings namespace (ADR-0007 / ADR-0131 tenant rung).sys_organization.*columns today. The tighten-only rule is unchanged.objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
Claim: PM loop round R7 · 2026-11-06T19:09Z · second branch on this card (the ADR-0069 amendment the maintainer ruled, comment above)
Session:
session_01Q4EjjRhUZjdy8VXs6Kkur2Account:
hotlong(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-30922-adr0069-store-amendmentWorktree:
/home/user/w30922b/objectstack-issue-30922-adrDomain:
domain:server(as claimed for this card)Seat:
repo:cloud#3File surface:
docs/adr/0069-*.mdonly (status-line amendment, plus the TL;DR 6 / D3 / D5 / D7 store wording) and the ADR index ifpnpm adr:indexchanges it. Governed path (docs/adr/**): Tier H, so the maintainer merges and the seat never does.Container & model:
S,mode:subagent,model: TIER_DEFAULT,effort: mediumClause-②: no — docs only
Metadata-protocol: none
Responsibility: ADR-0069 records where per-organization access-policy overrides live | none | readers of ADR-0069, and PR #31013's reviewers
Thread-read: none
Premise: holds — ADR-0069 at objectstack
origin/main41dc302496namessys_organization.*columns as the per-organization store, while PR #31013 stores them in theaccess_policysettings tenant rung. Maintainer ruling 「修订 ADR 写明存放位置(推荐)」.Serial constraints cleared: no in-flight claim on ADR-0069.
Carrier: objectstack.
objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
os-dev-report
{ "issue": 30922, "status": "done", "branch": "claude/issue-30922-adr0069-store-amendment", "pr": "https://github.com/objectstack-ai/objectstack/pull/31041", "session": "session_01Q4EjjRhUZjdy8VXs6Kkur2", "premise_still_valid": true, "summary": "ADR-0069 is amended in place, docs only, as draft PR #31041 (Tier H, the maintainer merges). Changes: a dated 2026-11-06 'Amended in place' status-line note citing ruling record 6692407743 on #30922 (verbatim 「修订 ADR 写明存放位置(推荐)」) and PR #31013; the store wording in TL;DR 6, the D3 per-org row, the D5 first row and the D7 field list changed from sys_organization.* to the settings tenant rung (access_policy namespace, one sys_setting row per organization); and a closing note under D7 that keeps the tighten-only rule, gives the why (only a settings write predicate receives the saving request's transport, which the per-org self-lock-out save guard needs; it is the store org admins already write), and records require_mfa as retired and no allowed_ip_ranges column added. No other decision changes. #31013's should-fix mechanics are not described. The dated status snapshots (D7 'Implementation status (2026-07-04)', Phasing P1/P2 rows) are left as written and the note says so. Premise verified at origin/main 41dc302496: those four places named sys_organization.* columns.", "tests": "Docs-only diff, so no tests apply. Every reading is at head ec3f44b944, whose tree e787194fc0 is identical to e0d1d72199 where the gates ran (the amend changed only the commit message). Ablation: n/a, no tested behaviour changed. Control-byte self-scan on the ADR: no hits.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack (tree objectstack @ e0d1d72199, 1 path, 27 changed lines) derived 21 commands. 20 exit 0: check-adr-links (+self-test), check-closing-keyword-parity (+self-test), check-comment-mask-corpus, plan-test-core-shards --self-test, and pnpm check:adr-anchors, adr-index, adr-symbol-anchors, ci-filter-parity, closed-ceremony-text, cross-package-test-inputs, doc-authoring, driver-memory-census, gitlink-declared, nul-bytes, pm-governed-merges, pm-prior-rulings, refd-timer-probe, watch-hint-literal. 1 NOT MEASURED: check:doc-formula-expressions exited 3 (PREREQUISITE NOT MET: formula/lint not built). Its prerequisite build queued twice on os-verify-lock (slot issue-30922-adr) and timed out twice (exit 99, 9m each) behind holder pid 24520, the sibling #31013 chain5.sh, which had held the lock 2741s. Declared narrowing: CI Lint & Repo Gates runs this family. --ran reconciliation: '21 derived famil(ies) accounted for — 20 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)', exit 0. pnpm adr:index: exit 0, 'unchanged docs/adr/README.md (237 lines)'. PR check-runs at report time: Check Changeset success, Governed Surface Queue Guard success; Lint (ESLint, docs & code guards, repo & tooling gates, CI/release/engine gates, PM dispatch-gates, scoped lanes), Type Check (workspace, source, consumer, debt ledger), Check Documentation Links and the PR-body guards all in_progress. CI convergence is the PM's to read.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "3 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST /repos/objectstack-ai/objectstack/issues/31041/labels skip-changeset, one stroke, run 42282439897), plus the os-dev-report via post-stamped (POST /repos/objectstack-ai/objectstack/issues/30922/comments). git push x2 (the empty-branch probe, then ec3f44b944) is not REST.", "open_questions": [ { "question": "D3's deployment row still reads `mfa_required` (global toggle), while the three MFA levels off/administrators/everyone (ruled on cloud#3668) are not recorded in ADR-0069. Should a further amendment record them?", "options": ["A: leave ADR-0069 as amended here; the levels live in #31013 and cloud#3668's rulings", "B: a second status-line amendment recording the levels in D3, after #31013 settles"], "recommendation": "B, after #31013 lands, because ADR-0069 D3 then contradicts the shipped setting shape. It is outside this order (store wording only), so it was not done here." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: repo:cloud#3 seat · D3's 'mfa_required (global toggle)' wording versus the three-level MFA setting (open_questions[0]) · noted in PR #31041 Acceptance notes, not filed", "carrier: none · deviations: the first push was refused by pre-push check:commit-card-trailers ('Refs #30922' in the commit message); the unpublished commit was amended to drop the card references (tree unchanged, no force-push). Scratch logs for this run first landed in the sibling's shared scratchpad/issue-30922 directory under names it does not use, so nothing was overwritten; they were moved to scratchpad/issue-30922-adr." ] }objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
os-dev-report
{ "issue": 30922, "status": "done", "branch": "claude/issue-30922-adr0069-store-amendment", "pr": "https://github.com/objectstack-ai/objectstack/pull/31041", "session": "session_01Q4EjjRhUZjdy8VXs6Kkur2", "premise_still_valid": true, "summary": "On the seat's call, the three MFA levels are folded into the ADR-0069 amendment as new commit 27e0710231 on PR #31041 (Tier H, draft; no amend, no force-push). In D3, the deployment row's `mfa_required` changes from 'global toggle' to the deployment level `off` / `administrators` / `everyone`, default off. Its mechanism now reads 'when the level covers the user' (`everyone`: every user; `administrators`: ADR-0090 D12's tenant-level, organization-level and delegated administrators). The per-organization row takes the same three levels under the tighten-only rule: `off` or a level at least as strong as the deployment's, a stronger level only. The dated status-line note gains one clause for the levels, citing ruling G2 on objectstack-ai/cloud#3668 (record 6684194038, verbatim 「可以,按三档做(推荐)」), with the deployment value as default and floor. #31013's should-fix mechanics (concurrent cap, organization switch, retired-option refusal) are not described. Item 6 was not executed as ordered: I did not PATCH the PR body (conflict named in open_questions). The replacement body, with the levels added to 维护者速读, the before/after table, the Acceptance notes and Verification, is ready for the seat at /tmp/claude-0/-home-user/681a6c6c-7819-57eb-aed2-6900ff14a303/scratchpad/issue-30922-adr/pr-body-v2.md.", "tests": "Docs-only diff, so no tests apply. Readings are at head 27e0710231. Ablation: n/a. Control-byte self-scan on the ADR: no hits. pnpm adr:index: exit 0, 'unchanged docs/adr/README.md (237 lines)' (the status line stays on line 3, inside the 40-line header window).", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 27e0710231 (1 path, 29 changed lines) derived 21 commands, the same list as the first run. 20 exit 0: check-adr-links (+self-test), check-closing-keyword-parity (+self-test), check-comment-mask-corpus, plan-test-core-shards --self-test, and pnpm check:adr-anchors, adr-index, adr-symbol-anchors, ci-filter-parity, closed-ceremony-text, cross-package-test-inputs, doc-authoring, driver-memory-census, gitlink-declared, nul-bytes, pm-governed-merges, pm-prior-rulings, refd-timer-probe, watch-hint-literal. 1 NOT MEASURED: check:doc-formula-expressions exited 3 (PREREQUISITE NOT MET; the formula/lint build needs os-verify-lock, held by pid 17875 (cloud#3661) with pid 28279 queued; two earlier 9m attempts were exit 99). Declared narrowing: CI Lint & Repo Gates runs it. --ran reconciliation: '21 derived famil(ies) accounted for — 20 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)', exit 0. Caveat: dispatch-gates flagged a STALE TREE. The branch is 5 or more commits behind origin/main 3fe5f2a025, and scripts/regen-artifacts.mjs (not in this diff, not a family on this list) changed across that range. main was not merged into the open PR (AGENTS.md section 10: only on a conflict, a main-caused red or a queue removal); CI runs on the merge ref. PR check-runs at 27e0710231 at report time: Governed Surface Queue Guard success, Check Documentation Links success, PR-body guards success, Check PR Size success, Test UI success; Lint (all lanes) and Type Check (all lanes) in_progress.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "1 this round — os-dev-report via post-stamped (POST /repos/objectstack-ai/objectstack/issues/30922/comments). git push of 27e0710231 is not REST. No PR body PATCH.", "open_questions": [ { "question": "The seat's item 6 ('update the PR body's 维护者速读') conflicts with os-dev.md: 'PR 正文 dev 只写一次,在开 PR 那一笔,⛔ 不 PATCH;事后要改的报告点名改法,席位代写', and the dispatch-vs-file rule says the file wins. Who writes the revised body?", "options": ["A: the seat PATCHes PR #31041's body with the prepared replacement (scratchpad issue-30922-adr/pr-body-v2.md: 维护者速读 改了什么/为什么改/两分钟验证 mention the three levels; the What changes paragraph, status-line row, a new D3 deployment row in the table, the D3 per-org mechanism note, the Acceptance notes and the Verification head are updated; first three lines unchanged)", "B: the dev PATCHes it on an explicit per-order override recorded in os-dev.md"], "recommendation": "A, because it is what os-dev.md prescribes and the text is ready. Read the body back after the write; the footer is already in the prepared text, so do not re-append one." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · earlier open question (the three MFA levels) is resolved by this commit; nothing filed" ] }objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
os-dev-report
{ "issue": 30922, "status": "done", "branch": "claude/issue-30922-adr0069-store-amendment", "pr": "https://github.com/objectstack-ai/objectstack/pull/31041", "session": "session_01Q4EjjRhUZjdy8VXs6Kkur2", "premise_still_valid": true, "summary": "Both should-fixes from contract review 6694338252 are applied as new commit f3ce9c02b3 on PR #31041 (no amend, no force-push, no card reference in the message). S1: in the D3 per-organization row, 'a stronger level only' becomes 'never a weaker one'; the first clause 'a level at least as strong as the deployment's' is kept. S2: the D7 note's ADR-0131 citation gains one parenthetical, '(organization ownership is total: each such row is owned by its organization, and only the settings global rung leaves `sys_setting`)'. The second half follows ADR-0131 D7's text that sys_setting's global rung leaves the tenant-scoped table. Nothing else changed (+3/-2 lines); O1 (the D5 seam cell) is untouched. The PR body was not PATCHed. It now quotes the old S1 wording, so the exact replacements are listed in open_questions for the seat to write.", "tests": "Docs-only diff, so no tests apply. Readings are at head f3ce9c02b3. Ablation: n/a. Control-byte self-scan on the ADR: no hits. pnpm adr:index: exit 0, 'unchanged docs/adr/README.md (237 lines)'.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at f3ce9c02b3 (1 path, 30 changed lines) derived 21 commands, the same list as before. 20 exit 0: check-adr-links (+self-test), check-closing-keyword-parity (+self-test), check-comment-mask-corpus, plan-test-core-shards --self-test, and pnpm check:adr-anchors, adr-index, adr-symbol-anchors, ci-filter-parity, closed-ceremony-text, cross-package-test-inputs, doc-authoring, driver-memory-census, gitlink-declared, nul-bytes, pm-governed-merges, pm-prior-rulings, refd-timer-probe, watch-hint-literal. 1 NOT MEASURED: check:doc-formula-expressions exited 3 (PREREQUISITE NOT MET). The formula/lint build needs os-verify-lock, which is held by pid 12759 (the sibling #31013 chain6.sh) with two runs queued. Declared narrowing: CI Lint & Repo Gates runs it. --ran reconciliation: '21 derived famil(ies) accounted for — 20 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)', exit 0. STALE TREE caveat as before: 6 or more commits behind origin/main, with scripts/regen-artifacts.mjs (not in this diff) changed across that range; main was not merged into the open PR (AGENTS.md section 10). PR check-runs at f3ce9c02b3 at report time: Governed Surface Queue Guard, Check Documentation Links, PR-body guards, Check PR Size and Test UI success; Lint and Type Check lanes in_progress.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "1 this round — os-dev-report via post-stamped (POST /repos/objectstack-ai/objectstack/issues/30922/comments). git push of f3ce9c02b3 is not REST. No PR body PATCH.", "open_questions": [ { "question": "PR #31041's live body still quotes the S1 wording this commit replaced, and its Verification line names the old head. These are the exact replacements for the seat to write, each old string occurring once in the live body: (1) in 维护者速读 改了什么, '组织级同样三档、只能更强。' becomes '组织级同样三档、不得弱于部署级(可相同或更强)。'; (2) in the D3 per-org table row, 'a stronger level only (`off`, then' becomes 'never a weaker one (`off`, then'; (3) in Acceptance notes, 'The per-organization row allows a stronger level only.' becomes 'The per-organization row allows a level at least as strong as the deployment's, never a weaker one.'; (4) the Verification sentence starting 'All readings were taken at head `27e0710231`, where the gates were re-run after the levels commit.' changes in its head and commit phrase to 'All readings were taken at head `f3ce9c02b3`, where the gates were re-run after the wording commit (review 6694338252 S1/S2).', and its '5 or more commits behind' becomes '6 or more commits behind'; the rest of that sentence is unchanged.", "options": ["A: the seat applies the four replacements and reads the body back", "B: leave the body as is until the delta review"], "recommendation": "A, because line (2) and line (3) misstate the ADR text the reviewer will read. Read the body back after the write and do not re-append the footer." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · O1 (the D5 seam cell) left as is by order, until #31013 settles; nothing filed" ] }objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
os-dev-report
{ "issue": 30922, "status": "done", "branch": "claude/issue-30922-per-org-access-policy", "pr": "https://github.com/objectstack-ai/objectstack/pull/31013", "session": "session_01Q4EjjRhUZjdy8VXs6Kkur2", "premise_still_valid": true, "summary": "Rework for contract review 6692495550, at head b0b494c04a. origin/main merged once, by merge with no rebase, at 56fe7fdf74; `docs/adr/**` untouched. M1: the cli Setup-tree pin moves 31 -> 32 and asserts `nav_settings_access_policy`. M2: zh-Hant sidebar label 存取原則 (platform-objects zh-Hant.ts), zh-Hant copy for the retired `require_mfa` column, and ru/de/ko/zh-Hant access_policy settings copy; check:app-nav-i18n exit 0. S1, the concurrent cap: two caps over two populations. The deployment cap counts every live session of the user, in any organization, which keeps its pre-existing meaning so the floor never loosens. An organization's own cap counts only the user's sessions scoped to that organization and ends only those, oldest first, so a strict-org sign-in never evicts another organization's sessions. Both caps are swept at sign-in (keeping the new session) and at an active-organization switch, where the switching session counts as scoped to the target and is kept. A strict organization's cap therefore cannot be exceeded by switching sessions in. S2: a switch is judged against the target organization's IP list, its idle and absolute limits, and its cap, before it lands, from the session row as it stands. The switch request runs no heartbeat, so last_activity_at is not refreshed first. Idle means the session's own inactivity, so activity in another organization counts as activity. A session past either limit is ended in place (the D4 revocation) and the switch is refused with 401 UNAUTHENTICATED. S3 fixed: on every session read through the HTTP auth door, the organization's IP list is judged again with the address that door established, and a session the list no longer admits is ended in place with reason ip_not_allowed. S4 fixed: the per-org self-lock-out check no longer refuses a tenant-level administrator's save (`AuthManager.isTenantLevelAdministrator`, the scoping's own predicate). S8: `assertMfaRequirementOptions` refuses the retired `mfaRequired` key, and a non-level `mfaRequirement`, at AuthManager construction and on applyConfigPatch, with a message naming the replacement. S5: the changeset's upgrade note now says a write of true/false to `auth.mfa_required` is refused (`invalid_option`) and names cloud `apps/cloud/test/settings-cross-org-doors.test.ts:533/:552` for the pin move. The rules are stated in the organization-access-policy.ts header (cap, switch, roaming, 30 s / 60 s staleness) and in the access_policy manifest help. Also: the tenant-audit census page moves 261 -> 262 write sites for the switch revocation's write, and an idle/absolute `revoke_reason` slip introduced mid-rework was fixed before any run counted (diff vs origin/main on that file shows no revoke_reason change). PR body: written once at pr_create, so not patched by me. Additions for the seat to write: (1) S5, beside the auth.mfa_required narrowing: 'A write of `true`/`false` to `auth.mfa_required` is now refused by the option table (`invalid_option`); consumer objectstack-ai/cloud `apps/cloud/test/settings-cross-org-doors.test.ts:533` (write) and `:552` (read-back) must be rewritten to `everyone` in the pin move.' (2) the cap, switch and roaming rules above, replacing Acceptance notes bullet 3 (roaming), and dropping the A10 note; (3) the Tests and Ablations sections should add the S1/S2/S3/S4/S8 ablations from `tests`.", "tests": "At head b0b494c04a: plugin-auth `pnpm --filter @objectstack/plugin-auth test` Test Files 231 passed (231), Tests 4125 passed | 10 skipped. At 2e1b12c269 (later commits: census docs, typed engine options in auth-manager.ts only, re-covered by the plugin-auth run above): service-settings test Test Files 71 passed, Tests 1369 passed; platform-objects test Test Files 117 passed, Tests 1637 passed; cli `pnpm --filter @objectstack/cli test` (both layers) Test Files 600 passed | 1 skipped, Tests 7401 passed | 9 skipped. Verify held-session pins at b0b494c04a: 3 files, 49 passed. New-rule tests (organization-access-policy.test.ts): roaming re-judgement end to end through handleRequest; the org cap ends only that org's oldest sessions; a switch sweep keeps the switching session; the deployment cap still counts every session; the session-update hook sweeps the target's cap on a switch; a switch past the target's idle limit is ended and refused with last_activity_at not refreshed first; absolute limit at switch; the retired option is refused at construction and on patch. organization-mfa-enrollment-guard.test.ts: the self-lock-out check refuses an org admin saving from outside but admits a tenant-level admin, on a real SettingsService. Ablations through scripts/ablation-replace.mjs (anchor x1->x0 on disk, auto-restore, trap `git checkout HEAD`), failures out of 27 or 19 tests: S1a org-only population 1, S1b switch sweep in the hook 1, S1c keep the switching session 2/19 (first attempt refused by the tool for an empty replacement, so no run; re-run with --delete), S2a switch judged 1, S2b switch idle rule 1, S3 roaming re-judgement 1, S4 tenant-admin save 1, S8a construction refusal 1, S8b patch refusal 1. Restore: git diff HEAD empty after each pass; control 27/27 passed.", "gates": "`node scripts/pm/dispatch-gates.mjs --commands` at 2e1b12c269 derived 81 families, all run, plus check:app-nav-i18n exit 0. Exit codes captured before any pipe. All exit 0 on their final run except as noted. check-tenant-audit-census (and --self-test) went 1 -> 0 after `tenant-audit-census.mjs --write` plus the page's prose counts. check:query-options-erasure went 1 -> 0 after typing the switch judgement's engine options. The census page edit then derived 27 more docs families (108 total): 26 exit 0; @objectstack/spec check:skill-examples exit 3, PREREQUISITE NOT MET. Families that read the last-touched sources were re-run at b0b494c04a, all exit 0: system-context-census, durability-log-level, slot-lookup, error-status-conformance, issue-citations, doc-authoring, nul-bytes, tenant-audit-census, query-options-erasure. check-adr-0087-registration exit 0. NOT MEASURED, all exit 3 on missing prerequisites: check:dual-build-cjs-loads (a package without dist/), check:type-check-debt (its closure build could not take the verify lock), spec check:skill-examples. `--ran` over the 81: 81 run; the 27 docs families were run separately (list above). CI check-runs on the new head not awaited (in_progress).", "dogfood_battery": "b0b494c04a · os-verify-lock: VERDICT command-exit 0 · `pnpm --filter @objectstack/dogfood test` Test Files 428 passed | 3 skipped (431) · Tests 3561 passed | 41 skipped (3602) · no failures", "mcp_calls": "0", "api_writes": "1 this round — this os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/30922/comments). PR body not patched. Plus git pushes (not REST).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: seat · S6 (inert `ui/packages/app-shell/src/console/organizationMfaNotices.ts`) and S7 (a setup.write-gated client-address read) are seat follow-ups per the dispatch; not touched here", "carrier: cloud · objectstack-ai/cloud `apps/cloud/test/settings-cross-org-doors.test.ts:533/:552` writes and reads back `auth.mfa_required = true`; the pin move past this release must rewrite both to `everyone` (now in the changeset upgrade note)" ] }objectstack-fleet commentedon Nov 7, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
os-dev-report
{ "issue": 30922, "status": "done", "branch": "claude/issue-30922-per-org-access-policy", "pr": "https://github.com/objectstack-ai/objectstack/pull/31013", "session": "session_01Q4EjjRhUZjdy8VXs6Kkur2", "premise_still_valid": true, "summary": "Merge round. `git merge origin/main` (43 commits; no rebase, no force-push) on b0b494c04a gave merge commit a06983b5c0, which is the final head. Conflicted files, both generated by the tenant-audit census: content/docs/permissions/tenant-audit-census.mdx and docs/audits/2026-08-tenant-audit-write-call-sites.counts.md. Resolution keeps both sides: take main's versions (main had moved the census from 261 to 266), re-run `node scripts/tenant-audit-census.mjs --write` (exit 0), which counts 266 plus this PR's one switch-revocation write = 267. Then move the page's hand-written prose counts to match: 266 to 267 write sites, 189 to 190 decidable, 148 to 149 decidably elevated (still 56%), and the 2/266 citation to 2/267. check-tenant-audit-census and its --self-test exit 0. Every other file merged clean. That includes the plugin-auth files main also changed (auth-manager.ts, auth-plugin.ts, auth-route-ledger, and the MCP/SCIM/authorized-clients modules), plus the five *.objects.generated.ts bundles; this PR's retired-require_mfa copy survives in each. A grep of the merged tree finds no remaining use of the retired `mfaRequired` option outside the refusal and its test. No PR code change in this round.", "tests": "At merged head a06983b5c0, under the verify lock (chain build 0, typecheck plugin-auth/service-settings/platform-objects/cli all 0). plugin-auth `pnpm --filter @objectstack/plugin-auth test`: Test Files 234 passed (234), Tests 4163 passed | 10 skipped. service-settings test: Test Files 71 passed, Tests 1369 passed. platform-objects test: Test Files 117 passed, Tests 1637 passed. cli `pnpm --filter @objectstack/cli test`, both layers: Test Files 601 passed | 1 skipped, Tests 7419 passed | 9 skipped. Verify held-session pins: 3 files, 49 passed. No ablations this round: no behaviour changed.", "gates": "`node scripts/pm/dispatch-gates.mjs --commands` at a06983b5c0 derived 108 families. All were run; `--ran` reconciliation: 108 derived, 108 run, 0 UNRUN. check:app-nav-i18n exit 0. Exit codes captured before any pipe: 105 exit 0. NOT MEASURED, all exit 3 on missing prerequisites: check:dual-build-cjs-loads (a package without dist/), check:type-check-debt (its closure build could not take the verify lock), @objectstack/spec check:skill-examples. Tenant-audit census re-written because main moved it (see summary): check exit 0, --self-test exit 0. GitHub mergeable_state for the new head read `unknown` right after the push (still computing); the branch is 4 commits behind origin/main at report time, with no conflict reported. CI on the new head not awaited.", "dogfood_battery": "n/a this round — a merge-only head with no PR code change; the battery last passed at b0b494c04a (Test Files 428 passed | 3 skipped, Tests 3561 passed | 41 skipped). The merge brings 43 main commits, so the seat may require a re-run on a06983b5c0.", "mcp_calls": "0", "api_writes": "1 this round — the os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/30922/comments). Plus one git push (not REST), which was accepted, with no permission-classifier refusal.", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }