Skip to content

web: navigate from unresolved to resolved CA build steps#1682

Draft
amaanq wants to merge 5 commits into
NixOS:masterfrom
obsidiansystems:ca-resolve-ui
Draft

web: navigate from unresolved to resolved CA build steps#1682
amaanq wants to merge 5 commits into
NixOS:masterfrom
obsidiansystems:ca-resolve-ui

Conversation

@amaanq

@amaanq amaanq commented Apr 24, 2026

Copy link
Copy Markdown
Member

Note

This depends on #1629

Resolved CA steps do not own the log users are trying to inspect, so
leaving them as terminal pages makes the build view look stuck or failed
in the wrong place. The log page now follows the recorded resolution chain
to the step that actually performed the work, while preserving a pending
page for unresolved, running, or malformed chains.

The redirect banner is reconstructed from BuildSteps instead of session
flash so copied log URLs and refreshes keep the same context. The JSON
summary exposes the same durable resolution data for API clients that
need to follow CA build steps without scraping HTML.

@amaanq
amaanq marked this pull request as draft April 24, 2026 16:09
@Ericson2314

Copy link
Copy Markdown
Member
  1. nixlog URL is for any type of step, not just build steps. Resolve steps should have pages too.
  2. "resolve of" should be "resolution of"

Ericson2314 and others added 5 commits July 16, 2026 14:56
Soon, we're going to make a new build step page which will share a
number of things with the build page.

In order to get ready for that, extract the following into a new
`build-common.tt` for reuse:

- `renderOutputs`
- `renderOutputsTable`
- `renderStepStatus`
- `renderStepDuration`
- `renderStepMachine`
- `renderLogButtons`

Likewise, move the `showLog` helper out of `Build.pm` into
`Hydra::Helper::LogEndpoints`. Both are needed by the BuildStep
controller introduced in a later commit.

As a bonus, the new `renderLogButtons` is already used twice within
`build.tt` itself (for the build log and the runcommand log),
deduplicating previously identical button markup.

No behavior changes.
Build steps are, in my view, an important concept that Hydra doesn't
yet give enough attention. This is my attempt to rectify that.

A new detail page at `/build/:id/step/:stepnr` shows output paths,
derivation, system, machine, duration, status, and log links, reusing
the shared blocks extracted in the previous commit. Clicking anywhere in
the build steps table row now navigates to this page, instead of the
step log page. The step log pages also have a link back to this page.

Also reflecting giving build steps more status, introduce
`Hydra::Controller::BuildStep`, chained off `/build/buildChain`, giving
them a first-class controller.

For a bit of back story, note that in the future, we might switch
associating build steps more with derivations than builds. This
reflects that we don't really care *why* something was scheduled (the
build/root derivation) as much as *what* was scheduled, especially when
multiple new builds would "race" to schedule the same derivation. It
also bodes well for a future where Hydra can act as a Nix derivation
that receives ad-hoc build requests, so the "build" in this case would
be rather lacking in metadata. Both these scenarios point to a world
where `BuildStep`s become more important than `Build`s, building (ahem)
atop this refactor.

The step log handling is now better suited to live as part of this
controller. Accordingly, it is moved from
`/build/:id/nixlog/:stepnr[/raw|/tail]` to
`/build/:id/step/:stepnr/log[/raw|/tail]`. The old `nixlog` URLs are
preserved as 301 redirects in `Build.pm`. All templates updated to
generate the new canonical URLs.
Replace the in-memory `resolved_drv_map` with a `resolvedDrvPath`
column on `BuildSteps` (migration upgrade-87). The
`resolve_drv_output_chains` SQL query now joins through this column to
follow unresolved → resolved chains when looking up outputs, so the
mapping survives restarts.

`try_resolve_force` no longer needs the in-memory map, and the
recursive SQL handles resolution transparently on the primary path.
The per-link loop survives only as a fallback for chains the SQL
cannot resolve: it retries each link against the DB and then the
`.drv` file on disk (authoritative for input-addressed derivations),
since a chain can mix links known only to the DB with links whose drv
only exists on disk, and the recursive SQL stops at the first miss.

A step with `status = 13` (`Resolved`) always has a non-null
`resolvedDrvPath` (enforced by a check constraint). Since the original
step's row is only inserted once resolution has already happened, the
resolved path is recorded directly in that `INSERT` rather than by a
later `UPDATE`. Resolved steps get their own `InsertResolvedBuildStep`
/ `create_resolved_build_step` rather than extra optional fields on
`InsertBuildStep`, since the two cases are semantically disjoint. The
lookup query uses the column to find outputs from the resolved drv's
successful buildstep instead.
Build step pages branch on status=13 to show the original drv, resolved basename, and the terminal step link instead of the Build/Substitution info table; the log endpoint 302s to the terminal's log or back to the step page when no terminal log exists yet.
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