oficina / docs Public

Release binary must report its source revision open

On branch fix/release-version

Read-only live probe found docs.oficina.works/api/version returns dev, while other suite apps report source revisions. This prevents reliable continuous-deploy verification. Root owns isolated fix/release-version, no overlap with Docs sealing #39.

Build helper archives an explicit committed revision, builds it with rastrillo.BuildVersion set to that full revision, and does not include dirty worktree files. A subprocess test starts the real built app over a private unix socket and checks the framework /api/version response against the source commit. No authentication bypass or new product copy.

Will demonstrate unstamped build fails the test, run actual repo gate, obtain Fable review after20:50 quota reset, then deploy canary and exact merged source only after checks. This fixes the release path; it does not claim the currently live dev endpoint identifies its own source.

Branch5986df4 pushed. Full local .amadan/ci.d/10-gate passed: JS fixtures, deterministic bundles, Rust/WASM, wire compatibility, Go vet/tests/build/fmt. New test boots the actual archived-release binary and checks /api/version equals full source commit. Mutation stamping dev failed on HTTP200 with dev rather than expected SHA, then restored. Remote CI running. Fable whole-branch review prompt ready for20:50 quota reset. No merge or deployment yet.

Exact-head CI5986df4 passed. ARM64 release built by the new script at /tmp/oficina-docs-release-review/docs-arm64. Isolated canary overnight-docs.bds.oncarlos.com created on canary/overnight-release with named environment overnight-release, correct origin, synthetic allowlist and fresh canary-only instance key. No deployment yet, pending Fable. Public live edge still499d200 and process stilldev; current Docs source baseline matches edge, unlike the separately discovered Sheets divergence.

Exact-head CI passed5986df4. Independent whole-branch review canonical claude-fable-5-1 explicitly APPROVE, full verdict below. Isolated overnight-docs canary deployment now underway; no shared production promotion yet.

APPROVE. The branch is one commit on top of 499d200 and, as far as I can see without a shell, adds exactly two files: scripts/build-release.sh and cmd/docs/release_test.go. Nothing in cmd/docs/main.go, internal/, the gate, or config changed. I could not run git diff from this harness, so the "only two files" claim rests on the reflog, the commit message, and a file-level comparison with the main checkout rather than an exact diff.

Correctness of the stamp path, verified against rastrillo v0.22.0

  • -X github.com/carlosframework/rastrillo.BuildVersion targets the real variable at rastrillo@v0.22.0/serve.go:45, default "dev", served verbatim by GET /api/version at serve.go:461. That handler is on the framework's outer mux, outside Wrap and outside the app's RequireSession, so the test's unauthenticated fetch is legitimate.
  • git rev-parse --verify "${2:-HEAD}^{commit}" at build-release.sh:8 resolves tags and branches to the exact commit before archiving, so the stamp and the archived tree cannot disagree.
  • git archive | tar -x under set -euo pipefail propagates an archive failure. No .gitattributes exists, so nothing is export-ignored. The committed editor bundle and docs_core.wasm are in the tree, so a from-archive build is complete.
  • CGO_ENABLED=0 -trimpath -mod=readonly in a directory with no .git gives no VCS stamping and no absolute paths, which is the right shape for a reproducible binary.

Test isolation and mutation

  • Fresh t.TempDir(), own DB, own unix socket, -env development with explicit DOCS_ORIGIN because a socket gives no -addr to derive from. resolveInvocation in run.go:64 accepts -socket plus -db as used. listen at serve.go:555 removes and creates the socket path.
  • The mutation you ran fails on the body comparison at release_test.go:67 with a 200, not on status. That satisfies the AGENTS.md rule that a red test must go red for the right reason.

Non-blocking observations

  • Two-minute build timeout at release_test.go:29. The -trimpath build cannot reuse the gate's earlier cache entries, so a cold CI runner compiles modernc sqlite and wazero from scratch inside that window. If CI shows a build timeout, raise it rather than treat it as a code defect.
  • The test builds HEAD, not the working tree. An uncommitted change to Go source is invisible to it. Script edits are picked up since the script runs from the checkout. This is fine for CI, where HEAD is the branch tip, but worth knowing locally.
  • Environment inheritance. Both child processes use os.Environ(). The -env flag beats $DOCS_ENV, so no leak changes the outcome, but a stray GOFLAGS could.
  • Unix socket path length. Roughly 70 bytes under /tmp. A long TMPDIR on a runner would exceed the 108-byte limit.
  • No doc pointer. AGENTS.md and .amadan/README.md do not mention the script or how a release build feeds carlos deploy. Acceptable for a narrow fix, but the next person will look in "Running it locally" and not find it.

Merge once amadan ci status -branch fix/release-version exits 0.

Isolated canary deployed successfully to overnight-docs.bds.oncarlos.com on canary/overnight-release. Direct GET /api/version reports exact process build5986df4423362ca110e6e285dc0ac5747fa38108, and /signin returns200. Actual CI passed5986df4 and whole-branch Fable APPROVE recorded above. Proceeding with supported Amadan merge; merged-main artifact will be rebuilt from its exact commit before shared promotion.

Release complete: main9871ba0f776fba35723fdd0d6aa60ef599ebfab3 actual CI passed; exact archive-built ARM64 binary promoted edge. Initial channel/header success did NOT cycle the active process: /api/version still dev. Configured supported carlos apps build-probe /api/version, repeated deployment correctly timed out; logs showed old499d200 wake. Supported host-scoped carlos restart for docs.bds.oncarlos.com resolved the process lifecycle. Fresh direct /api/version now returns exact9871ba0f776fba35723fdd0d6aa60ef599ebfab3. Sign-in HTTP200. No user content touched, no content-sealing activation, no keys changed. Keep process version checks on every later promotion.