Repository navigation
cloud-connection: one rule for the capability (ruling 乙): the page, its record and its three doors require manage_platform_settings like its nav entry; a managed runtime also refuses bind/start and bind/poll #25119
Description
Filing gate ③: the maintainer's direct order. Filed by domain:cli seat 2 (seat post #22648) · os-justin · session session_01LmjU2x1faLZ39DVTFyVca6. ⛔ Not a claim.
The maintainer's word, verbatim: the seat asked in its session's chat whether one rule should govern the Cloud Connection capability. That question is ③ 2 of the review of record 6315584966 on PR #25110 (#25097). The maintainer answered with a picker, choosing the option labelled 「乙 统一成一套」: the page and the three doors also require manage_platform_settings.
Reader, and what they do: domain:cli seat 2 dispatches it in its serial order.
Where it stands (origin/main after PR #25110, ae58b26f9)
- The nav entry sits in Setup's
group_integrations, whoserequiredPermissions: ['manage_platform_settings'](packages/platform-objects/src/apps/setup.app.ts) the nav filter applies server-side. - The page and doors take
setup.accessalone:- the page
cloud_connection_settings(norequiredPermissionsof its own); POST bind/start,POST bind/pollandPOST unbind(holdsSetupAccessinpackages/cloud-connection/src/cloud-connection-plugin.ts);GET status's full-record branch.- So a
setup.access-only administrator (the defaultorganization_adminset) is not served the entry but can open the page by URL and drive the doors.
- the page
- On a platform-managed runtime (the env service key is set),
bind/startandbind/pollstill run. A completed bind persists a device credential the key shadows, and can move the cloud-side connection row (cloud-connection: on a platform-managed runtime, bind/start and bind/poll still run, so a device bind persists a credential the service key shadows and can move the cloud-side connection row #25113, folded in here).
Ruling 乙, as built
- One capability gate:
manage_platform_settings, the Integrations group's own.- It replaces
setup.accessat the three doors and atstatus's full-record branch. A caller without it keeps the narrow status shape it gets today. - The page declares the same
requiredPermissions. - Follow the precedent for platform-settings doors (security(service-datasource): datasource-admin routes require a platform-settings capability beyond authentication #9593,
service-datasource's admin routes): one resolver, no second reading of the grant.
- It replaces
- Managed runtime:
bind/startandbind/pollrefuse asunbinddoes: 409RESOURCE_CONFLICT, after the identity and capability checks and before any control-plane call or store write. - Pins:
- an
organization_admin-only caller is refused at every door and served the narrow status; - a
manage_platform_settingsholder is served as before; - the managed refusal covers all three doors;
- existing pins are updated, never loosened (
cloud-connection-auth-gate,cloud-connection-setup-access,cloud-connection-platform-managed,error-envelope.conformance).
- an
- Docs:
content/docs/deployment/cloud-connection.mdx;- the plugin header's cloud-connection: bind/start, bind/poll and unbind admit any signed-in user (no Setup Access check), and GET /status serves the approving account's email and organization id to anonymous callers #24148 sentence ("the three doors … refuse exactly who that page refuses"), which becomes true again for the entry, the page and the doors;
- any page that names
setup.accessas this capability's gate.
- Changeset:
@objectstack/cloud-connection. This is a narrowing (organization_adminloses the capability), sominorwith the BREAKING banner per AGENTS.md. It owes oneCONTRACT_REVIEW_TIERreview of record.
Out of scope: the device-code flow's own steps, the status shape for a permitted caller, packages/spec/**.
Folds: #25113 (p3). This card's PR carries Fixes #25113.
Dedupe
One MCP search_issues query returned 7 hits, all closed and none this. #25097 is the source, and #9593 is the precedent named above. New.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 28 (serial) ·
domain:cliseat 2 · p2 · ruling 乙 (the maintainer's 「乙 统一成一套」), filed by this seat; it folds #25113 · 2026-10-21T19:42ZSession:
session_01LmjU2x1faLZ39DVTFyVca6Account:
os-justin(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-25119-cloud-connection-one-ruleWorktree:
objectstack-issue-25119Domain:
domain:cliSeat:
domain:cli#2(seat post #22648)File surface (read on
origin/main1b3b65e643; line numbers move; stop on a breach and explain it in the report):packages/cloud-connection/src/cloud-connection-plugin.ts:manage_platform_settings, replacessetup.access(holdsSetupAccessabout:516,refuseWithoutSetupAccessabout:551) atPOST bind/start,POST bind/pollandPOST unbind, and atGET status's full-record branch (about:579). A caller without it keeps the narrow status shape. There is one resolver and no second reading of the grant; the precedent isservice-datasource's admin routes (security(service-datasource): datasource-admin routes require a platform-settings capability beyond authentication #9593).bind/startandbind/pollrefuse asunbinddoes, with 409RESOURCE_CONFLICTafter the identity and capability checks and before any control-plane call or store write.packages/cloud-connection/src/cloud-connection-ui.ts: the pagecloud_connection_settingsdeclaresrequiredPermissions: ['manage_platform_settings'], if pages carry that key (measure first; if they do not, say how the page is gated).organization_admin-only caller (setup.accesswithoutmanage_platform_settings) is refused at every door and served the narrow status;manage_platform_settingsholder is served as before;cloud-connection-auth-gate,cloud-connection-setup-access,cloud-connection-platform-managed,error-envelope.conformance.content/docs/deployment/cloud-connection.mdx, and any page namingsetup.accessas this capability's gate.@objectstack/cloud-connection.packages/spec/**;packages/platform-objects(the Setup app's group gate stays as it is).Container & model:
M,mode:subagent,model: default tier(dispatch-gates.mjs --tierat1b3b65e643: "no path-derived mandate")Clause-②: no (narrowing)
Basis for the Clause-② line: a caller holding
setup.accesswithoutmanage_platform_settings(the defaultorganization_adminset) loses the three doors, the page and the full status record, and a managed runtime refuses two more doors. Nothing widens. It owes oneCONTRACT_REVIEW_TIERreview of record before the queue.Responsibility: this lane's
packages/cloud-connection. The platform rule it adopts is the Integrations group's own gate. It reaches every runtime's cloud-connection doors.Thread-read: none
Serial constraints cleared:
packages/cloud-connection/**orcloud-connection.mdx. All 9 open PRs were read in this act.packages/runtime) and PR fix(rest)!: the CSV export writes a text cell in a form its consumer reads as text, and the CSV import reverses it (#25078) #25130 (packages/rest) are disjoint.Mode: serial. This is the seat's only dev in flight.
objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 1 (takeover) ·
domain:cliseat 2 · p2 · ruling 乙 (the maintainer's 「乙 统一成一套」) · it folds #25113 · it continues claim6324946471on the same branch · 2026-10-21T22:19ZRelease: claim
6324946471· sessionsession_01LmjU2x1faLZ39DVTFyVca6· accountos-justin· 因: the claimant is unreachable (its session is out of tokens) · 去向: this claim, in this same stroke, on the same branch and file surface. Provenance: who — the maintainer; verbatim — 「前任没有 token了,你接手他的所有开发」; where — the chat of this seat's sessionsession_01AFrKwndmrCLtF5V9hNtrw3.Session:
session_01AFrKwndmrCLtF5V9hNtrw3Account:
os-bill(the seat's linked user asGET /useranswers it; always the card's assignee, swapped fromos-justinin this stroke)Branch:
claude/issue-25119-cloud-connection-one-ruleWorktree:
objectstack-issue-25119Domain:
domain:cliSeat:
domain:cli#2(seat post #22648)File surface: unchanged from claim
6324946471, which carries it in full (packages/cloud-connection/src/cloud-connection-plugin.ts,cloud-connection-ui.ts, their pins,content/docs/deployment/cloud-connection.mdx, any page namingsetup.accessas this capability's gate, a changeset for@objectstack/cloud-connection; the same hold-offs). Stop on a breach and explain it in the report.Container & model:
M,mode:subagent,model: default tier(dispatch-gates.mjs --tierat60b42cd0b: "no path-derived mandate")Clause-②: no (narrowing)
Basis for the Clause-② line: unchanged from
6324946471. Asetup.access-only caller loses the three doors, the page and the full status record, and a managed runtime refuses two more doors. Nothing widens. It owes oneCONTRACT_REVIEW_TIERreview of record before the queue.Responsibility: this lane's
packages/cloud-connection. The platform rule it adopts is the Integrations group's own gate. It reaches every runtime's cloud-connection doors.Thread-read: 6324946471
Serial constraints cleared: no open PR touches
packages/cloud-connection/**orcloud-connection.mdx(all 9 open PRs' file lists read in this act). Since1b3b65e643,origin/mainmoved 2 commits (863c58022,60b42cd0b), neither touching those paths. This seat's PR #25136 (packages/runtime) and PR #25130 (packages/rest) are disjoint.Resume-from:
claude/issue-25119-cloud-connection-one-rule@1b3b65e643Handoff record: the old branch's last pushed sha is
1b3b65e643, which isorigin/mainat the old claim. The round-28 dev pushed no commit of its own and posted no report, so there is nothing to inherit. The new dev starts from that sha and mergesmainfirst.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{
"issue": 25119,
"status": "done",
"branch": "claude/issue-25119-cloud-connection-one-rule",
"pr": "#25143",
"session": "session_01AFrKwndmrCLtF5V9hNtrw3",
"premise_still_valid": true,
"summary": "Ruling 乙 built in packages/cloud-connection. One helper, holdsPlatformSettings, replaces holdsSetupAccess at all four call sites (bind/start, bind/poll, unbind, and status's full-record branch). It reads manage_platform_settings (CLOUD_CONNECTION_CAPABILITY, one constant in cloud-connection-ui.ts) through the existing resolveAuthzContext, so there is no new dependency edge (H3 holds). The 403 PERMISSION_DENIED shape is unchanged (H4 holds); the message now names manage_platform_settings. On a managed runtime, bind/start and bind/poll now refuse as unbind does (#25113): one PLATFORM_MANAGED_REFUSAL (409 RESOURCE_CONFLICT) at the same position, after the identity and capability checks and before any control-plane call or store write. H2 is disproven: PageSchema is a strict object with no requiredPermissions key and says to gate the data a page shows, the meta read gate has no page arm, and spec is out of scope, so no key was invented. The page is held where its data is served (status record and the three doors). The nav entry nav_cloud_connection declares requiredPermissions [manage_platform_settings] on itself, following nav_datasources in the same group. H5 is disproven: the route ledger records no gate for the binding rows, so nothing moved there. H1 holds (516/551/579 at 1b3b65e). Merged origin/main at abc25a3 (newer than 60b42cd), a fast-forward, before any edit. Seat action needed: the advisory check 'The card this PR closes must claim this branch' is red because #25113 carries no Claim: naming this branch. A Claim on #25113 is a PM write outside this run's budget.",
"tests": "At head d0bc816, under os-verify-lock: pnpm --filter @objectstack/cloud-connection test gave Test Files 54 passed (54), Tests 670 passed (670), VERDICT command-exit 0; typecheck (tsc --noEmit plus tsconfig.test.json, 54 test files in the program per --listFiles) gave exit 0. The rewritten setup-access pin alone has 55 cases. Ablation 1 (capability read reverted to setup.access in holdsPlatformSettings, via ablation-replace: anchor 1 to 0, blob 4637329150d5 to c6d2e5143a67): setup-access pin plus envelope conformance gave 21 failed, 62 passed; restored with blob == HEAD 4637329150d5 and git diff HEAD empty. Ablation 2 (bind/poll managed refusal deleted, --delete, anchor 1 to 0, blob to 75073de2f440): 4 suites gave 6 failed, 102 passed (managed pin bind/poll x2, auth-gate managed case, setup-access managed control x2, envelope bind/poll 409); restored byte-identical. The first attempt of ablation 2 was a no-op that ablation-replace refused (the replacement was a substring of the anchor, so the count rose 0) and no test ran; it was redone with --delete. No dist leg: the suites import ./cloud-connection-plugin.js from src.",
"gates": "Local subset: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at d0bc816 derived 96 commands (85 by path, 8 by kind, 8 whole-tree). All 96 ran with exit codes recorded to disk before any pipe. 93 gave exit 0 on the first pass; 3 gave exit 3 (PREREQUISITE NOT MET) and were re-run to exit 0 once the prerequisite was met: check-plugin-teardown-shape --self-test needed fixture commit 621a487 (fetched by sha); check:skill-examples and check:dual-build-cjs-loads needed built dist (pnpm build, 75/76 turbo cache hits). --ran reconciliation exit 0: 96 derived, 96 run, 0 NOT-MEASURED, 0 UNRUN. Also: node scripts/check-platform-checklist.mjs --changed-from origin/main exit 0 (1 anchor judged, 0 lost); eslint --no-inline-config over the 9 changed TS files exit 0. PR check-runs at d0bc816, read once: Lint & Repo Gates success, TypeScript Type Check success, Test Core success (6/6 shards), Build Core success, Governed Surface Queue Guard success, Check Changeset success, Lint · ESLint success, Lint · PM dispatch-gates success, Dogfood Regression Gate success, Spec property liveness success, Build Docs success. The card this PR closes must claim this branch: failure (advisory, not one of the five required; #25113 has no Claim naming the branch, which is a seat write).",
"dogfood_battery": "d0bc81613 · os-verify-lock: VERDICT command-exit 0 (held 1212s) · Test Files 287 passed | 3 skipped (290) · Tests 2395 passed | 18 skipped (2413) · no failures",
"mcp_calls": "0 — no MCP GitHub tool called (reads via gh api REST; writes via the fleet-write relay)",
"api_writes": "2 — via the fleet-write relay (repository_dispatch to the board, executed as objectstack-fleet[bot]): (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos//issues/25143/assignees [os-bill]; (2) comment = POST /repos//issues/25119/comments (this report). git push is not counted.",
"line_budget": "11 files, +548 / -321 = 869 changed lines vs the 3000 human-merge threshold: under. No governed surface touched (no .claude/, skills/, docs/adr/**, AGENTS.md, workflows).",
"files_changed": [
".changeset/25119-cloud-connection-one-rule.md",
"content/docs/deployment/cloud-connection.mdx",
"packages/cloud-connection/src/cloud-connection-plugin.ts",
"packages/cloud-connection/src/cloud-connection-ui.ts",
"packages/cloud-connection/src/cloud-connection-setup-access.pin.test.ts",
"packages/cloud-connection/src/cloud-connection-platform-managed.pin.test.ts",
"packages/cloud-connection/src/cloud-connection-auth-gate.pin.test.ts",
"packages/cloud-connection/src/error-envelope.conformance.test.ts",
"packages/cloud-connection/src/cloud-connection-plugin.test.ts",
"packages/cloud-connection/src/connection-credential-store.test.ts",
"packages/cloud-connection/src/cloud-connection-runtime-version.pin.test.ts"
],
"deviations": [
"Changeset level is patch, not the card's minor. AGENTS.md Post-Task Checklist 3 and the Check Changeset gate follow ruling A (2026-10-21, #25105): the level follows the metadata protocol alone. This diff is Metadata-protocol: none, so patch, keeping the BREAKING banner and the ADR-0087 disposition not-required (no-migration-prescription). Check Changeset is green on the PR. This is a conflict between the dispatch and AGENTS.md, stated here, not chosen silently.",
"pnpm lint: the dispatch asks for it; the agent definition makes repo-wide scans CI-owned. Ran eslint --no-inline-config over the 9 changed TS files (exit 0) instead. The PR's Lint · ESLint check-run is success.",
"The page declares no requiredPermissions: H2 is disproven (PageSchema has no such key). The page is gated by the mechanism that exists: the entry (group gate plus its own item-level requiredPermissions) and the data path (status record and the three doors).",
"nav_cloud_connection gained an item-level requiredPermissions (inside cloud-connection-ui.ts, in the file surface). This is redundant with the group gate today, and ties the entry to the doors' constant.",
"origin/main had moved to abc25a3 when the worktree was built; merged that (a fast-forward) instead of 60b42cd.",
"The pending .changeset/25097-cloud-connection-platform-managed.md was NOT edited (outside the file surface), though this PR makes two of its sentences false. See out_of_scope_findings.",
"Advisory check 'The card this PR closes must claim this branch' is red for #25113 (no Claim naming this branch). Posting a claim is outside this run's write budget and role."
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: exception: release-text · evidence: the pending, unreleased .changeset/25097-cloud-connection-platform-managed.md says 'The connect and disconnect requests still take Setup Access alone.' and that the disconnect refusal comes 'after the sign-in and Setup Access checks'. Both are false once PR #25143 lands, and both changesets compile into the same release's CHANGELOG. Suggested fix: drop the first sentence and change the phrase to 'after the sign-in and capability checks' (one edit to that changeset; a seat call, either as a patch round on this branch or as a docs-only PR) · dedupe words: 25097 changeset, Setup Access alone, cloud-connection release text",
"carrier: none (承接者:无) · noted, not filed: POST /install and the three read routes (installation, installed, org-packages) still take any signed-in session, as before (pre-existing, with a TODO in the code; out of scope per the card). No public-door reading was taken. Recorded in the PR's Acceptance notes."
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 22, 2026
os-dev-report
{
"issue": 25119,
"status": "done",
"round": "patch round 1: make the pending 25097 changeset true for this PR",
"branch": "claude/issue-25119-cloud-connection-one-rule",
"pr": "#25143",
"head": "f827e706365a462b6a3688149e5ceec197d11b78",
"session": "session_01AFrKwndmrCLtF5V9hNtrw3",
"summary": "One commit on top of d0bc816 edits .changeset/25097-cloud-connection-platform-managed.md only; its frontmatter is untouched. (1) 'after the sign-in and Setup Access checks' became 'after the sign-in and capability checks'. (2) Dropped 'The connect and disconnect requests still take Setup Access alone.' (3) One further smallest edit, because the sentence was false of this head: the BREAKING list's Unchanged bullet read 'a runtime without the service key, apart from the entry's group. The connection status answer is unchanged on every runtime.' It now reads 'a runtime without the service key, apart from the entry's group and the permission its connect and disconnect requests and its connection details require, which another change in this release raises to
manage_platform_settings. The connection status answer is otherwise unchanged on every runtime.' Every other sentence was re-read against this head and is true: the title line, the ADR-0087 marker and the BREAKING banner say 'refuses to disconnect' and 'a disconnect request ... is now refused', which still hold. The worktree was rebuilt from origin/claude/issue-25119-cloud-connection-one-rule; main was not merged (no conflict, no main-caused red). PR body NOT written by this run: see deviations and pr_body_edit.","gates": "At f827e70, exit codes to disk before any pipe. node scripts/check-changeset-no-major.mjs --base origin/main --event (the PR's pull_request payload as stored) gave exit 0, LEVEL AXIS green (no (narrowing), none, patch). pnpm check:changeset-claims does not exist in package.json, so it was not run. dispatch-gates --commands re-derived 96 commands, the same set as at d0bc816. Re-ran the 27 whose inputs this round touched (13 matched by the 25097 path, plus 14 whole-tree or kind-matched): 26 gave exit 0; node scripts/check-empty-changeset.mjs --base origin/main gave exit 1, the designed DELIBERATE CORRECTION refusal ('this PR changes a changeset it did not add': do NOT restore it; get it confirmed on the PR; the gate stays red either way). The other 69 read no path this round changed, so their exit codes are carried from the full 96-command run at d0bc816, stated in the record. --ran exit 0: 96 derived, 96 run, 0 NOT-MEASURED, 0 UNRUN. PR check-runs on f827e70, read once, all completed: The card this PR closes must claim this branch success (green after the seat's Claim 6329172927 on #25113). Lint & Repo Gates, TypeScript Type Check, Test Core (6/6), Build Core and Governed Surface Queue Guard all success. Check Changeset failure on step 12 only (Reject an empty-frontmatter changeset added by this PR, the same designed deliberate-correction red); its step 13 (ADR-0087 disposition) and step 15 (major/level guard) are success. Check Changeset is not one of the five required contexts. All other checks are success or skipped.",
"files_changed": [
".changeset/25097-cloud-connection-platform-managed.md"
],
"pr_body_edit": "For the seat to apply (this run does not PATCH the PR body). (a) In '## Docs', append the line: '-
.changeset/25097-cloud-connection-platform-managed.md(the pending note from the platform-managed change): its sentences now match this PR (see Acceptance notes).' (b) Replace the first Acceptance-notes bullet ('Release text. ... It is left to the seat, because it lies outside this card's file surface.') with: '- Pending release note corrected (deliberate correction, ordered by the seat). The pending 25097 changeset's two sentences now match this PR: "after the sign-in and Setup Access checks" now reads "after the sign-in and capability checks", and "The connect and disconnect requests still take Setup Access alone." is dropped. Its Unchanged bullet now names the permission this release raises tomanage_platform_settings. The frontmatter is untouched.Check Changesetstays red on its foreign-changeset step by design (check-empty-changeset, deliberate-correction class); its ADR-0087 and level steps are green. This line is the written confirmation that route asks for.' Keep 'Fixes #25119' and 'Fixes #25113' on their own first lines.","deviations": [
"PR body not updated by this run. The dispatch allowed one PR-body write, but the agent definition says a dev writes the PR body once, at pr_create, never PATCHes it, and names later edits in the report for the seat to write. The relay also has no PR-body op (issue_patch on the PR number would be that PATCH). The exact edit is in pr_body_edit. This is a conflict between the dispatch and the definition, named here; the definition was followed.",
"A third sentence was edited beyond the two named (the Unchanged bullet), under the dispatch's 'smallest further edit that keeps every sentence true of this PR's head'. The exact before and after are in summary.",
"check-empty-changeset exits 1 by design on this diff (the deliberate-correction class), so Check Changeset is red on its step 12. Its documented remedy is a written confirmation on the PR, not a restore and not skip-changeset. The confirmation text is in pr_body_edit (b).",
"--ran: 69 of the 96 exit codes are carried from the d0bc816 run (those families read no path this round changed), as ordered ('re-run only what this touches'). 27 were re-run at f827e70."
],
"mcp_calls": "0 — no MCP GitHub tool called (reads via gh api REST)",
"api_writes": "1 — this comment: fleet-write relay op comment = POST /repos//issues/25119/comments. No PR-body write, no labels, no ready flip. git push is not counted.",
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Oct 22, 2026
ACCEPT → PR #25143 (the
## 席位核对posted in this stroke) ·domain:cliseat 2 · sessionsession_01AFrKwndmrCLtF5V9hNtrw3· 2026-10-22T00:39Z · headf827e7063. Review of record6329791200(CONTRACT_REVIEW_TIER, PASS). It also closes #25113 (folded, claim6329172927).Generated by Claude Code