Run the two typecheck scripts nothing ran, and build the images from their lockfiles - #121
Run the two typecheck scripts nothing ran, and build the images from their lockfiles#121Hotragn wants to merge 1 commit into
Conversation
…their lockfiles Two gates were written, committed, and never reached. `agent-computer` and `supervisor` each ship `"typecheck": "tsc --noEmit"`. Root `typecheck` is `bun run --filter '*' typecheck`, which enumerates workspaces, and `workspaces` is app, server and worker. So neither script has ever run: the process holding the only `spawn` in the deployment, and the only one holding a Docker socket, reached an image without a type check. Both pass today, so this is a gate turned on rather than a backlog cleared. A separate job rather than another line in `static`, because each installs from its own lockfile and the root install cannot produce their dependency trees. Matrixed so each reports its own result, and in `verify` so branch protection needs no new entry. The lockfiles are the other half, and they were worse than unenforced. Every deployable but the root one installed with a plain `bun install`, and its `bun.lock` was not in the build context at all, so the committed file could not have been honoured however the command was written. Each build resolved afresh: an image built next month was not the image built today, which is the drift the note about pinning Bun is already there to prevent, twenty-three lines above the install that ignored it. It is also what CopilotKit#64's provenance attestation signs, so the digest was exact and part of what went into it was decided by nothing in this repository. `agent-computer`, `supervisor`, `agent-bot` and `agent-langgraph` now copy their lockfile and install `--frozen-lockfile`. All four were checked against their committed lockfile first, so this pins what is already resolved rather than asking for a refresh. The `examples/` packages keep their lockfiles and are left alone: nothing installs them in CI or in an image, so there is no build to pin.
|
One note for whoever picks this up: the checks here need approving before they run. Both runs are sitting at What I could check locally is in the Proof section, and it is the part that decides whether the new job is worth having: both The one thing only CI can answer is whether There is also a small irony worth naming: a PR whose whole subject is checks that never ran is a PR whose own checks will not run until somebody presses a button. |
|
Thank you for this. Closing it in favour of #123, which covers the same ground and landed tonight, but the diagnosis here is yours: you raised #112 and this went up alongside it. You were right on both halves. Two One technical note that is worth having, because it would have bitten as soon as CI ran. Your - run: bun install --frozen-lockfile
working-directory: ${{ matrix.package }}
- run: bun run typecheck
working-directory: ${{ matrix.package }}Both packages set CI never ran here (fork PRs need releasing by a maintainer), so nothing surfaced it. The merged version adds a root install first, which is also the order the root Two of yours we did not take, both worth recording:
Your changelog entry is better than having none, which is what merged. That file is being caught up separately and your framing of the drift is the clearer one. For what it is worth, I built all five images before merging and confirmed the effect you predicted: adding an unreviewed package to Please do send more. Genuinely good find, and the write-up was a pleasure to read. |
What this changes
Two gates that were written, committed, and never reached. Both cover
agent-computer, which is theprocess a Bot's input reaches a child process in.
1. Two
typecheckscripts that never ranagent-computer/package.jsonandsupervisor/package.jsoneach ship"typecheck": "tsc --noEmit". Roottypecheckisbun run --filter '*' typecheck, which enumeratesworkspaces, and
workspacesis["app", "server", "worker"].ci.ymlrunsbun run typecheckandnothing else typechecks anything, so neither script has ever run in CI.
That is the process holding the only
spawnin the deployment, and the only one holding a Dockersocket (
supervisor/Dockerfile:1), reaching an image without a type check. #68 changedshell.tswithout one seeing it.
Both pass today, so this is a gate turned on rather than a backlog cleared:
A separate job rather than another line in
static, because each installs from its own lockfile andthe root install cannot produce their dependency trees. Matrixed so each reports its own result with
fail-fast: false, and added toverifyso branch protection needs no new entry — which is what #64built that gate for.
agent-bot,agent-langgraphand theexamples/packages have notypecheckscript at all. That isa separate question and I have left it alone.
2. Lockfiles that were not merely unenforced — they were not in the build context
Every deployable but the root one installed with a plain
bun install, and none of them copied itsbun.lock:Dockerfile:48-49COPY agent-computer/package.json …thenbun installagent-computer/Dockerfile:14-15COPY agent-computer/package.json ./thenbun installsupervisor/Dockerfile:13-14COPY supervisor/package.json ./thenbun installagent-bot/Dockerfile:8-9COPY … agent-bot/package.json …thenbun installagent-langgraph/Dockerfile:8-9COPY … agent-langgraph/package.json …thenbun installSo the committed lockfile could not have been honoured however the command was written — the file was
not there. Each build resolved afresh.
The root
Dockerfileargues against this itself, twenty-three lines above the install that ignored it:It also bears on #64. That change signs a build provenance attestation for the image digest, and
provenance over a tree resolved at build time attests to less than it looks like: the digest is exact,
and part of what went into it was decided by nothing in this repository.
All four now copy their lockfile and install
--frozen-lockfile.The
examples/packages keep their lockfiles and are untouched: nothing installs them in CI or in animage, so there is no build to pin.
Closes #112
Where it runs
configuration and four image builds.
are built from a pinned dependency tree rather than a freshly resolved one, which is the same on
every replica by construction.
request like the others and is covered by
verify.Boundary and audit
image's dependency tree is now decided by a committed file rather than by whatever the registry
serves that day.
Changelog
Added under
Unreleased→Changed: "The images are built from the lockfiles that are committed."Proof
The four installs were checked against their committed lockfiles before the flag was added, so
this pins what is already resolved rather than asking for a refresh. Each in a clean directory
containing only its
package.jsonandbun.lock:Both new typechecks run clean locally, which is the whole of what the new job asserts:
ci.ymlparses, and the new job is wired into the gate rather than only defined:.dockerignoredoes not excludebun.lock, so the newCOPYlines resolve. Theimagejob buildsthe root
Dockerfileon every pull request, so the changed build is exercised here rather thanfirst at a release.
bun run lintclean (including--error-on-warnings, from #120). This change touches only YAML,Dockerfiles and Markdown, none of which biome formats, so
format:checkis unaffected by it.What is not covered
examples/lockfiles, per above — nothing builds them.agent-botandagent-langgraphstill have no typecheck script. Adding one is writing a newgate rather than turning on a written one, and might surface real errors; worth doing, worth doing
separately.
imagejob, which builds rather than typechecks. Theyare their own job for that reason.
package.json, thebuild now fails and says so, which is the point — but it does mean a dependency bump has to update
the lockfile in the same commit.