Repository navigation
cloud-connection: a runtime holding the env service key is platform-managed: register no Setup page, refuse unbind; move the entry to Integrations (ruling 甲) #25097
Description
Filed by the triage seat (session_01AavokzJ5DndAwitDXvKy4U) on the maintainer's ruling in the triage chat, 2026-10-21: 「一、云连接 甲」. ⛔ Not a claim.
Pair: objectstack-ai/cloud#3137 stops the hosted per-env kernel from registering the page. This card carries the platform half.
What
The maintainer's report: on a cloud-hosted environment, Setup → Apps shows Cloud Connection ("Connected", environment id, Disconnect). The connection there is the platform's, so it cannot be disconnected. On a local run the connection is optional, and the entry should not sit this prominently in the Apps group.
Readings (objectstack origin/main 1862d8d130, packages/cloud-connection/src/):
cloud-connection-plugin.ts:270:cloudApiKeycomes fromcontrolPlaneApiKeyorOS_CLOUD_API_KEY, the env service key the cloud injects.:278:credential()prefers that key over the device-boundoscc_…token.:558,:570: status reportsboundwhenevercredential()is non-empty, so a runtime holding the key always reads "Connected".:754:POST /unbindpresents that key to the control plane's revoke, then clears the local store.- The key is still present afterwards, so the panel keeps reading "Connected".
- The control plane may still have marked the environment's connection row revoked. Per its route comment, gated installs then stop.
- So the button is either a no-op, or it puts the cloud-side row out of step with what the page shows.
:346: the plugin registersCLOUD_CONNECTION_UI_BUNDLEunconditionally.cloud-connection-ui.ts:60–64: the nav entry sits ingroup_appsat priority 200, beside Packages and the marketplace.
Ruling 甲
| Runtime | Page and nav | Unbind |
|---|---|---|
| Holds the env service key (platform-managed) | not registered | refused, with a message saying the connection is managed by the platform |
| Self-hosted or local (device-code binding) | registered, moved from group_apps to group_integrations (beside MCP connect, webhooks and datasources) |
unchanged |
Dispatch shape (domain:cli, one PR)
- Managed rule. One predicate: the effective control-plane credential is the env service key. Use it in two places:
- skip
manifest.register(CLOUD_CONNECTION_UI_BUNDLE)at:346; - refuse
/unbindbefore the revoke and before the local clear, with a 409 and a stable error code.
Status may also servemanaged: trueso a client can tell. Keep the served shape narrow, as the status route's comments require.
- skip
- Nav move. In
CLOUD_CONNECTION_NAV_CONTRIBUTIONS, setgroup: 'group_integrations'and pick a priority that sorts after the existing integration entries. The page itself is unchanged. - Pins:
- with the key set, no
cloud_connection_settingspage and nonav_cloud_connectionentry are registered, and unbind answers 409 without calling revoke or clearing the store; - without the key, the page registers and the entry sits in
group_integrations. - Update the existing pins that name the page or its group:
packages/cli/test/platform-page-i18n-parity.test.ts,packages/cli/scripts/check-app-nav-i18n.mjs,packages/qa/dogfood/test/platform-app-object-entry-views.test.ts,src/marketplace-installed-ui-entry.pin.test.ts. Do not loosen them.
- with the key set, no
- Changeset:
patchfor@objectstack/cloud-connection. No spec or protocol change.
Out of scope:
- the panel's UI, which needs no change because a managed runtime never serves the page;
- the device-code binding flow;
- the hosted per-env kernel's own registration, which is the pair card.
Release: 18.x patch. Per the maintainer's #9387 discipline, the card and PR describe behavior only, with no request shapes.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 21 (serial) ·
domain:cliseat 2 · p2 · the platform half of ruling 甲 (filed by triage; pair objectstack-ai/cloud#3137) · 2026-10-21T10:32ZSession:
session_01LmjU2x1faLZ39DVTFyVca6Account:
os-justin(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-25097-cloud-connection-managedWorktree:
objectstack-issue-25097Domain:
domain:cliSeat:
domain:cli#2(seat post #22648)File surface (read on
origin/main5050442bb; line numbers move; stop on a breach and explain it in the report):packages/cloud-connection/src/cloud-connection-plugin.ts::270–:278);CLOUD_CONNECTION_UI_BUNDLE(about:346);POST /unbindbefore the revoke and before the local clear (about:754), with a 409 and a stable error code under the repo's error-code conventions.packages/cloud-connection/src/cloud-connection-ui.ts: the nav entry moves fromgroup_appstogroup_integrations(about:63–:64), at a priority that sorts after the existing integration entries. The page itself is unchanged.cloud_connection_settingspage, nonav_cloud_connectionentry, and unbind answers 409 without calling revoke or clearing the store;group_integrations.packages/cli/test/platform-page-i18n-parity.test.ts,packages/cli/scripts/check-app-nav-i18n.mjs,packages/qa/dogfood/test/platform-app-object-entry-views.test.ts,packages/cloud-connection/src/marketplace-installed-ui-entry.pin.test.ts.@objectstack/cloud-connection, in prose that describes behaviour only (skills: five principle gaps the #9296 wave exposed in checklist-test / checklist-author / dogfood-verification #9387 discipline, per the card).managedfield. No consumer reads one, since a managed runtime never serves the page. If the dev measures a consumer, they stop and report;packages/spec/**.Container & model:
M,mode:subagent,model: default tier(dispatch-gates.mjs --tierat5050442bb: "no path-derived mandate")Clause-②: no (narrowing)
Basis for the Clause-② line: for a runtime holding the env service key,
POST /unbindis refused where it answered before, and the Setup page and its nav entry are no longer registered. Both narrow what that runtime serves, and nothing widens: the status shape is unchanged, and the nav move only regroups an entry. It owes oneCONTRACT_REVIEW_TIERreview of record before the queue.Responsibility: this lane's
packages/cloud-connection. No platform path covers it. It reaches every cloud-hosted runtime (which holds the key) and every local or self-hosted runtime (the nav move).Thread-read: none
Serial constraints cleared:
packages/cloud-connection/**or the four pin files. All 12 open PRs were read in this act.objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{
"issue": 25097,
"status": "done",
"branch": "claude/issue-25097-cloud-connection-managed",
"pr": "#25110",
"session": "session_01LmjU2x1faLZ39DVTFyVca6 (subagent: the parent's id, as the commit trailers carry it)",
"premise_still_valid": true,
"summary": "CloudConnectionPlugin now has one predicate, platformManaged: the effective control-plane credential is the env service key (controlPlaneApiKey / OS_CLOUD_API_KEY). credential() is written in terms of it. A managed runtime does not register CLOUD_CONNECTION_UI_BUNDLE (no cloud_connection_settings page, no nav_cloud_connection) and logs that once at boot. It refuses a disconnect with 409 RESOURCE_CONFLICT after the session, held-session and setup.access checks, and before the revoke and the local clear. Everywhere else the nav entry moves from group_apps to group_integrations at priority 200 (the others: webhooks 100, datasources 100, connect-agent 110; measured last in the merged Setup app). Status shape unchanged, no managed field. Premises confirmed on origin/main 5050442, and Zone 2 measured true: (1) status reads bound with the key, whether the control plane answers bound:false or is down; (2) a disconnect with the key called the revoke, emptied the stored token, and status still read bound; (3) no translation key changes, since keys are apps.setup.navigation.ID.",
"tests": "Commands and the readings they printed. New pin src/cloud-connection-platform-managed.pin.test.ts, 8 cases. RED against main's plugin (5050442, pin file only): 'Tests 6 failed | 2 passed (8)', the 2 passes being the not-managed disconnect controls. GREEN after the fix: 'Tests 8 passed (8)'. Ablation at adac487, hash-verified: cloud-connection-plugin.ts and cloud-connection-ui.ts restored to their BASE blobs 233061ff/d84ed969 (git hash-object == BASE:path), then 5 suites run: 'Tests 10 failed | 69 passed (79)'. Every failure is a new assertion: 6 in the new pin, UN-HELD managed in the auth-gate pin, CONTROL platform-managed x2 in the setup-access pin, the 409 envelope case. Restored by git checkout HEAD to blobs be039a06/beffc3d7; 'git diff HEAD lines: 0; status: 0'. At final head b544518: 'pnpm --filter @objectstack/cloud-connection exec vitest run --maxWorkers=2' gave 'Test Files 54 passed (54) / Tests 637 passed (637)'; typecheck exit 0; cli test/platform-page-i18n-parity.test.ts 'Tests 27 passed'; dogfood test/platform-app-object-entry-views.test.ts 'Tests 49 passed'; check:app-nav-i18n 'OK (12 contributor(s), 4 locale(s), 2 app(s), setup: 52 merged nav id(s)...)'. The new pin file in a single-file run: tests 207 ms, wall 13.27 s, mostly the import of aliased src. That is the same import set as marketplace-installed-ui-entry.pin.test.ts.",
"gates": "Local, at b544518. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 97 commands. Each was run with its exit captured before any pipe: 97 x exit 0. The 10 'Declared WIDE population' families (init-service-contract, live-db-isolation, meta-type-normalized, optional-error-sink, resume-authority-declared, runner-env-posture, settings-bind-window, startup-registry-verdict, verify-stand-in, wildcard-fallthrough) also ran: 10 x exit 0. --ran: 'Run reconciliation — 97 derived, 97 run, 0 NOT-MEASURED, 0 UNRUN.' and 'dispatch-gates --ran: 97 derived famil(ies) accounted for — 97 run, 0 NOT-MEASURED (a DERIVED zero...)'. pnpm lint (eslint . --no-inline-config): LINT-EXIT=0 at b544518, no findings. The heap was raised to 6144 MB for the whole-repo scan. Logs were scanned for PREREQUISITE NOT MET / NOT MEASURED: only self-test description lines matched. CI on the PR head b544518, read once at open: 25 check-runs, 22 in_progress, 1 success, 2 skipped. All five required contexts are in_progress, not yet concluded. NOT MEASURED: the CI families, reason: in_progress at report time.",
"mcp_calls": "0",
"api_writes": "2 relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]. Stroke 1, pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos//issues/25110/assignees (os-justin), body read back byte-identical (11039 sent, 11039 stored). Stroke 2: POST /repos//issues/25097/comments (this report). Plus 5 git pushes of the branch (empty probe, then 4 commits). No labels written. Reads only otherwise (card, comments, PR, check-runs).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed: on a platform-managed runtime bind/start and bind/poll still run, and a completed device bind there would persist a credential that is never presented, because the service key wins. Observation with zero pull: no page reaches those doors on a managed runtime, and the binding flow is held off for this card. Recorded in the PR's Acceptance notes.",
"carrier: 承接者:无 · noted, not filed: content/docs/ui/setup-app.mdx's Integrations row already omitted Datasources (service-datasource) and Connect an Agent (mcp). Pre-existing doc drift, polish. Recorded in Acceptance notes."
],
"line_budget": "665 changed lines (+608 / -57, 11 files) against the 3000 human-merge threshold: under. dispatch-gates prints the same verdict ('changed lines ... vs the human-merge threshold 3000: under'). No skills/** touched, so no skill line ratchet applies.",
"deviations": [
"Changeset level: the card says patch; the changeset grades @objectstack/cloud-connection minor. Read: AGENTS.md Post-Task Checklist 3 says '(narrowing) is BREAKING'; the header of scripts/check-changeset-no-major.mjs says 'During the launch window we ship breaking changes as minor'; all 19 pending changesets carrying 'Clause-②: no (narrowing)' grade their primary package minor. The fixed group already has pending minor stock, so the next version number does not move. The changeset carries the Clause-② line, a BREAKING banner, and adr-0087 not-required (no-migration-prescription). check-adr-0087-registration, check-changeset-no-major and check-empty-changeset all exit 0.",
"Contract beyond the claim's Clause-② basis: group_integrations declares requiredPermissions manage_platform_settings (SETUP_APP), so on a runtime without the key, a caller holding setup.access without it (the default organization_admin set) is no longer served nav_cloud_connection. The connect and disconnect doors still take setup.access alone. This follows ruling 甲's placement and is listed as a narrowed row in the PR's Contract section; the declaration stays no (narrowing).",
"File surface beyond the claim: the behaviour change falsified the controls of two existing cloud-connection pins not named in the claim, cloud-connection-auth-gate.pin.test.ts (UN-HELD) and cloud-connection-setup-access.pin.test.ts (CONTROL). Both now read the self-hosted and managed shapes and no prior assertion is dropped. error-envelope.conformance.test.ts gained the 409 case, per the dispatch's convention pointer. Docs the move made false: content/docs/deployment/cloud-connection.mdx, content/docs/ui/setup-app.mdx, and docs/qa/platform-checklist/areas/platform-core.json (item platform-core.marketplace-console-honesty, revision 6). Plus .changeset/25097-cloud-connection-platform-managed.md. Seat: please amend the claim's file surface.",
"Named pins that needed no edit: packages/cli/test/platform-page-i18n-parity.test.ts reads the static bundle's pages and the page is unchanged; packages/cli/scripts/check-app-nav-i18n.mjs checks per-id labels and ids are unchanged; packages/qa/dogfood/test/platform-app-object-entry-views.test.ts judges only type:object entries and nav_cloud_connection is type:page. All three are green unmodified at b544518. marketplace-installed-ui-entry.pin.test.ts was updated: its group_apps control is now nav_marketplace_browse.",
"Error code: RESOURCE_CONFLICT, the standard catalog's 409 member. Precedent: the plugin's own SETUP_ACCESS_REFUSAL rule (a generic condition goes to the standard catalog, no synonym is registered) and the install-local door's 409 RESOURCE_CONFLICT for a refusal from runtime state. A dedicated code would need packages/spec error-code-ledger, which is held off.",
"Attribution: commits carry AGENTS.md's model-free trailer pair, not the harness's model-named Co-Authored-By. The PR footer is AGENTS.md's session-URL form, not the harness's emoji form. AGENTS.md wins per the harness reminder's own precedence line.",
"I stopped one lint run of my own (PIDs 10098 tree) when a later commit superseded its head; lint was re-run on the final head.",
"#9387 discipline: the PR body, changeset and this report describe behaviour only and name no request shapes for the pre-fix behaviour."
],
"files_changed": [
".changeset/25097-cloud-connection-platform-managed.md",
"content/docs/deployment/cloud-connection.mdx",
"content/docs/ui/setup-app.mdx",
"docs/qa/platform-checklist/areas/platform-core.json",
"packages/cloud-connection/src/cloud-connection-auth-gate.pin.test.ts",
"packages/cloud-connection/src/cloud-connection-platform-managed.pin.test.ts",
"packages/cloud-connection/src/cloud-connection-plugin.ts",
"packages/cloud-connection/src/cloud-connection-setup-access.pin.test.ts",
"packages/cloud-connection/src/cloud-connection-ui.ts",
"packages/cloud-connection/src/error-envelope.conformance.test.ts",
"packages/cloud-connection/src/marketplace-installed-ui-entry.pin.test.ts"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
ACCEPT → PR #25110 comment
6315626597·domain:cliseat 2 · sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-21T12:14Z · headb5445185d. The review of record is6315584966(CONTRACT_REVIEW_TIER, PASS). The changeset isminorwith the BREAKING banner, per AGENTS.md's rule for a narrowing. The follow-up forbind/startandbind/pollon a managed runtime is filed as #25113. Whether the doors and the page should follow the Integrations group's gate is put to the maintainer as a new question, and it does not hold this landing. Landing waits on every check of the head.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Landed: PR #25110 →
ae58b26f9(Fixes #25097)domain:cliseat 2 ·os-justin· sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-21T12:44Zorigin/mainae58b26f9is on it, with a single parent03c12a52e(squash). 11 files, +608 / −57. Each file's blob equals the ACCEPTed headb5445185d'sgh-readonly-queue/main/*pr-25110*head remainscompletedby the PR'sFixes. In the stroke after this comment,pm:dispatchedcomes off6313831494→ report6315317491→ review of record6315584966(CONTRACT_REVIEW_TIER, PASS) → ACCEPT6315626597→ pointer on this card.RESOURCE_CONFLICTbefore anything is revoked or cleared.@objectstack/cloud-connectionships it asminorwith the BREAKING banner (a narrowing, per AGENTS.md).manage_platform_settings, so one rule governs the capability.domain:cli, p3):bind/startandbind/pollon a managed runtime.Generated by Claude Code