Skip to content

Services get a full resource surface: deployment subgroup, create/list, and the lifecycle verbs - #162

Merged
wmadden-electric merged 31 commits into
mainfrom
s8-service-primitives
Aug 12, 2026
Merged

Services get a full resource surface: deployment subgroup, create/list, and the lifecycle verbs#162
wmadden-electric merged 31 commits into
mainfrom
s8-service-primitives

Conversation

@wmadden-electric

Copy link
Copy Markdown
Contributor
$ prisma service deployment --help
USAGE
  prisma service deployment list [--project id-or-name] [<service>]
  prisma service deployment show <deployment>
  prisma service deployment promote <deployment> [<service>]
  prisma service deployment rollback [--to deployment] [<service>]
  prisma service deployment start <deployment> [<service>]
  prisma service deployment stop <deployment> [<service>]
  prisma service deployment delete <deployment> [<service>]

COMMANDS
  list      List deployments for the service
  show      Show a deployment in detail
  promote   Promote a deployment to production by rebuilding with production env vars
  rollback  Roll back production to a previous deployment
  start     Start a stopped deployment
  stop      Stop a running deployment
  delete    Delete a deployment and the artifact it holds

The decision. The Management API already draws the seam this PR builds on: Composer produces deployments; the CLI manages them. The service commands ported for continuity kept the legacy flat shape (service list-deploys, service show-deploy, top-level promote/rollback) and left real holes — no service list, no service create (a service could only be born as a side effect of deploying to it), and no deployment start/stop/delete despite the endpoints existing. This PR reshapes the group around the resource model: a service deployment subgroup owns the deployment verbs, and the five missing commands exist. The old spellings are deleted, not aliased — this CLI is pre-rc, so the renames are divergence-list entries, not compatibility debt.

What changed.

  • service deployment list|show|promote|rollback replace the four flat spellings; ids, help, presenters, errors and tests moved together. The engine answers the old spellings with CLI.UNKNOWN_COMMAND.
  • service list (GET /v1/apps) and service create (POST /v1/apps — exactly the four create-body fields, pinned by a request-capture test). create on a taken name returns the existing service (existing: true) — semantics flagged for an operator ruling in the divergence file.
  • service deployment start|stop (POST .../start|stop) and delete (DELETE, typed consent per the service remove precedent). start's artifact-not-uploaded refusal is the API's answer presented, not a CLI-invented precondition.
  • Two presenter corrections: a deployment's url follows liveness (promoted domain only for the live deployment, its own preview domain otherwise), and live derives from the service record alone — the local live-state cache is retired in both directions.
  • Deleting the live deployment needs no CLI guard: verified from the control plane's source that the API tears down (detach endpoint → stop → delete) rather than refuses.

The parity record is .drive/projects/prisma-cli-v8/assets/s2/parity-divergences-s8.md; the slice contract with every ruling is .drive/projects/prisma-cli-v8/specs/s8-services.md. The new e2e coverage (service create/list/remove) has its first real run in this PR's CI — it needs the e2e service token, so it self-skips locally.

Alternatives. Keeping the old spellings as aliases was rejected (doubles the grammar for four commands with no users to protect). A CLI-side guard on deleting the live deployment was rejected after reading the server's delete path — the API handles it. service logs stays shelved deliberately: the API owners accepted serving deployment logs over plain HTTP with live streaming later, so it lands as a small follow-up shaped like build logs once the endpoint serves HTTP, and the engine grows no WebSocket transport.

🤖 Generated with Claude Code

wmadden-electric and others added 22 commits August 12, 2026 12:26
…s) added to the plan

The S8 design discussion (2026-08-12) settled the plan's four
questions: no Composer-ownership note for now, records verified
compatible between Composer and the legacy deploy path, the
log-ownership conflict dissolved (composer log reads the local dev
daemon, not the platform), and service logs stays shelved while the
operator asks the API owners whether deployment logs can be served
over plain HTTP. The contract carries the command tree (deployment
subgroup, old spellings deleted, five new commands) and two presenter
corrections.

