Skip to content

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

Closed

Description

@objectstack-fleet

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: cloudApiKey comes from controlPlaneApiKey or OS_CLOUD_API_KEY, the env service key the cloud injects.
  • :278: credential() prefers that key over the device-bound oscc_… token.
  • :558, :570: status reports bound whenever credential() is non-empty, so a runtime holding the key always reads "Connected".
  • :754: POST /unbind presents 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 registers CLOUD_CONNECTION_UI_BUNDLE unconditionally.
  • cloud-connection-ui.ts:60–64: the nav entry sits in group_apps at 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)

  1. 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 /unbind before the revoke and before the local clear, with a 409 and a stable error code.
      Status may also serve managed: true so a client can tell. Keep the served shape narrow, as the status route's comments require.
  2. Nav move. In CLOUD_CONNECTION_NAV_CONTRIBUTIONS, set group: 'group_integrations' and pick a priority that sorts after the existing integration entries. The page itself is unchanged.
  3. Pins:
    • with the key set, no cloud_connection_settings page and no nav_cloud_connection entry 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.
  4. Changeset: patch for @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

  1. added
    bugSomething isn't working
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    and removed on Oct 21, 2026
  2. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 21 (serial) · domain:cli seat 2 · p2 · the platform half of ruling 甲 (filed by triage; pair objectstack-ai/cloud#3137) · 2026-10-21T10:32Z
    Session: session_01LmjU2x1faLZ39DVTFyVca6
    Account: os-justin (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-25097-cloud-connection-managed
    Worktree: objectstack-issue-25097
    Domain: domain:cli
    Seat: domain:cli#2 (seat post #22648)
    File surface (read on origin/main 5050442bb; line numbers move; stop on a breach and explain it in the report):

    • packages/cloud-connection/src/cloud-connection-plugin.ts:
      • one "managed" predicate: the effective control-plane credential is the env service key (about :270–:278);
      • with it, skip registering CLOUD_CONNECTION_UI_BUNDLE (about :346);
      • refuse POST /unbind before 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 from group_apps to group_integrations (about :63–:64), at a priority that sorts after the existing integration entries. The page itself is unchanged.
    • Pins:
      • managed: no cloud_connection_settings page, no nav_cloud_connection entry, and unbind answers 409 without calling revoke or clearing the store;
      • not managed: the page registers and the entry sits in group_integrations.
    • The existing pins that name the page or its group are updated, not loosened: 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.
    • A changeset for @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).
    • ⛔ Hold-offs:
      • the status route's served shape: no managed field. No consumer reads one, since a managed runtime never serves the page. If the dev measures a consumer, they stop and report;
      • the panel UI;
      • the device-code binding flow;
      • the hosted per-env kernel (the pair card);
      • packages/spec/**.
        Container & model: M, mode:subagent, model: default tier (dispatch-gates.mjs --tier at 5050442bb: "no path-derived mandate")
        Clause-②: no (narrowing)
        Basis for the Clause-② line: for a runtime holding the env service key, POST /unbind is 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 one CONTRACT_REVIEW_TIER review 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:
    • No open PR touches packages/cloud-connection/** or the four pin files. All 12 open PRs were read in this act.
    • This seat has no other dev in flight. rest: one record export format may not neutralize a stored value for the context its consumer reads it in (reach not measured; detail withheld under the disclosure ruling) #25078 awaits the maintainer's choice, with no code and no hold.
  3. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  4. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #25110 comment 6315626597 · domain:cli seat 2 · session session_01LmjU2x1faLZ39DVTFyVca6 · 2026-10-21T12:14Z · head b5445185d. The review of record is 6315584966 (CONTRACT_REVIEW_TIER, PASS). The changeset is minor with the BREAKING banner, per AGENTS.md's rule for a narrowing. The follow-up for bind/start and bind/poll on 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

  5. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #25110 → ae58b26f9 (Fixes #25097)

    domain:cli seat 2 · os-justin · session session_01LmjU2x1faLZ39DVTFyVca6 · 2026-10-21T12:44Z

    Reading Result
    PR #25110 Merged through the merge queue (enqueued 2026-10-21T12:21Z, merged 2026-10-21T12:43Z)
    origin/main ae58b26f9 is on it, with a single parent 03c12a52e (squash). 11 files, +608 / −57. Each file's blob equals the ACCEPTed head b5445185d's
    Queue branch No gh-readonly-queue/main/*pr-25110* head remains
    This card Closed completed by the PR's Fixes. In the stroke after this comment, pm:dispatched comes off
    • Review chain: claim 6313831494 → report 6315317491 → review of record 6315584966 (CONTRACT_REVIEW_TIER, PASS) → ACCEPT 6315626597 → pointer on this card.
    • What landed (ruling 甲):
      • A runtime holding the env service key is platform-managed. It registers no Cloud Connection page or nav entry, and it refuses a disconnect with 409 RESOURCE_CONFLICT before anything is revoked or cleared.
      • Elsewhere, the entry sits last in Setup's Integrations group.
      • @objectstack/cloud-connection ships it as minor with the BREAKING banner (a narrowing, per AGENTS.md).
    • Open with the maintainer: whether the doors and the page should follow the Integrations group's manage_platform_settings, so one rule governs the capability.
    • Filed from this round: 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 (domain:cli, p3): bind/start and bind/poll on a managed runtime.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:clipriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions