Skip to content

Build logs: one timeline per Image Build, a section per Builder - #1127

Merged
nick-potts merged 6 commits into
mainfrom
feat/build-log-history
Sep 26, 2026
Merged

nick-potts merged 6 commits into
mainfrom
feat/build-log-history

Conversation

@nick-potts

@nick-potts nick-potts commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Each Image Build's build log now tells the whole story as one timeline. Every Builder's go gets its own section, and a move to another Builder is one plain sentence built from the typed SkipReason. The header above the log is gone. The canvas node and the panel now say only "Built on ".

Building on GitHub Actions                                   View run ↗
  21:09:00  ✓  Waiting for a runner                 18s    ← Cloud: opened before dispatch, closed at check-in
  21:09:18  ✗  Installing ployz                      4s    ← runner (getployz/build#5)
GitHub couldn't install ployz 0.1.2-beta.48. Building on hel-1 instead.
  21:09:25  ✓  Waiting for a free build slot        40s    ← only when the daemon queued it
  21:10:05  ✓  Uploading source                      2s
             Building web …
  21:12:40  ✓  Exporting image                       6s

A GitHub build shows its push with progress for each layer:

  ✓  Pushing image   12s
       5f70bf18a086: Pushed
       Pushed sha256:…

Sending the image to Machines happens at deploy time, so it appears in that Service's deploy log: "Sending image to hel-2, hel-3", then "Image sent". A delivery failure fails the deploy, not the build.

Where each step is recorded, so its timing is honest:

 build_step
+  attempt int    -- the go's place in the log; part of the unique key
 walk (Cloud)
+  planImageBuildWalk → every BuildCandidate carries its attempt (planning skips offset it)
+  each write passes { image, attempt } explicitly; the deploy step's own writes pass null
+  GitHub start → opens "Waiting for a runner" BEFORE dispatch, insert-if-absent (a retry never reopens it)
+  check-in     → closes it; a failure → failed "Starting the build" naming the cause
+                 (grant not issued / Machine unreachable / other)
+  skip / move / settle → closes the Builder's open steps
+  no Builder left      → failed "Couldn't start the build"
 view
+  a section's Builder comes from its skip (GitHub Actions / your servers) or the current holder
 collector
   Queued → "Waiting for a free build slot", Output → "Exporting image", Push → "Pushing image"
+  Output while Push is open → that step's lines; Sending/Delivered → deploy-log progress
 core
+  ployz_build::Stage::Push, emitted through serde; each `docker push` line as Progress::Output
+  SDK prepare: Sending { service: ServiceName, machines: Vec<MachineName> } before each Service's push,
+               Delivered { …, service } right after it; push failures are a plain Vec<String>
  • skipReasonText is now one plain sentence per reason, e.g. "No GitHub runner started within 3 min." It is also the failure message when no Builder is left.
  • Routine selection reasons (build order, had the cache, spread) no longer show anywhere in the UI. The data still holds them.
  • The node's build state follows only the last section. GitHub's failed install no longer turns a build that fell back to hel-1 red.
  • Section headings are derived, not written as a row. A Server go that was moved on is named "your servers": its Server is cleared with the move.
  • Logs written before this change are all attempt 0. They render as one section with no fallback sentence between steps. That's acceptable before 0.2.0.

Evidence

  • Before: the log header read "Built on hel-1 · spread across Servers · skipped GitHub: the runner stopped before finishing". GitHub's and the servers' Build Steps shared the key (image, build, key), so a fallback's stage:Building overwrote GitHub's.
    After: github-image-builds.postgres.test.ts covers every infrastructure move and checks:
    buildLogSections(steps).titles == ["Building on GitHub Actions",
                                       "<skip sentence> Building on <machine> instead."]
    no open GitHub steps left behind; the failed install counts only in its own section
    openBuildStep retried after check-in → the wait stays closed
    planImageBuildWalk → candidates carry attempt 0, 1 (1, 2 after a planning skip)
    
    Also deployment-view.test (derived headings, "your servers"), preparation-progress.test (push lines, deploy-log sending), deployment-logs.test, build-order.inngest-engine.test, the Postgres runtime-persistence and inngest-engine tests, typecheck, lint, workspace clippy -D warnings, fmt. All pass locally; CI runs the rest.

Merge Danger

Door: one-way once getployz/build's v1 moves; two-way until then.

Rollout order:

  1. Merge and deploy this PR.
  2. Release ployz. Runners install the version Cloud names, so they get the push stage from here.
  3. Merge Report "Installing ployz" as the first Build Step build#5 and move v1.

Rolling back Cloud after step 3 makes an older Cloud treat the runner's failed "Installing ployz" step as a failed build instead of moving on. Revert v1 first. The migration only adds a column that defaults to 0, and it can stay.

Blast Radius: build-logs

  • Until ployz is released, GitHub builds show no "Pushing image" step. Older runners and older ployz only produce fewer steps.
  • The SDK ships with Cloud, so Sending/Delivered always match.
  • Merged with main. The only conflict was dashboard/src/components/deployment-logs.tsx (main's time-zone clock and log skeleton), and both sides are kept.

Each Builder's go is a section of the Image Build's log, keyed by a new
attempt column. A move opens with one plain sentence from the skip trail.
Cloud times the wait for a runner; ployz build streams the push; the SDK
reports sending each image to its Machines. The mechanical Built-on header
is gone; routine selection reasons stay in the data only.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@railway-app

railway-app Bot commented Sep 26, 2026

Copy link
Copy Markdown

🚅 Environment ployz2-pr-1127 in Ployz Dashboard has no services deployed.

Codex added 5 commits September 26, 2026 03:34
# Conflicts:
#	dashboard/src/components/deployment-logs.tsx
…e view, sending in the deploy log

The walk passes each go's attempt; the skip-trail subquery and per-step
overrides are gone. Section headings come from the go's Builder, not a
heading row. The runner wait opens once, before dispatch. Sending an image
is the deploy's: it reads in that Service's deploy log and a delivery
failure no longer reddens the build. A failed check-in names its cause.
… with their report, sending tracked apart

A servers not_started skip carries the Server the Engine chose, so its
section still reads "Building on hel-1". A runner report files its steps
in the same transaction as the guard that takes it, so one that loses to a
move leaves nothing open in GitHub's section. The collector tracks the
Service being sent on its own and never leaks it into later phases.
# Conflicts:
#	dashboard/src/components/deployment-logs.tsx
@nick-potts
nick-potts merged commit 0bf20ff into main Sep 26, 2026
14 checks passed
@nick-potts
nick-potts deleted the feat/build-log-history branch September 30, 2026 15:14
nick-potts added a commit that referenced this pull request Sep 30, 2026
* Build logs: one timeline per Image Build, a section per Builder

Each Builder's go is a section of the Image Build's log, keyed by a new
attempt column. A move opens with one plain sentence from the skip trail.
Cloud times the wait for a runner; ployz build streams the push; the SDK
reports sending each image to its Machines. The mechanical Built-on header
is gone; routine selection reasons stay in the data only.

* Typed Push stage and SDK names for sending; push failures as a plain list

* Build log review: one explicit attempt per write, Builder named by the view, sending in the deploy log

The walk passes each go's attempt; the skip-trail subquery and per-step
overrides are gone. Section headings come from the go's Builder, not a
heading row. The runner wait opens once, before dispatch. Sending an image
is the deploy's: it reads in that Service's deploy log and a delivery
failure no longer reddens the build. A failed check-in names its cause.

* Build log review 2: moved Server go keeps its name, runner steps land with their report, sending tracked apart

A servers not_started skip carries the Server the Engine chose, so its
section still reads "Building on hel-1". A runner report files its steps
in the same transaction as the guard that takes it, so one that loses to a
move leaves nothing open in GitHub's section. The collector tracks the
Service being sent on its own and never leaks it into later phases.

---------

Co-authored-by: Codex <codex@codex-vm.tailcb9c5.ts.net>
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.

1 participant