S10 is new at operator instruction: after the surface stops moving,
every skill teaching these CLIs is rewritten against v8.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Four dispatches: the deployment subgroup with the presenter
corrections; service list + create; the deployment lifecycle
commands; closure records.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
`list-deploys`, `show-deploy`, `promote`, and `rollback` become
`service deployment list|show|promote|rollback`. The old spellings are
deleted with no aliases: paths, command ids, help text, presenter copy,
error next-actions, and test names all move, and the group gains its own
brief entry next to `service domain`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
`service deployment show` now renders the promoted endpoint domain the
deploy reported instead of the deployment's preview domain, falling back
to the preview domain only when the owning service cannot be found.

The live deployment is derived from the service's latest deployment id
alone: the local-state fallback (`readKnownLiveDeployment`) is gone from
the service commands, and so is the dead scan for a provider-supplied
live flag that `listDeployments` never sets.

`service show` presents a live url only when the service has a live
deployment, because a service that was never promoted still carries an
endpoint domain and that domain does not resolve.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The API owners accept HTTP for deployment logs provided live
streaming can come later, so no engine socket is built and the
WebSocket design shelves as the future streaming path. R-S8-3 is
amended twice from D1's findings: deployment show's url follows
liveness (promoted domain only for the live deployment), and local
CLI live-state retires in both directions — the contract's claim
that only legacy app deploy wrote it was false.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…tired

`service deployment show` presented the service's promoted
`appEndpointDomain` for every deployment. That address only serves the
live deployment, so a non-live deployment showed a url that does not
reach it, and a service that was never promoted showed a placeholder
domain that resolves to nothing. The url is now the promoted address
only when the shown deployment is the one the service names as latest,
and the deployment's own preview domain otherwise.

`service deployment promote` and `rollback` also still wrote the local
live-deployment cache. Nothing in v8 reads that state any more — the
read fallback went in the previous commit — so the writes are dead and
go with the reads. The legacy `app` family keeps its own writes and the
store helper stays for them.

The local-state test for `service deployment show` did not discriminate:
its fixture still named a live deployment, so the deleted lookup was
never reached. It now uses a service with no latest deployment and seeds
both the remembered project and the cache entry, which is what the
retired code path needed to report `dep_1` live.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The error a user sees when promote, rollback, or remove cannot find a
service rendered the bare verb: "Service promote requires an existing
service" and "rerun promote with --service <name>". Those are the
spellings this slice deleted — the command is `service deployment
promote` now.

`resolveServiceReleaseState` already computed the mounted path for the
read state's `commandName`, so that string is hoisted to one const and
passed to the error as well, which also removes the duplicated mapping
of "remove" to its own path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
`POST /v1/apps` was reachable only through `createBranchApp`, the
deploy flow's private helper, which answers with the narrow shape that
flow needs and drops the rest of the record. A `service create` command
needs the whole service back — in particular whether it names a live
deployment, which decides whether it has a URL worth showing.

`createComputeService` is that call, returning a full `AppRecord` and
whether the service already existed. `createBranchApp` now delegates to
it, so the create body has one site rather than two that can drift, and
the 409-means-it-already-exists behavior is shared rather than copied.
The raw-record mapping the listing already did is extracted to
`toAppRecord` and used by both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Until now a service could only be born as a side effect of deploying to
it, and there was no way to see which services a project has without
picking one first. Both are result commands on endpoints that already
exist.

`service list` reports every service on the resolved branch as a table,
following the `project list` precedent: the human table names an absent
region and an undeployed service in words, the stdout lane leaves both
empty so a consumer does not have to parse them back out.

`service create` sends exactly the four fields the API's create body
takes — displayName, project, optional region, optional branch — and
nothing else. A name already taken on the branch comes back as the
existing service rather than an error, which is the `service domain add`
precedent in this same group, and the result says which of the two
happened.

Neither command presents a live URL for a service that names no live
deployment. The endpoint domain such a service already carries does not
resolve until the first promote, so showing it would hand the user a
dead address — the same correction D1 made to the deployment presenters.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…s e2e coverage

