Apply & deploy
The apply lifecycle — how a product.config.ts push reaches the edge, and how to read the farthershore/apply check.
The apply lifecycle — how a product.config.ts push reaches the edge, and how to read the farthershore/apply check.
When you push a change to product/product.config.ts, FartherShore applies it:
it builds the Manifest IR, compiles it, accepts the new
spec, and publishes the snapshot to the edge gateway. The whole sequence is one
apply timeline — a single read-side view derived from the build, compile, and
deployment records — surfaced as the farthershore/apply check on the pushed
commit and as the deployments card in the dashboard.
You don't trigger apply by hand. Pushing the branch is the trigger. The CLI
gives you farthershore build to compile locally and
farthershore product publish to cut a release, but the apply itself runs
server-side off the git event.
# Compile product/product.config.ts to Manifest IR locally (CI-safe).
# Server-side validation + apply happen when you push, not here.
farthershore build --format json
Every apply flows through the same ordered phases. Each phase has a status of
pending, running, succeeded, failed, or skipped.
| Phase | What it does |
|---|---|
| Build IR | Executes product/product.config.ts and emits the Manifest IR. (Labelled "Build IR" to distinguish it from a frontend portal build.) |
| Compile | Core compiles the IR into the internal product model; surfaces compiler diagnostics on failure. |
| Accept | The draft spec is promoted to the accepted spec, just before publish. |
| Apply to edge | Publishes the compiled snapshot to the gateway. This is the step that makes the change live. |
| Stripe | Only present for economic changes (pricing/plan edits) — reconciles Stripe. null (omitted) for non-economic applies. |
The overall status collapses the phases: any failed phase ⇒ failed; edge
succeeded ⇒ succeeded; any running phase ⇒ running; edge skipped (validated
but deferred) ⇒ skipped.
The manifest apply (the farthershore/apply check, whose first phase is Build
IR) and the portal build (the farthershore/frontend check) are separate
pipelines. A template-mode product with no frontend change applies its manifest
without ever building a portal — don't conflate the two checks.
A push always validates — Build IR and Compile run for every commit, including
on a DRAFT product and on pull-request commits (the farthershore/validate
check). But validating is not deploying.
ENV_PUSH) publishes its snapshot
synchronously — a completed env apply is live on that env's edge. See
Environments.So "applied" (compiled + accepted) and "deployed" (serving on the edge) are
distinct states. The apply check reports the edge phase honestly: a green Build
IR + Compile with a skipped edge means validated but not yet deployed.
An economic change on the default branch — a pricing or plan edit — validates and
accepts, then defers the real edge apply to a GitHub Release. Nothing is
published on the push: the edge phase reads skipped until you cut the release,
and the Stripe phase reconciles billing as part of that release apply. This is
why pricing changes are gated behind an explicit release rather than landing the
instant you push.
What counts as an economic change is defined with the product contract. To ship one, cut a release.
After a push, confirm a product is actually serving — not just that the commit
compiled — with product status. It returns lifecycle, the latest release
version, the latest deployment run, and a derived live boolean (ACTIVE + a real
release applied + the edge serving the snapshot).
farthershore product status croncloud --format json
{
"id": "prod_...",
"status": "ACTIVE",
"latestReleaseVersion": "v1.2.0",
"live": true,
"latestDeployment": {
"id": "dep_...",
"status": "SUCCEEDED",
"edgePublishStatus": "SUCCEEDED",
"createdAt": "2026-06-24T17:40:11.000Z"
}
}
live: true is the only signal that means "subscribers are hitting the new
snapshot." A SUCCEEDED build with live: false means the manifest validated
but the edge has not published it (a DRAFT product, or a deferred economic
change).
product publish deploys the current spec live and cuts a versioned vX.Y.Z
release with an auto-derived semver bump. It is the path for the deferred
economic changes above.
# Auto-derive the bump from the change and cut the release.
farthershore product publish croncloud --format json
# Preview the computed bump + reasons without cutting a tag.
farthershore product publish croncloud --dry-run --format json
# Force a bump, or pin the exact next tag.
farthershore product publish croncloud --bump minor --format json
farthershore product publish croncloud --version v2.0.0 --format json
A breaking (blocking-risk) change is refused unless you pass --accept-breaking.
Publish enforces the same go-live gates as the dashboard: at least one plan, an
origin, and a verified Stripe connection (clear STRIPE_NOT_CONNECTED /
STRIPE_NOT_VERIFIED / BILLING_TAX_NOT_ENROLLED remediation is printed).
FartherShore posts checks on the commit so apply status lives where you push. Check names double as commit-status contexts, so branch-protection required checks match even when the GitHub App lacks the Checks permission and the platform degrades to a commit status.
| Check | Posted on | Reports |
|---|---|---|
farthershore/validate | PR commits | Manifest validation (Build IR + Compile) for the proposed change. |
farthershore/build | Pushed/released commits | The Product SDK build — the product/ build that produces the deterministic Manifest IR. |
farthershore/apply | Pushed/released commits | The full apply timeline — Build IR → Compile → Accept → Apply to edge (→ Stripe). |
farthershore/frontend | Pushed/released commits | The portal (frontend) build — the frontend/ build that renders a custom portal. Only fires when a frontend build actually runs. |
Checks are feedback, never control flow: a GitHub or platform hiccup is logged and swallowed, and never blocks the apply itself.