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
spec: declare the console flag features.cloudManaged — a PUBLIC_AUTH_FEATURES entry with a hide-when-on gate semantics, and AuthFeaturesConfigSchema declares it (child of #25083, ruling 6341690661 Q3 A) #25292
Filed by domain:spec seat 2 (seat post #18549), os-bill, session session_01B2EeooonSXrANpkpgUSfFZ, on the cross-lane hand-off 6349666746 from domain:services seat 1 (card #25083, claim 6349623693). ⛔ Not a claim.
Parent: #25083 (p1, domain:services). Ruling: 6341690661 on #25083, Q3 → A, the maintainer's 「其他同意」. This is the ruling's one spec widening (Metadata-protocol: added).
What the ruling binds in this lane
The console flag is camelCase like every sibling (twoFactor, ssoEnforced, audiencePosture); PUBLIC_AUTH_FEATURES gains a hide-when-on gate semantics (features.X != true) and the platform-objects forward guard learns it; AuthFeaturesConfigSchema declares it.
packages/spec/src/kernel/public-auth-features.ts: the cloudManaged entry with its gatedInputs, and a third semantics beside opt-in and default-on in featureGatePredicate (hide when on: features.X != true). The gated inputs are the platform-objects actions the ruling names for the engine half (invite_user ×4, create_user, set_user_password); read the engine hand-off on [PM seat] domain:server · seat 2 — 🟢 sunhaolin #20966 for the exact list.
domain:engine: the forward guard learning the new semantics lives in packages/platform-objects/src/feature-gate-guard.test.ts.
Acceptance
cloudManaged is in PUBLIC_AUTH_FEATURES / PUBLIC_AUTH_FEATURE_NAMES with its gated inputs and the hide-when-on semantics; featureGatePredicate returns features.cloudManaged != true for it.
Claim: PM loop round 13
Session: session_01P9sxzbFDWjQD3FdsL3mN4u (the card thread; seat session session_01B2EeooonSXrANpkpgUSfFZ posts this claim)
Account: os-bill
Branch: claude/project-thread-4kg5av (the card thread's designated push branch; claude/issue-N-slug is the convention, and this is the measured platform exception the pm-dispatch runbook records)
Worktree: objectstack-issue-25292
Domain: domain:spec
Seat: domain:spec#2 (seat post #18549)
Ruling-ref: 6341690661
File surface: packages/spec/src/kernel/public-auth-features.ts (the cloudManaged entry and the hide-when-on semantics in featureGatePredicate), packages/spec/src/api/auth-endpoints.zod.ts (AuthFeaturesConfigSchema), any spec-side reader of PublicAuthFeatureSemantics that must learn the third arm, their regenerated references, tests and one changeset (stop on breach; explain in the report). ⛔ Not plugin-auth (services) and not platform-objects (engine).
Container & model: M, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate), effort: xhigh (p1); a published-schema change owes one CONTRACT_REVIEW_TIER review of record before the queue
Clause-②: yes (widening, per the ruling; the dev measures it from the diff)
Responsibility: n/a — not a defect; the spec child of #25083 under ruling 6341690661 Q3 A
Thread-read: none
Serial constraints cleared: none. No open PR touches public-auth-features.ts or auth-endpoints.zod.ts (open-PR file scan).
Ruling: needs_decision fork review (project review thread 「cloudManaged 落地顺序裁决」) · letter A · maintainer 「对于这种类似的问题,能否你自己开一个单独的 fable thread 做评审,对于自己有把握决定的问题,自己决定,不能决定的开决策卡?」 2026-10-22T22:11Z
Proxy ruling under the maintainer's delegation quoted above, by the review thread's session session_01NWFx9wugzhXAeiumRNN226 (project thread), on the needs_decision fork the card thread (session_01P9sxzbFDWjQD3FdsL3mN4u, branch claude/project-thread-4kg5av, head 8ff4f744) reported to domain:spec seat 2: the landing order of the features.cloudManaged entry. Marker: auto-adjudicated. ⚠️ Reversible on one word from the maintainer; the maintainer is shown this ruling in the review thread for 追认, and nothing here forecloses another letter.
What the review thread re-verified (code read at fb7501bc, the branch's base, and at the branch head 8ff4f744)
The spec half is built. The branch carries PublicAuthFeatureSemantics + 'hide-when-on'; featureGatePredicate as a total map over the three semantics (a fourth arm fails to compile); the PUBLIC_AUTH_FEATURES.cloudManaged entry (surface: 'crud', six gatedInputs: invite_user on sys_user / sys_member / sys_invitation / sys_organization, sys_user.actions.create_user, sys_user.actions.set_user_password); AuthFeaturesConfigSchema.cloudManaged: z.boolean().optional(); the regenerated references; a minor changeset declaring Clause-②: yes (widening) / Metadata-protocol: added. That is exactly what ruling 6341690661 Q3 → A binds for this lane.
The lock is three-way and mechanical, not a convention. Three pins hold the registry, the platform objects and the served payload equal, and each runs in Test Core (required):
packages/platform-objects/src/feature-gate-guard.test.ts, forward: every gatedInputs path must carry the flag's gate in its lowered visible → the spec entry alone reds six rows.
the same file, reverse: every features.<name> inside a visible predicate must name a registry flag → the six predicates alone red.
packages/plugins/plugin-auth/src/public-feature-registry.test.ts: the boolean keys getPublicConfig() serves must equal PUBLIC_AUTH_FEATURE_NAMES, and a flag that is not default-on must serve false by default → the spec entry alone reds two cases; the served line alone reds the key-set case.
So the spec entry, the six visible predicates and the one served line are one commit on main, or none of them is. The card thread measured 6 + 2 reds with the spec half alone (dependency closure built, suites run); the review thread re-read the three pins and the lowering and confirms the reading.
The forward guard cannot accept a second gate as written.lowerRequiresFeature composes (<existing visible>) && <gate>, and requiresFeature names ONE flag (z.enum(PUBLIC_AUTH_FEATURE_NAMES)). The six inputs already carry one flag each (organization ×4, admin ×2), so the cloudManaged gate has to be written inside visible and lowers to (… && features.cloudManaged != true) && features.<other> == true; the guard's test visibleSource === gate || endsWith('&& ' + gate) then reds the cloudManaged row of every such input. The guard must learn to find a gate as an &&-conjunct.
.claude/skills/pm-dispatch/SKILL.md § 域车道: 「跨域例外路径:拆不动的跨域单 PR 由分诊席指定一个车道 PM 认领,认领评论申报文件面」 and 「跨域相交只经三条越界通道:跨域例外路径、认领席跟到底的越界面、接手无主阻塞项」. This is the recorded mechanism for an unsplittable cross-domain PR.
The decision frame's base rule (same file): 「声明即强制,绝不让 AI 声明一个运行时不兑现的能力」; 「过渡也从紧 —— 创业阶段不渐进」; 「新增门禁默认否:门禁是只减不增的零件,例外只有维护者点名」.
AGENTS.md, Multi-agent working discipline §2: one feature branch + one PR per task; a multi-card change uses a trunk branch, ⛔ no stacked series. Prime Directive [WIP] Fix error in step four of the action run #5: no workarounds.
The guard's new matcher. The forward guard accepts a lowered predicate for (path, flag) iff featureGatePredicate(flag) is one &&-conjunct of it, with parentheses that only group conjuncts transparent; a gate under ||, ! or ?: is not a gate; ⛔ no substring includes. The two shapes accepted today (gate alone; the final && gate) keep passing byte-identically. Pinned in the same file with the shapes gate, (a) && gate, (a && gate) && b, and the refused a || gate.
The six predicates.requiresFeature stays single-flag (a list form would be a second spec widening the ruling did not name); each of the six keeps its existing requiresFeature and gains features.cloudManaged != true written inside its visible source (the spelling featureGatePredicate('cloudManaged') returns; no other change to the predicate). Pinned as platform-objects: hide invite_user ×4, create_user and set_user_password when features.cloudManaged is on (visible predicates, hide-when-on) #25295's Acceptance reads: with features.cloudManaged true each of the six is hidden; false or absent, each is visible as today. set_user_password is hidden in the console only — ⛔ no server-side refusal here (ruling Q4 → A; the doors are the services half's).
Declarations. PR body: Clause-②: yes (widening), Metadata-protocol: added (the spec entry governs; several ⇒ added over none). One changeset per package the diff moves: @objectstack/specminor (already written), @objectstack/platform-objects and @objectstack/plugin-auth at the level the dev measures (expected patch, Metadata-protocol: none each). A measured (narrowing) anywhere ⇒ stop and report; none is expected.
⛔ Not: B — landing 'hide-when-on' and the schema key first without the entry (a declared key the server does not serve and a semantics with zero flags, 「声明而未兑现」 by construction; the joint PR still follows, so spec is reviewed twice); C — a guard exemption or a gatedInputs: [] interim entry (a new transitional gate shape with no maintainer naming it; a registry that would say "registered, enforced later"); a stacked PR off core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294's branch; moving the served line into a services-owned PR (it cannot be green on its own either).
Why A, on the four axes (business standpoint)
① Long-term soundness (weight ≥50%).main stays green at every commit and the registry keeps its one meaning: a registered flag is served and enforced. B leaves a window in which /auth/config's schema promises a key the server never sends; C adds a door the next flag will walk through too.
② Measured business pull. cloud's production containers already set OS_CLOUD_MANAGED=1 (cloud#3133); the console's Setup → Users copy, the invite and password doors and RecoveryPasswordReminder all read this one flag. Nothing reads it until all three halves exist, so a partial landing serves nobody earlier.
③ AI-error prevention. The three pins are exactly what stops a generator from registering a flag it does not serve, or gating an input on a flag that does not exist. A keeps them strict and teaches the forward guard the two-gate shape instead of relaxing it.
Only-① pick: A. Do ②③④ flip it: no. Effort for the chosen letter: S–M on top of the branch (six predicate edits, one matcher with pins, one line), one PR, domain:spec seat 2 with the engine seat's read; precedent for the shape: #25294's one-line cross-lane amendment.
Confidence gate as applied
Mechanical boundary: the ruling adds no contract beyond what 6341690661 Q3 → A already binds; it fixes the landing mechanics for a trio the pins hold together, and the recorded 跨域例外路径 is the channel for that.
① Four facets one way: above. ② Floors: no security or permission boundary moves (console visibility only; the server-side doors stay the services half's); no published contract semantics change beyond the ruled widening; no gate is weakened — one gate is taught a shape. ③ No maintainer ruling is overturned: Q3 → A stands verbatim; the order inside the trio was delegated to the seat. The one judgement call — one served line crossing into domain:services, the maintainer's other account's lane, claimed by 6349623693 — follows the core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294 precedent and is presented to the maintainer for 追认.
Failure direction stays loud: any missing half is a required-check red; one revert.
① 长远:三半同一 commit 落 main,注册表「登记即服务即强制」的意思不变,main 每个提交都绿;B 留下 schema 声明了但服务端不发的窗口,C 给注册表开「登记了先不查」的口子。
② 拉动:cloud 生产容器已带 OS_CLOUD_MANAGED=1,Setup → Users 文案、邀请/密码入口、密码提醒都读这一个旗;三半不齐谁也读不到,分开落不会让任何人更早用上。
③ 防错:三条钉子正是拦住 AI「登记了不服务」「门禁挂在不存在的旗上」的守卫;A 保持它们严格,只教前向守卫认双旗合取,不放宽。
④ 不扩散:零新门禁、零新键、零过渡态;#25295 本来就要的那个 PR 加一行,工作量 S–M。
Prior rulings read: #250836341690661(Q2 D / Q3 A / Q4 A,执行段「Blocked-by: lines as the seat sees the order」)、指针 6311773273 / 6311801640(已被 Q2 D 部分取代);#25294 认领 6351990387 与修订 6352016263(单行跨车道先例);#25083 services 认领 6349623693;#7481(PUBLIC_AUTH_FEATURES_NOT_ADVERTISED 的来历);#2874 P0/P2(三条钉子);pm-dispatch § 域车道「跨域例外路径」;AGENTS.md 多代理纪律 §2;thread: 卡线程的分叉分析(项目文件 card-25292/fork-analysis.md)。
Claim amendment · domain:spec seat 2 · session session_01B2EeooonSXrANpkpgUSfFZ · 2026-10-22T22:17Z · ⛔ not a new claim (round 13 stands: 6351958701)
Ruling-ref: 6352436010
Thread-read: 6352436010
Branch: claude/project-thread-4kg5av (unchanged; the trunk of the ruling's one PR)
File surface, widened per ruling 6352436010 items 1 and 7 (the 跨域例外路径):
the spec half as claimed (packages/spec/src/kernel/public-auth-features.ts, packages/spec/src/api/auth-endpoints.zod.ts, their references, tests, one @objectstack/spec changeset);
Ruling supplement · to 6352436010 (letter A unchanged) · item 7 · 2026-10-22T23:02Z
Review thread, same session (session_01NWFx9wugzhXAeiumRNN226). The domain:spec seat reports that The card this PR closes must claim this branch (check:closing-target-claim, run 39868749352) reds on the joint PR #25309 (head d30caab4): the PR carries Fixes #25295, and #25295 holds only the engine seat's ⛔-not-a-claim pointer 6352506874. The gate's rule is the one items 1 and 7 did not reconcile: a pull request may close a card only while that card's own thread carries a Claim: whose Branch: line names the PR's head branch; a Part of target is never read; the assignee field is no identity record (scripts/check-closing-target-claim.mjs).
Supplement, consistent with the 跨域例外路径 the ruling rests on (「拆不动的跨域单 PR 由分诊席指定一个车道 PM 认领,认领评论申报文件面」):
Not taken: (b) Part of #25295 with a hand close after merge — it severs the closing record from the merge and leaves the card's state to a manual act the ruling set out to avoid.
{
"issue": 25292,
"status": "done",
"branch": "claude/project-thread-4kg5av",
"pr": "https://github.com/objectstack-ai/objectstack/pull/25309",
"session": "session_01P9sxzbFDWjQD3FdsL3mN4u",
"premise_still_valid": true,
"summary": "One joint PR under ruling 6352436010 (letter A): spec declares features.cloudManaged (new 'hide-when-on' semantics lowering to `features.X != true`, the PUBLIC_AUTH_FEATURES entry with six gated inputs, AuthFeaturesConfigSchema.cloudManaged); platform-objects carries #25295 in full (six `visible` predicates plus the forward guard's depth-0 && conjunct matcher with pins); plugin-auth serves `cloudManaged: isCloudManaged()` after #25294 landed (main merged in, no rebase). Head 72cea5b1, draft, CI all green. The PR body still carries the pre-#25294 text (Blocked-by, the two-red window, d30caab4 verification); per the dev's write-once rule it is not patched here, and a full replacement body is ready for the seat to write (see open_questions).",
"tests": "72cea5b1: plugin-auth `vitest run src/auth-manager.test.ts src/public-feature-registry.test.ts` Test Files 2 passed, Tests 302 passed; plugin-auth typecheck 0; platform-objects `vitest run` Test Files 88 passed, Tests 1318 passed; platform-objects typecheck 0 (lock VERDICT command-exit 0). 91d3cd6b: plugin-auth full `vitest run` Test Files 1 failed | 186 passed: `getPublicConfig > should return safe public configuration` exact-match lacked `cloudManaged: false`, fixed in 72cea5b1 together with a new case that sets OS_CLOUD_MANAGED=1 and reads true. spec `check:generated`: all 14 generated artifacts up to date after rebuilding spec on the merged tree. Ablation of the served line (on-disk `cloudManaged: isCloudManaged()` -> `cloudManaged: false`): `serves features.cloudManaged from OS_CLOUD_MANAGED` 1 failed; restored from copy, git diff empty. Guard ablations (earlier, d30caab4, unchanged files): deleting the gate on sys_member.invite_user -> 1 failed / 100 passed; `true || gate` -> 1 failed / 101 passed; both restored to the HEAD blob. Spec suite (d30caab4): 783 files, 22794 passed, 1 todo.",
"gates": "local subset on 72cea5b1: `dispatch-gates --commands` derives 117; 116 exit 0; 1 exit 3 PREREQUISITE NOT MET = NOT MEASURED: `node scripts/check-plugin-teardown-shape.mjs --self-test` (shallow clone cannot read pinned fixture 621a4876; the non-self-test `check-plugin-teardown-shape` exit 0). `--ran` reconciliation: 117 derived, 116 run, 1 NOT-MEASURED, 0 UNRUN. CI on 72cea5b1 (check-runs): 36 success, 6 skipped, 0 failure; incl. Test Core (1/6..6/6) success, Build Core success, Build Docs success, Type Check · workspace/source gates/consumer gates/debt ledger success, Lint · ESLint / repo & tooling gates / docs & code guards / CI, release & engine gates / PM dispatch-gates success, Check Changeset success, The card this PR closes must claim this branch success, No other open PR may claim the same issue success, Part-of PR must not also close its card success, Spec property liveness success, Governed Surface Queue Guard success.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "5 — mcp__github__get_job_logs x4, mcp__github__pull_request_read x1 (get_check_runs); all read-only",
"api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, #25309, draft, assignee os-bill) via scripts/pm/fleet-write/dispatch.mjs; this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/25292/comments) via scripts/pm/post-stamped.mjs. Plus git pushes to claude/project-thread-4kg5av (840a8ad0 merge of main, 91d3cd6b, 72cea5b1).",
"open_questions": [
{
"question": "The PR body must drop `Blocked-by: #25294` and the 'Services line: not in yet' two-red window, and its Verification section is for d30caab4. The dev does not PATCH the body; who writes the replacement?",
"options": ["A the seat writes the prepared replacement body verbatim (same declarations, Fixes/Part-of lines unchanged; Services section, Verification at 72cea5b1, the narrowing acceptance note and the changeset line updated)", "B the seat edits only the two named spans"],
"recommendation": "A, because the Verification and Acceptance-notes sections are also stale and the prepared body changes nothing else"
}
],
"out_of_scope_findings": [
"carrier: PR #25309 ## Acceptance notes · the spec comments say an absent default-on flag 'fails open', but @objectstack/formula's celEngine faults with `No such key` on any absent flag, default-on included, so a payload omitting a flag falls to the consumer's fault handling · noted, not filed",
"carrier: PR #25309 · docs-drift check named content/docs/permissions/sso.mdx (via getPublicConfig); read: it gives an abbreviated example ('additional features keys such as …') and no page enumerates every features key, so no doc change · noted, not filed"
]
}
Ruling confirmed: 6352436010 letter A · maintainer 「#25292 追认 A」 · 2026-10-23T02:08Z
The maintainer ratified the proxy ruling 6352436010 (with its supplement 6353227863) in the project's decision batch (item 2 of 6), at 2026-10-23T02:05Z. Recorded by domain:spec seat 2 (seat post #18549), os-bill, session session_01B2EeooonSXrANpkpgUSfFZ. PR #25309, which closes this card and #25295, now leaves draft and lands under it.
Seat check 6355692640 on head 72cea5b1ef, under ruling 6352436010 (ratified, 6355684586 on #25292), contract review PASS 6355339198 and the engine seat's PASS 6353213686. The PR closes #25292 and #25295; it leaves draft and joins the merge queue now, and the landing record follows here.
Activity
objectstack-fleet commentedon Oct 22, 2026
Claim: PM loop round 13
Session:
session_01P9sxzbFDWjQD3FdsL3mN4u(the card thread; seat sessionsession_01B2EeooonSXrANpkpgUSfFZposts this claim)Account:
os-billBranch:
claude/project-thread-4kg5av(the card thread's designated push branch;claude/issue-N-slugis the convention, and this is the measured platform exception the pm-dispatch runbook records)Worktree:
objectstack-issue-25292Domain:
domain:specSeat:
domain:spec#2(seat post #18549)Ruling-ref: 6341690661
File surface:
packages/spec/src/kernel/public-auth-features.ts(thecloudManagedentry and the hide-when-on semantics infeatureGatePredicate),packages/spec/src/api/auth-endpoints.zod.ts(AuthFeaturesConfigSchema), any spec-side reader ofPublicAuthFeatureSemanticsthat must learn the third arm, their regenerated references, tests and one changeset (stop on breach; explain in the report). ⛔ Not plugin-auth (services) and notplatform-objects(engine).Container & model:
M,mode:thread,model: default(dispatch-gates --tier: no path-derived mandate),effort: xhigh(p1); a published-schema change owes oneCONTRACT_REVIEW_TIERreview of record before the queueClause-②: yes (widening, per the ruling; the dev measures it from the diff)
Responsibility: n/a — not a defect; the spec child of #25083 under ruling
6341690661Q3 AThread-read: none
Serial constraints cleared: none. No open PR touches
public-auth-features.tsorauth-endpoints.zod.ts(open-PR file scan).Generated by Claude Code
objectstack-fleet commentedon Oct 22, 2026
Ruling: needs_decision fork review (project review thread 「cloudManaged 落地顺序裁决」) · letter A · maintainer 「对于这种类似的问题,能否你自己开一个单独的 fable thread 做评审,对于自己有把握决定的问题,自己决定,不能决定的开决策卡?」 2026-10-22T22:11Z
Proxy ruling under the maintainer's delegation quoted above, by the review thread's session⚠️ Reversible on one word from the maintainer; the maintainer is shown this ruling in the review thread for 追认, and nothing here forecloses another letter.
session_01NWFx9wugzhXAeiumRNN226(project thread), on theneeds_decisionfork the card thread (session_01P9sxzbFDWjQD3FdsL3mN4u, branchclaude/project-thread-4kg5av, head8ff4f744) reported todomain:specseat 2: the landing order of thefeatures.cloudManagedentry. Marker:auto-adjudicated.What the review thread re-verified (code read at
fb7501bc, the branch's base, and at the branch head8ff4f744)PublicAuthFeatureSemantics+'hide-when-on';featureGatePredicateas a total map over the three semantics (a fourth arm fails to compile); thePUBLIC_AUTH_FEATURES.cloudManagedentry (surface: 'crud', sixgatedInputs:invite_useronsys_user/sys_member/sys_invitation/sys_organization,sys_user.actions.create_user,sys_user.actions.set_user_password);AuthFeaturesConfigSchema.cloudManaged: z.boolean().optional(); the regenerated references; aminorchangeset declaringClause-②: yes (widening)/Metadata-protocol: added. That is exactly what ruling6341690661Q3 → A binds for this lane.packages/platform-objects/src/feature-gate-guard.test.ts, forward: everygatedInputspath must carry the flag's gate in its loweredvisible→ the spec entry alone reds six rows.features.<name>inside avisiblepredicate must name a registry flag → the six predicates alone red.packages/plugins/plugin-auth/src/public-feature-registry.test.ts: the boolean keysgetPublicConfig()serves must equalPUBLIC_AUTH_FEATURE_NAMES, and a flag that is notdefault-onmust servefalseby default → the spec entry alone reds two cases; the served line alone reds the key-set case.So the spec entry, the six
visiblepredicates and the one served line are one commit onmain, or none of them is. The card thread measured 6 + 2 reds with the spec half alone (dependency closure built, suites run); the review thread re-read the three pins and the lowering and confirms the reading.lowerRequiresFeaturecomposes(<existing visible>) && <gate>, andrequiresFeaturenames ONE flag (z.enum(PUBLIC_AUTH_FEATURE_NAMES)). The six inputs already carry one flag each (organization×4,admin×2), so thecloudManagedgate has to be written insidevisibleand lowers to(… && features.cloudManaged != true) && features.<other> == true; the guard's testvisibleSource === gate || endsWith('&& ' + gate)then reds thecloudManagedrow of every such input. The guard must learn to find a gate as an&&-conjunct.PUBLIC_AUTH_FEATURES_NOT_ADVERTISEDis not one. That list names flags that are NOT in the registry and must not be served (public-auth-features: passkeys/magicLink exempt.reason points at objectui#2514, which closes as "documented reserved" — decide stop-advertising vs keep-as-reserved #7481 withdrew them); it exempts nothing that is registered. An entry withgatedInputs: []+exempt.reasonwould be a second transitional shape (registered, served, enforced nowhere).isCloudManaged(), engine; claim6351990387, amendment6352016263; branchclaude/project-thread-dhsqgf; no PR yet) is the only dependency the served line has. platform-objects: hide invite_user ×4, create_user and set_user_password when features.cloudManaged is on (visible predicates, hide-when-on) #25295 (the six predicates, engine) ispm:blocked, unclaimed. plugin-auth, setup users: a managed (SSO-only) hosted environment keeps only authorization + view in Setup → Users, turns its local sign-up off, and gives a JIT user the declared default permission set (cloud#3132 ruling A) #25083's services claim6349623693(os-sales, branchclaude/project-thread-i0vfmz, no PR) names 「getPublicConfig()servesfeatures.cloudManaged」 in its surface and says the services half waits for the spec entry and the accessor — the circle this ruling cuts. PR refactor(plugin-auth): move AuthManager's actor and organization guards into auth-manager-actor-guards.ts (#25224 cut 1) #25273 (theauth-manager.tsguard extraction) is already merged, so no open PR touches the served line's region at this reading.Governing text
6341690661on plugin-auth, setup users: a managed (SSO-only) hosted environment keeps only authorization + view in Setup → Users, turns its local sign-up off, and gives a JIT user the declared default permission set (cloud#3132 ruling A) #25083, Q3 → A, binds spec and guard in one sentence: 「PUBLIC_AUTH_FEATURESgains a hide-when-on gate semantics (features.X != true) and the platform-objects forward guard learns it;AuthFeaturesConfigSchemadeclares it」; its execution delegates the order: 「Blocked-by:lines as the seat sees the order (the core accessor first)」. The measurement shows that inside the trio there is no order to see; only "the core accessor first" survives..claude/skills/pm-dispatch/SKILL.md§ 域车道: 「跨域例外路径:拆不动的跨域单 PR 由分诊席指定一个车道 PM 认领,认领评论申报文件面」 and 「跨域相交只经三条越界通道:跨域例外路径、认领席跟到底的越界面、接手无主阻塞项」. This is the recorded mechanism for an unsplittable cross-domain PR.6352016263(one line incloud-connection,domain:cli, declared on the card, seat-ruled).The ruling: A — the three halves land in one PR on the spec card's branch, once #25294 is on
mainFixed here, so no second decision opens:
claude/project-thread-4kg5avis the trunk. On top of the spec half it gains (i) the engine half of platform-objects: hide invite_user ×4, create_user and set_user_password when features.cloudManaged is on (visible predicates, hide-when-on) #25295 in full — the sixvisiblepredicates and the forward guard's conjunct matching, inpackages/platform-objects; (ii) exactly one services line —cloudManaged: isCloudManaged()in thefeaturesliteral ofgetPublicConfig()(packages/plugins/plugin-auth/src/auth-manager.ts) with its import from@objectstack/core. Nothing else of plugin-auth, setup users: a managed (SSO-only) hosted environment keeps only authorization + view in Setup → Users, turns its local sign-up off, and gives a JIT user the declared default permission set (cloud#3132 ruling A) #25083's services half moves here. The PR carriesFixes #25292,Fixes #25295,Part of #25083— ⛔ neverFixes #25083.isCloudManaged()from core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294: it is added once core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294 has merged andmainhas been merged into the trunk — ⛔ not by branching off core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294's branch (no stacked series). The draft PR may open as soon as the spec and engine halves are complete; until the served line is in, its body names the known two-red window inpublic-feature-registry.test.tsand carries a line-initialBlocked-by: #25294. ACCEPT and the queue wait for green.(path, flag)ifffeatureGatePredicate(flag)is one&&-conjunct of it, with parentheses that only group conjuncts transparent; a gate under||,!or?:is not a gate; ⛔ no substringincludes. The two shapes accepted today (gatealone; the final&& gate) keep passing byte-identically. Pinned in the same file with the shapesgate,(a) && gate,(a && gate) && b, and the refuseda || gate.requiresFeaturestays single-flag (a list form would be a second spec widening the ruling did not name); each of the six keeps its existingrequiresFeatureand gainsfeatures.cloudManaged != truewritten inside itsvisiblesource (the spellingfeatureGatePredicate('cloudManaged')returns; no other change to the predicate). Pinned as platform-objects: hide invite_user ×4, create_user and set_user_password when features.cloudManaged is on (visible predicates, hide-when-on) #25295's Acceptance reads: withfeatures.cloudManagedtrue each of the six is hidden; false or absent, each is visible as today.set_user_passwordis hidden in the console only — ⛔ no server-side refusal here (ruling Q4 → A; the doors are the services half's).public-feature-registry.test.tskey-set equality and the default (falseunder vitest, whereOS_CLOUD_MANAGEDis unset). The "true when managed" pins belong to the services half (6349623693), using core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294'sresetCloudManagedForTesting().Clause-②: yes (widening),Metadata-protocol: added(the spec entry governs; several ⇒addedovernone). One changeset per package the diff moves:@objectstack/specminor(already written),@objectstack/platform-objectsand@objectstack/plugin-authat the level the dev measures (expectedpatch,Metadata-protocol: noneeach). A measured(narrowing)anywhere ⇒ stop and report; none is expected.packages/platform-objects/src/identity/{sys-user,sys-member,sys-invitation,sys-organization}.object.ts,packages/platform-objects/src/feature-gate-guard.test.ts, the oneauth-manager.tsline and its import — citing this comment asRuling-ref, after re-checking open PRs on those files. Two declarations, ⛔ not claims: on platform-objects: hide invite_user ×4, create_user and set_user_password when features.cloudManaged is on (visible predicates, hide-when-on) #25295 (engine lane) that the card is built in spec: declare the console flag features.cloudManaged — a PUBLIC_AUTH_FEATURES entry with a hide-when-on gate semantics, and AuthFeaturesConfigSchema declares it (child of #25083, ruling 6341690661 Q3 A) #25292's PR, which carriesFixes #25295; on plugin-auth, setup users: a managed (SSO-only) hosted environment keeps only authorization + view in Setup → Users, turns its local sign-up off, and gives a JIT user the declared default permission set (cloud#3132 ruling A) #25083 (services lane,domain:servicesseat 1's claim) that the one served line lands in spec: declare the console flag features.cloudManaged — a PUBLIC_AUTH_FEATURES entry with a hide-when-on gate semantics, and AuthFeaturesConfigSchema declares it (child of #25083, ruling 6341690661 Q3 A) #25292's PR and the services branch drops its own copy when it mergesmain— everything else in6349623693stands. The engine seat recordsBlocked-by: #25294on platform-objects: hide invite_user ×4, create_user and set_user_password when features.cloudManaged is on (visible predicates, hide-when-on) #25295 and keeps itpm:blocked.CONTRACT_REVIEW_TIERreview of record before the queue (published-schema face), run by thedomain:specseat, effortxhigh(p1). Thedomain:engineseat reads theplatform-objectshunks and the guard change and posts one PASS/FAIL line on the PR before the spec seat's ACCEPT. The PR stays draft until core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294 is onmainAND the maintainer's 追认 has reached the review thread or this card.'hide-when-on'and the schema key first without the entry (a declared key the server does not serve and a semantics with zero flags, 「声明而未兑现」 by construction; the joint PR still follows, so spec is reviewed twice); C — a guard exemption or agatedInputs: []interim entry (a new transitional gate shape with no maintainer naming it; a registry that would say "registered, enforced later"); a stacked PR off core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294's branch; moving the served line into a services-owned PR (it cannot be green on its own either).Why A, on the four axes (business standpoint)
mainstays green at every commit and the registry keeps its one meaning: a registered flag is served and enforced. B leaves a window in which/auth/config's schema promises a key the server never sends; C adds a door the next flag will walk through too.OS_CLOUD_MANAGED=1(cloud#3133); the console's Setup → Users copy, the invite and password doors andRecoveryPasswordReminderall read this one flag. Nothing reads it until all three halves exist, so a partial landing serves nobody earlier.Only-① pick: A. Do ②③④ flip it: no. Effort for the chosen letter: S–M on top of the branch (six predicate edits, one matcher with pins, one line), one PR,
domain:specseat 2 with the engine seat's read; precedent for the shape: #25294's one-line cross-lane amendment.Confidence gate as applied
6341690661Q3 → A already binds; it fixes the landing mechanics for a trio the pins hold together, and the recorded 跨域例外路径 is the channel for that.domain:services, the maintainer's other account's lane, claimed by6349623693— follows the core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294 precedent and is presented to the maintainer for 追认.① 长远:三半同一 commit 落 main,注册表「登记即服务即强制」的意思不变,main 每个提交都绿;B 留下 schema 声明了但服务端不发的窗口,C 给注册表开「登记了先不查」的口子。
② 拉动:cloud 生产容器已带
OS_CLOUD_MANAGED=1,Setup → Users 文案、邀请/密码入口、密码提醒都读这一个旗;三半不齐谁也读不到,分开落不会让任何人更早用上。③ 防错:三条钉子正是拦住 AI「登记了不服务」「门禁挂在不存在的旗上」的守卫;A 保持它们严格,只教前向守卫认双旗合取,不放宽。
④ 不扩散:零新门禁、零新键、零过渡态;#25295 本来就要的那个 PR 加一行,工作量 S–M。
Prior rulings read: #25083
6341690661(Q2 D / Q3 A / Q4 A,执行段「Blocked-by: lines as the seat sees the order」)、指针6311773273/6311801640(已被 Q2 D 部分取代);#25294 认领6351990387与修订6352016263(单行跨车道先例);#25083 services 认领6349623693;#7481(PUBLIC_AUTH_FEATURES_NOT_ADVERTISED的来历);#2874 P0/P2(三条钉子);pm-dispatch § 域车道「跨域例外路径」;AGENTS.md 多代理纪律 §2;thread: 卡线程的分叉分析(项目文件card-25292/fork-analysis.md)。Execution after the ruling
needs-user-decision→pm:queue(one replace). ⛔ Ruling is not dispatching: thedomain:specseat resumes the SAME card thread and branch (no fresh dispatch), posts the claim amendment withRuling-ref: <this comment id>and the widened surface, moves the card topm:dispatched, and writesBlocked-by: #25294line-initial in the body for the landing (pm:blockedif the build finishes before core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294 lands).Blocked-by: #25294; core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294 proceeds unchanged and is told thatisCloudManagedandresetCloudManagedForTestingare consumed by this trunk the moment it merges.decisions/25292-ruling.md; ledger row incoordinator/rulings.md.Generated by Claude Code
objectstack-fleet commentedon Oct 22, 2026
Claim amendment ·
domain:specseat 2 · sessionsession_01B2EeooonSXrANpkpgUSfFZ· 2026-10-22T22:17Z · ⛔ not a new claim (round 13 stands:6351958701)Ruling-ref: 6352436010
Thread-read: 6352436010
Branch:
claude/project-thread-4kg5av(unchanged; the trunk of the ruling's one PR)File surface, widened per ruling
6352436010items 1 and 7 (the 跨域例外路径):packages/spec/src/kernel/public-auth-features.ts,packages/spec/src/api/auth-endpoints.zod.ts, their references, tests, one@objectstack/specchangeset);packages/platform-objects/src/identity/{sys-user,sys-member,sys-invitation,sys-organization}.object.ts(the sixvisiblepredicates) andpackages/platform-objects/src/feature-gate-guard.test.ts(the forward guard's&&-conjunct matcher and its pins), one@objectstack/platform-objectschangeset;cloudManaged: isCloudManaged()ingetPublicConfig()'sfeaturesliteral inpackages/plugins/plugin-auth/src/auth-manager.ts, with its import from@objectstack/core, one@objectstack/plugin-authchangeset. Added only after core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294 is onmainandmainis merged into this branch (no stacking).Stop on breach; explain in the report.
PR keywords:
Fixes #25292,Fixes #25295,Part of #25083(⛔ neverFixes #25083).Clause-②: yes (widening),
Metadata-protocol: added(unchanged; a measured narrowing anywhere stops the build).Serial constraints cleared: core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294 (
isCloudManaged(), engine) lands first —Blocked-by: #25294in the card body. Open-PR file scan on the widened surface: only draft PR feat(plugin-auth): a JIT sign-in reads the IdP locale claim into the user language preference #25303 (claude/project-thread-6usz2l, IdP locale claim) touchesauth-manager.ts, in the import block andvalidateUserInfo(~line 1886), not ingetPublicConfig()(~line 7809). Whichever lands second mergesmain; the import block is the only possible textual overlap. PR refactor(plugin-auth): move AuthManager's actor and organization guards into auth-manager-actor-guards.ts (#25224 cut 1) #25273 is merged. No open PR touches the platform-objects files.Review:
CONTRACT_REVIEW_TIER(published-schema face),xhigh, by this seat; thedomain:engineseat posts one PASS/FAIL line on the platform-objects hunks before ACCEPT. The PR stays draft until core: isCloudManaged() — one accessor for OS_CLOUD_MANAGED=1 beside isHostKernelComposition, with the production fuse (no bound control plane ⇒ refuse to start) #25294 is onmainand the maintainer's 追认 of6352436010arrives.Generated by Claude Code
objectstack-fleet commentedon Oct 22, 2026
Ruling supplement · to
6352436010(letter A unchanged) · item 7 · 2026-10-22T23:02ZReview thread, same session (
session_01NWFx9wugzhXAeiumRNN226). Thedomain:specseat reports thatThe card this PR closes must claim this branch(check:closing-target-claim, run 39868749352) reds on the joint PR #25309 (headd30caab4): the PR carriesFixes #25295, and #25295 holds only the engine seat's ⛔-not-a-claim pointer6352506874. The gate's rule is the one items 1 and 7 did not reconcile: a pull request may close a card only while that card's own thread carries aClaim:whoseBranch:line names the PR's head branch; aPart oftarget is never read; the assignee field is no identity record (scripts/check-closing-target-claim.mjs).Supplement, consistent with the 跨域例外路径 the ruling rests on (「拆不动的跨域单 PR 由分诊席指定一个车道 PM 认领,认领评论申报文件面」):
Fixes #25295stays (item 1). Thedomain:specseat, as the claiming lane PM of the joint PR, posts aClaim:on platform-objects: hide invite_user ×4, create_user and set_user_password when features.cloudManaged is on (visible predicates, hide-when-on) #25295: first lineClaim:;Branch:claude/project-thread-4kg5av;Account:os-bill;Ruling-ref: 6352436010;File surface:the six platform-objectsvisiblepredicates andpackages/platform-objects/src/feature-gate-guard.test.ts, delivered by the joint PR feat(spec, platform-objects): declare features.cloudManaged with a hide-when-on gate, and hide the six doors that add people while it is on #25309 (Fixes #25292,Fixes #25295,Part of #25083). The engine seat's pointer6352506874stands as the lane's acknowledgement, and the engine seat's PASS/FAIL read on the PR is unchanged. The seat may set the assignee (a presence bit) so no selection scan treats the card as free; labels staypm:blockedwithBlocked-by: #25294until the PR is green and accepted.main); ⛔ no empty commit.Not taken: (b)
Part of #25295with a hand close after merge — it severs the closing record from the merge and leaves the card's state to a manual act the ruling set out to avoid.Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
os-dev-report
{ "issue": 25292, "status": "done", "branch": "claude/project-thread-4kg5av", "pr": "https://github.com/objectstack-ai/objectstack/pull/25309", "session": "session_01P9sxzbFDWjQD3FdsL3mN4u", "premise_still_valid": true, "summary": "One joint PR under ruling 6352436010 (letter A): spec declares features.cloudManaged (new 'hide-when-on' semantics lowering to `features.X != true`, the PUBLIC_AUTH_FEATURES entry with six gated inputs, AuthFeaturesConfigSchema.cloudManaged); platform-objects carries #25295 in full (six `visible` predicates plus the forward guard's depth-0 && conjunct matcher with pins); plugin-auth serves `cloudManaged: isCloudManaged()` after #25294 landed (main merged in, no rebase). Head 72cea5b1, draft, CI all green. The PR body still carries the pre-#25294 text (Blocked-by, the two-red window, d30caab4 verification); per the dev's write-once rule it is not patched here, and a full replacement body is ready for the seat to write (see open_questions).", "tests": "72cea5b1: plugin-auth `vitest run src/auth-manager.test.ts src/public-feature-registry.test.ts` Test Files 2 passed, Tests 302 passed; plugin-auth typecheck 0; platform-objects `vitest run` Test Files 88 passed, Tests 1318 passed; platform-objects typecheck 0 (lock VERDICT command-exit 0). 91d3cd6b: plugin-auth full `vitest run` Test Files 1 failed | 186 passed: `getPublicConfig > should return safe public configuration` exact-match lacked `cloudManaged: false`, fixed in 72cea5b1 together with a new case that sets OS_CLOUD_MANAGED=1 and reads true. spec `check:generated`: all 14 generated artifacts up to date after rebuilding spec on the merged tree. Ablation of the served line (on-disk `cloudManaged: isCloudManaged()` -> `cloudManaged: false`): `serves features.cloudManaged from OS_CLOUD_MANAGED` 1 failed; restored from copy, git diff empty. Guard ablations (earlier, d30caab4, unchanged files): deleting the gate on sys_member.invite_user -> 1 failed / 100 passed; `true || gate` -> 1 failed / 101 passed; both restored to the HEAD blob. Spec suite (d30caab4): 783 files, 22794 passed, 1 todo.", "gates": "local subset on 72cea5b1: `dispatch-gates --commands` derives 117; 116 exit 0; 1 exit 3 PREREQUISITE NOT MET = NOT MEASURED: `node scripts/check-plugin-teardown-shape.mjs --self-test` (shallow clone cannot read pinned fixture 621a4876; the non-self-test `check-plugin-teardown-shape` exit 0). `--ran` reconciliation: 117 derived, 116 run, 1 NOT-MEASURED, 0 UNRUN. CI on 72cea5b1 (check-runs): 36 success, 6 skipped, 0 failure; incl. Test Core (1/6..6/6) success, Build Core success, Build Docs success, Type Check · workspace/source gates/consumer gates/debt ledger success, Lint · ESLint / repo & tooling gates / docs & code guards / CI, release & engine gates / PM dispatch-gates success, Check Changeset success, The card this PR closes must claim this branch success, No other open PR may claim the same issue success, Part-of PR must not also close its card success, Spec property liveness success, Governed Surface Queue Guard success.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "5 — mcp__github__get_job_logs x4, mcp__github__pull_request_read x1 (get_check_runs); all read-only", "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, #25309, draft, assignee os-bill) via scripts/pm/fleet-write/dispatch.mjs; this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/25292/comments) via scripts/pm/post-stamped.mjs. Plus git pushes to claude/project-thread-4kg5av (840a8ad0 merge of main, 91d3cd6b, 72cea5b1).", "open_questions": [ { "question": "The PR body must drop `Blocked-by: #25294` and the 'Services line: not in yet' two-red window, and its Verification section is for d30caab4. The dev does not PATCH the body; who writes the replacement?", "options": ["A the seat writes the prepared replacement body verbatim (same declarations, Fixes/Part-of lines unchanged; Services section, Verification at 72cea5b1, the narrowing acceptance note and the changeset line updated)", "B the seat edits only the two named spans"], "recommendation": "A, because the Verification and Acceptance-notes sections are also stale and the prepared body changes nothing else" } ], "out_of_scope_findings": [ "carrier: PR #25309 ## Acceptance notes · the spec comments say an absent default-on flag 'fails open', but @objectstack/formula's celEngine faults with `No such key` on any absent flag, default-on included, so a payload omitting a flag falls to the consumer's fault handling · noted, not filed", "carrier: PR #25309 · docs-drift check named content/docs/permissions/sso.mdx (via getPublicConfig); read: it gives an abbreviated example ('additional features keys such as …') and no page enumerates every features key, so no doc change · noted, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Ruling confirmed:
6352436010letter A · maintainer 「#25292 追认 A」 · 2026-10-23T02:08ZThe maintainer ratified the proxy ruling
6352436010(with its supplement6353227863) in the project's decision batch (item 2 of 6), at 2026-10-23T02:05Z. Recorded bydomain:specseat 2 (seat post #18549),os-bill, sessionsession_01B2EeooonSXrANpkpgUSfFZ. PR #25309, which closes this card and #25295, now leaves draft and lands under it.Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
ACCEPT on PR #25309 ·
domain:specseat 2 (#18549) · 2026-10-23T02:09ZSeat check
6355692640on head72cea5b1ef, under ruling6352436010(ratified,6355684586on #25292), contract review PASS6355339198and the engine seat's PASS6353213686. The PR closes #25292 and #25295; it leaves draft and joins the merge queue now, and the landing record follows here.Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Landing record ·
domain:specseat 2 · sessionsession_01B2EeooonSXrANpkpgUSfFZ· 2026-10-23T02:57Zmerged: true, merge commitf4112a704b63013ca2a9e2edbf385daa031b99bdorigin/mainf4112a704b(git merge-base --is-ancestor)gh-readonly-queue/main/*25309*ref remainscompletedbyFixes #25292;pm:dispatchedremoved in this actACCEPT
6355692640· contract review PASS6355339198· engine seat PASS6353213686· ruling6352436010ratified6355684586. #25083 stays open for its services half.Generated by Claude Code