The optional service positional on `service list` fed a config target
into the context helper, but listing every service selects none, so the
only value the command took from that call was the project directory —
which does not depend on the target. The positional's sole observable
effect was failing when it named a target the config does not define.
It goes, and the call passes undefined, as `service create` already did.

The e2e run that removes the created service sat inside the
`service list` block. `describeCommand`'s argument is the marker the
coverage check reads, so a real `service remove` happy path existed
while the backlog still listed that command as owed. It gets its own
block and leaves AWAITING_COVERAGE.

Now that it is a coverage case rather than teardown, it asserts what it
removed instead of warning and returning on failure: the scratch
project's own teardown deletes everything it contains, so nothing in
this file has to double as cleanup. The comment above the backlog also
said these commands need a deployed service, which is what kept
`service remove` on the list; `service create` falsified that for the
commands that only need the service to exist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…nce note

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The compute SDK already had startDeployment, stopDeployment and
deleteDeployment; nothing in this repo reached them, because the only
paths that stop or delete a deployment went through the SDK's own
app-teardown and promote-switchover flows. Three thin wrappers put them
beside promoteDeployment, each raising the API's message on failure the
way the existing wrappers do.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Two result commands on endpoints that already existed. Each resolves the
service and the named deployment the way promote does, then calls the
API — unless the deployment already has the status being asked for, in
which case the run makes no call and warns, following promote's
already-live precedent.

The API refuses to start a deployment whose artifact has not been
uploaded. The CLI checks no such precondition of its own: the call goes
out and, if the API refuses, its message is what the user reads. A test
pins that, since the temptation to guess at the precondition is exactly
what the contract rules out.

Both commands are excluded from e2e coverage rather than added to the
backlog, per that file's rule that new commands need a test or a reason:
they act on a deployment, and only `composer deploy` can produce one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The destructive verb of the subgroup, following the `service remove`
precedent: the deployment id has to be typed back, or passed to
--confirm, before anything is deleted. --yes alone cannot grant it.

The contract asked for the live-deployment case to be settled before
this error path was shaped, and it is settled: the API allows deleting
the deployment a service currently points at. It detaches the endpoint,
stops the VM, deletes it, and clears the service's latestDeploymentId in
the same transaction. The only 409 documented on this endpoint is the
stop precondition — promotion is never consulted. So the CLI adds no
guard, and a test pins that deleting the live deployment succeeds.

The service is left with an endpointDomain that no longer resolves, but
that is already handled: every presenter added in this slice reports a
live url only when latestDeploymentId is set, which is null by then.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… from the control plane's source

The API tears down rather than refuses; no CLI-side guard. The
undeleted endpointDomain consequence joins D4's divergence list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
start, stop and delete each report a step-started before the API call
and a step-finished after it, and no test read those events on the path
where the call happens. The suite stayed green if the report lines were
deleted or the step was misspelled, which is the one thing these
assertions exist to catch.

Each happy path now asserts events[0] and events.at(-1) against the
exact step, copying what promote, rollback and remove already do. The
skip and refusal paths keep asserting an empty stream, which only means
something next to a case that pins what a command does emit.

Verified by misspelling start's step name and watching the test fail on
that assertion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…-S2b-9

The `service remove` test asserting that local live-deployment state is
cleared observed a key nothing had written, so it passed whether or not
the clearing happened. The key is now seeded between the show and the
remove run. The clearing is not dead code — the legacy `app` family
still writes it for the same project — so seeding was the right option
of the two offered, rather than dropping the claim. Verified by removing
the clear call and watching the test fail.

The backlog comment in e2e-coverage said its remaining entries act on a
deployed service. That holds for `service open`, the four
`service deployment *` commands and `build logs`, but not for
`service show` or the five `service domain *` commands, which need only
a service that exists. The comment now separates the two reasons instead
of stating one that is false for six of eleven entries.

Walking the acceptance list turned up the same defect one slice earlier
than D3 found it: `service list` and `service create` asserted no events
at all, where R-S2b-9 asks every command to assert them. Both stream
nothing, and now say so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The divergence file records what an S2c user sees change: the four
renames and their deleted spellings (including the command ids, which is
what a script notices), the five new commands, live deriving from the
platform record with local state retired in both directions, the two
presenter corrections, and the narrower liveUrl rule service show
actually implements.

It also carries what the review rounds surfaced and chose not to fix:
deployment list rows reporting live: null rather than false when nothing
is live, a json-only change; --branch resolving or creating, so a typo
makes a branch; create returning an existing service on 409, with the
semantics flagged as an operator ruling still pending; the endpointDomain
left non-resolving after the live deployment is deleted; and stop taking
production offline with no consent while delete demands a typed token,
which is contract-faithful but reads as an oversight now that the two
verbs sit side by side.

deferred.md gains the ownership-note revisit and the service logs
follow-up, both with the facts that make them actionable rather than
vague — no managedBy marker exists, and the transport question is
answered — plus two e2e follow-ups: tightening the service-id prefix
once someone can run the suite, and service show's now-unblocked happy
path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… precondition

Reviewer finding D4-R1-1: on a machine with no cache entry the rows
were already null, byte-identical to today — the entry now scopes the
change to where promote or rollback had written the cache.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@wmadden-electric, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13c95b13-0323-4ed0-9003-9b6ef0453648

📥 Commits

Reviewing files that changed from the base of the PR and between bd8aa78 and 7d27692.

📒 Files selected for processing (15)
  • .drive/projects/prisma-cli-v8/deferred.md
  • .drive/projects/prisma-cli-v8/plan.md
  • .drive/projects/prisma-cli-v8/plans/s8-services.md
  • packages/cli/src/lib/app/app-provider.ts
  • packages/cli/src/v8/service/deployment-run-state.ts
  • packages/cli/src/v8/service/deployment-start.ts
  • packages/cli/src/v8/service/deployment-stop.ts
  • packages/cli/src/v8/service/errors.ts
  • packages/cli/src/v8/service/presentation.ts
  • packages/cli/src/v8/service/target.ts
  • packages/cli/tests/v8-service-deployment-start.test.ts
  • packages/cli/tests/v8-service-deployment-stop.test.ts
  • packages/cli/tests/v8-service-list.test.ts
  • packages/cli/tests/v8-service-remove.test.ts
  • packages/cli/tests/v8-service-session.test.ts

Summary by CodeRabbit

  • New Features
    • Added service list and service create commands.
    • Added service deployment commands for listing, showing, starting, stopping, promoting, rolling back, and deleting deployments.
    • Improved service creation defaults, duplicate handling, lifecycle feedback, and URL presentation.
  • Changes
    • Replaced legacy deployment command names with the service deployment command group.
    • Added confirmation safeguards for deployment deletion.
  • Documentation
    • Documented service command behavior, parity details, settled design decisions, and deferred functionality.

Walkthrough

This change delivers the S8 service-primitives slice. It adds service list and service create, moves deployment commands under service deployment, and adds deployment start, stop, and delete commands. Provider operations, liveness derivation, URL presentation, typed results, error guidance, and command registration were updated. Unit, mount, session, E2E, authentication, consent, JSON, and lifecycle tests were added or updated. Service logs and WebSocket transport remain deferred.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: a deployment subgroup, service creation and listing, and deployment lifecycle commands.
Description check ✅ Passed The description directly explains the command restructuring, new service and deployment operations, behavior changes, testing, and deferred work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch s8-service-primitives
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch s8-service-primitives

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

wmadden-electric and others added 2 commits August 12, 2026 14:09
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>

# Conflicts:
#	packages/cli/tests/e2e-coverage.test.ts
Merging main restored the agent entries the branch's backlog comment
rewrite carried; main's e2e suite now covers them, and the coverage
check rightly refused a command both covered and owed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@pkg-pr-new

pkg-pr-new Bot commented Aug 12, 2026

Copy link
Copy Markdown

Open in StackBlitz

npx https://pkg.pr.new/@prisma/cli@162
npx https://pkg.pr.new/@prisma/cli-engine@162

commit: 7d27692

Every service command settled SERVICE.LOCAL_STATE_STALE against the real
API. The service tree carries its own copy of the project listing, to
avoid dragging the legacy controller's import graph, and that copy
filtered by comparing the API's workspace id against the credential's.

Those are the same workspace under two ids: the credential's
`workspace_id` claim carries the bare form, the management API returns
it `wksp_`-prefixed. The comparison matched nothing, so the listing came
back empty, so the project pinned in .prisma/local.json looked like it
had left the workspace. Every service command resolves a project through
that function, so all of them were broken, not just create.

#144 removed this exact filter from the legacy listing and explained
why: a credential names one workspace and the API answers within it, so
the comparison has no true-positive case and one catastrophic false
positive. The copy here was written from the version that still had it.
It goes the same way, along with the workspace parameter, so nothing
invites it back.

Nothing caught this because the fixtures wrote both sides of the
comparison as `ws_1`. The session suite now has a fixture that reports
the project the way the API really does, prefixed, against a bare
credential claim; it fails if the filter returns. Two tests there rested
on a two-workspace listing the API never produces, so they are reshaped
the way #144 reshaped its equivalents: one now refuses a project the API
did not return, the other proves the acting workspace comes from the
token's claims by what it presents rather than by which project resolves.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…found by S8's review sweep

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.drive/projects/prisma-cli-v8/plan.md:
- Around line 90-97: The settled design note in the plan still says the operator
is asking the transport question. Update the transport-status wording near the
“Design settled 2026-08-12” section to record that HTTP is acceptable per the S8
service specification and WebSocket design record, while keeping service logs
shelved for a future HTTP endpoint and avoiding any implication that the
question remains open.

In @.drive/projects/prisma-cli-v8/plans/s8-services.md:
- Line 14: Update the D1, D2, D3, and D4 headings in the plan to level-two
Markdown headings so they follow the file’s level-one heading without orphaned
level-three sections. Preserve the existing heading text and surrounding
content.

In `@packages/cli/src/v8/service/deployment-start.ts`:
- Around line 93-98: Update the result construction in
packages/cli/src/v8/service/deployment-start.ts lines 93-98 to use the
deployment status observed by a post-startDeployment read, or preserve the
pre-call status and have the presenter indicate that start was requested; do not
force "running". Apply the same change in
packages/cli/src/v8/service/deployment-stop.ts lines 89-94 after stopDeployment,
avoiding a forced "stopped" status. Use the existing lifecycle handlers and
deployment-fetching symbols.

In `@packages/cli/src/v8/service/deployment-stop.ts`:
- Around line 42-112: Extract the duplicated lifecycle logic from
serviceDeploymentStartCommand and the shown stop handler into a shared
runDeploymentStateChange helper in the deployment run-state module. Parameterize
the release command, target status, provider operation, failure summary,
diagnostic code/summary, and presentation function; preserve the existing target
resolution, deployment listing errors, selection persistence, step reporting,
result construction, and already-in-state behavior. Update both start and stop
commands to delegate to the helper.

In `@packages/cli/src/v8/service/errors.ts`:
- Around line 222-233: Update both service-level error handlers in
packages/cli/src/v8/service/errors.ts: releaseTargetRequiredError (lines
222-233) and serviceSelectionInvalidError (lines 114-131). Replace their
deployment-list next action with runCommandAction("List services", "service
list") so users are directed to the service-level listing command.

In `@packages/cli/src/v8/service/presentation.ts`:
- Around line 127-137: Update the empty-services branch in the next action
callback to avoid using the literal placeholder in the runCommandAction command;
emit service create without an argument so serviceCreateCommand reports the
missing positional, or move the placeholder text into the action reason while
keeping command executable.

In `@packages/cli/src/v8/service/target.ts`:
- Around line 234-257: Update listWorkspaceProjects to destructure and validate
the GET /v1/projects response error before mapping data. Throw the returned API
error when present, while preserving the existing project sorting and mapping
for successful responses.

In `@packages/cli/tests/v8-service-remove.test.ts`:
- Line 410: Update the assertion in the relevant v8 service removal test to read
remediation actions from frame.envelope.error.nextActions rather than
frame.envelope.nextActions, while preserving the expected action values.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7294019a-29ac-403b-9037-513451ee7ba6

📥 Commits

Reviewing files that changed from the base of the PR and between b363caf and bd8aa78.

📒 Files selected for processing (43)
  • .drive/projects/prisma-cli-v8/assets/engine/websocket-transport-design.md
  • .drive/projects/prisma-cli-v8/assets/s2/parity-divergences-s8.md
  • .drive/projects/prisma-cli-v8/deferred.md
  • .drive/projects/prisma-cli-v8/plan.md
  • .drive/projects/prisma-cli-v8/plans/s8-services.md
  • .drive/projects/prisma-cli-v8/specs/s8-services.md
  • packages/cli/e2e/service.e2e.ts
  • packages/cli/src/lib/app/app-provider.ts
  • packages/cli/src/v8/cli.ts
  • packages/cli/src/v8/service/create.ts
  • packages/cli/src/v8/service/deployment-delete.ts
  • packages/cli/src/v8/service/deployment-list.ts
  • packages/cli/src/v8/service/deployment-promote.ts
  • packages/cli/src/v8/service/deployment-rollback.ts
  • packages/cli/src/v8/service/deployment-show.ts
  • packages/cli/src/v8/service/deployment-start.ts
  • packages/cli/src/v8/service/deployment-stop.ts
  • packages/cli/src/v8/service/errors.ts
  • packages/cli/src/v8/service/list.ts
  • packages/cli/src/v8/service/open.ts
  • packages/cli/src/v8/service/presentation.ts
  • packages/cli/src/v8/service/release.ts
  • packages/cli/src/v8/service/results.ts
  • packages/cli/src/v8/service/show-deploy.ts
  • packages/cli/src/v8/service/show.ts
  • packages/cli/src/v8/service/target.ts
  • packages/cli/tests/e2e-coverage.test.ts
  • packages/cli/tests/v8-mount-coverage.test.ts
  • packages/cli/tests/v8-service-create.test.ts
  • packages/cli/tests/v8-service-deployment-delete.test.ts
  • packages/cli/tests/v8-service-deployment-list.test.ts
  • packages/cli/tests/v8-service-deployment-promote.test.ts
  • packages/cli/tests/v8-service-deployment-rollback.test.ts
  • packages/cli/tests/v8-service-deployment-show.test.ts
  • packages/cli/tests/v8-service-deployment-start.test.ts
  • packages/cli/tests/v8-service-deployment-stop.test.ts
  • packages/cli/tests/v8-service-list.test.ts
  • packages/cli/tests/v8-service-open.test.ts
  • packages/cli/tests/v8-service-remove.test.ts
  • packages/cli/tests/v8-service-session.test.ts
  • packages/cli/tests/v8-service-show-deploy.test.ts
  • packages/cli/tests/v8-service-show.test.ts
  • packages/cli/tests/v8-service-testkit.ts
💤 Files with no reviewable changes (2)
  • packages/cli/src/v8/service/show-deploy.ts
  • packages/cli/tests/v8-service-show-deploy.test.ts

Comment thread .drive/projects/prisma-cli-v8/plan.md
Comment thread .drive/projects/prisma-cli-v8/plans/s8-services.md Outdated
Comment thread packages/cli/src/v8/service/deployment-start.ts Outdated
Comment thread packages/cli/src/v8/service/deployment-stop.ts
Comment thread packages/cli/src/v8/service/errors.ts Outdated
Comment thread packages/cli/src/v8/service/presentation.ts
Comment thread packages/cli/src/v8/service/target.ts
Comment thread packages/cli/tests/v8-service-remove.test.ts
wmadden-electric and others added 5 commits August 12, 2026 14:35
…patch headings increment properly

Two CodeRabbit findings on #162: plan.md's S8 entry still described
the transport question as open, and the dispatch plan's D-headings
skipped from h1 to h3.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The service tree's project listing destructured only `data`, so a 401,
403 or 500 came back as zero projects. The caller then found the pinned
project missing and told the user their local binding was stale — sending
them to re-link a project that was never the problem. That is the same
wrong recovery path the workspace filter produced, reached from a
different direction.

The listing now checks the response and raises the API's own refusal,
through `projectApiError`, which is what the legacy listing this mirrors
already did.

The fetch moves out of the `listProjects` callback to its call site.
`resolveProjectTarget` runs its body inside a Result generator, and a
throw from the callback surfaces as "generator body threw" rather than
the API's message; listing first lets the error settle as itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ested

Both handlers spread the deployment record they fetched before the call
and overwrote `status` with the value being asked for. Nothing re-read
afterwards, so the output stated a settled status the API had never
confirmed — and the start and stop endpoints answer with an empty body,
so there was nothing to confirm it with. A deployment still coming up
was reported as running.

The provider gains `readDeployment`, a single-deployment read that does
not hunt for the owning service the way `showDeployment` does, since
these callers already know which service they are acting on. Both
handlers re-read after the call and present what came back. A deployment
that reports "starting" is now reported as starting. This follows the
direction #158 took for postgres: stop reporting what the API never said.

The two handlers were near-identical and this made them more so, but
every value that differs between them is decided by one discriminant, so
the shared body moves to `changeDeploymentRunState(ctx, args, verb)` and
the command files keep only their own help and arguments. A helper
taking eight unrelated parameters would not have been worth it; one
taking a verb is.

The test fixtures made the same assumption the code did: their recording
routes replaced the status transition the shared release fixture
performs, so they would have passed against a fake API that never
changed anything. They now model the transition, and each command has a
case where the API reports a transitional status and the command repeats
it rather than claiming the target state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Two recoveries sent the user somewhere that fails the same way they just
did. When no service could be selected, `releaseTargetRequiredError` and
`serviceSelectionInvalidError` both offered `service deployment list` —
a command that selects a service before it lists anything. They now
offer `service list`, which is the one that works without a selection.

`service list` on an empty project offered a run-command carrying
`service create <name>`. A consumer executes `command` verbatim, and
`create` takes its name as a positional, so following that action would
create a service called "<name>". Naming it is the user's decision, so
it becomes a user-choice action — which is how the project family
already handles a command with a placeholder in it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…lowed API refusal

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@wmadden-electric
wmadden-electric merged commit 9730012 into main Aug 12, 2026
12 checks passed
@wmadden-electric
wmadden-electric deleted the s8-service-primitives branch August 12, 2026 12:48
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

wmadden pushed a commit that referenced this pull request Aug 12, 2026
Records only. Marks S8 closed in the plan and the contract's status
line: shipped as #162, acceptance verified line by line at closure, with
the e2e-caught workspace-filter defect and its fix recorded. One ruling
stays open (`service create`'s 409-idempotent semantics — divergence
file marks it operator-ruling-pending); follow-ups live in
`deferred.md`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
wmadden-electric added a commit that referenced this pull request Aug 12, 2026
…ipeline

Operator rulings 2026-08-12: the existing publish mechanisms stand
(STOP-1); S7 carries the install smoke while S6 lands in parallel
(STOP-5); pin convergence waits until 8.0.0-rc.1 publishes (STOP-7).
STOP-6 closed by events - #162 merged first and this branch carries
the merge. versioning.md documents the verification stage between the
version decision and the registry; plan.md and deferred.md record
where S7 stands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
wmadden-electric added a commit that referenced this pull request Aug 12, 2026
…the rulings

Review findings (CodeRabbit). The substantive one: a workflow rerun or
re-publish dispatch met npm's refusal to publish over an existing
version and died before the Release step could repair a missing
Release or its assets. The publish step now treats an
already-published version as done and still fails on every other
error.

The rest are record consistency: the rollout table's @prisma/cli row
follows the next-tag ruling; the spec and dispatch plan are marked
revision 3 with the final STOP dispositions instead of the working
defaults they were drafted against; two markdownlint complaints
(heading levels, a line starting with #162) fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants