Skip to content

Product update: proven practice instead of our own machinery (F13) - #10

Merged
immakermatty merged 3 commits into
mainfrom
claude/DEV-6594-update-simple
Sep 21, 2026
Merged

immakermatty merged 3 commits into
mainfrom
claude/DEV-6594-update-simple

Conversation

@immakermatty

Copy link
Copy Markdown
Contributor

Why

The Principal, 2026-09-19: "Codex and Pablo named the risks correctly; now, early in the implementation, let's pivot to a cleaner solution. Our goal is not to build our own software machinery but to hold to proven practices and an elegant solution. Do not support every combination at any cost." Nothing on this codebase is deployed to a client, so this is the last free moment to change the trust format.

The contract merged in #4 was sound on paper, but implementing it (#5, #7, #8: ≈9,200 lines of src/update + src/publish and ≈7,000 lines of tests) showed where the weight comes from:

  1. TUF around an unpatched tuf-js. The client does not persist what it verifies, so the product grew its own role promotion, failure-state floor capture, a five-rule floor vector, link equivalence, a four-key publisher, a metadata tree on GitHub Pages beside artifacts on Releases, a redirect allowlist, a daily refresh job and a key ceremony. Four review rounds each found another gap in that layer.
  2. Three ways to finish an activation (a transient worker from the previous binary, a Launchpad watchdog, finalization on any CLI start) plus a readiness file, a stability period and four state files.
  3. A contract carrying 25 numbered deviations.

What changes (documents only)

  • docs/update.md rewritten, 880 → ~250 lines. Release trust = GitHub Releases of this public repository + one Sigstore attestation (actions/attest) over the manifest and every binary, verified by the maintained sigstore library against the exact-tag workflow identity, repository/owner IDs and source commit. A durable high-water mark keeps versions moving forward. One lazurio update command; on a supervised installation a pending.json commit marker, health poll, switch-back on failure and a guarded OnFailure= rollback unit for a crash-loop after power loss. --version <tag> on a prerelease is the whole canary mechanism; no channels. Exit statuses collapse to four classes with a short list of stable JSON error codes.
  • docs/decisions.md: new F13 with the compared alternatives (finish TUF, own signed manifest, HTTPS+checksum, attestation) and what is knowingly accepted; the two sentences that selected TUF are amended.
  • Banners and cross-references in release-cycle.md, pilot-repair.md, expired-trust-recovery.md, machine-handover.md, acceptance.md, ARCHITECTURE.md.

What deliberately does not change

Explicit activation with continuous visibility, immutable versions behind one symlink, a pre-switch self-check by the new binary, OS-owned applications (F8), update separate from content sync (F9), per-user install, the narrow target list, the T3 Code pill/poller model.

Knowingly given up, stated in the contract

  • No expiring freshness metadata: an attacker with the network and a valid github.com certificate can hold a client on its current version, never lower, never foreign bytes.
  • Trust rests on repository governance, so the tag ruleset, the protected release environment with a required reviewer, immutable releases and commit-pinned actions are part of the mechanism.
  • First installation is authenticated by HTTPS only (optional gh attestation verify before execution); self-verification by the downloaded binary is explicitly not presented as authentication.
  • An alive-but-unhealthy new version after a power loss inside the activation window is not recovered automatically; no watchdog is built for it.

Second opinion and evidence

  • Codex (gpt-6-astra) reviewed the pivot: agreed with the direction, and its corrections are in the text — bootstrap honesty, latest is a mutable pointer (hence high-water mark, exact-tag URLs after the redirect, monotonic gate in the workflow, explicit make_latest), anchored SAN pattern plus numeric repository/owner IDs and source commit, the durable ordering of the switch, the guarded OnFailure= no-op conditions, minimum_updater_version with defined semantics, permanent release.yml name.
  • Spike: sigstore@5.0.0 verified a real cli/cli SLSA provenance bundle under Bun 1.4.2 and inside a bun build --compile binary (cold 1.3 s including Sigstore's trust-root refresh); a wrong identity raised PolicyError, a tampered artifact failed the subject check; cross-compiles to linux-arm64.
  • bun run check green (419 tests; documents only).

Follow-up

One replacement implementation PR from main supersedes #5, #7 and #8 (they stay open until it exists, then are closed unmerged). It ports the pieces that survive — build identity, lock primitive, download transport, staging/layout, self-check, service unit, CLI wiring, the Linux qualification harness — reimplements check/verify/activation against this contract, deletes src/distribution with pilot-repair.md and expired-trust-recovery.md, and trims release-cycle.md. Target ≈2,000 lines of src/update.

Needed from the Organization Admin before the first real release candidate (no key ceremony, no Pages, no DNS, no secrets any more): tag ruleset v*, environment release with a required reviewer, immutable releases enabled.

🤖 Generated with Claude Code

… and a single activation path (F13)

The TUF-based contract grew a client persistence layer, a four-key publisher,
a second origin and three ways to finish an activation. Replace it with proven
practice: GitHub Releases + actions/attest + the sigstore verifier, a durable
high-water mark, one `lazurio update` command with a commit marker and a
systemd OnFailure rollback. Contract shrinks from 880 to ~250 lines.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head source review for 12fc067a67e68ace233cc0f76112b6111123e861.

I cannot approve this documentation contract yet. The direction—GitHub Releases plus a strictly verified Sigstore attestation rather than a product-owned TUF layer—is clear and appropriately records its explicit trade-offs. The following contract gaps must be resolved before implementation inherits it.

  1. pending.json has contradictory lifecycle semantics. The invariant says there is no pending attempt/journal (docs/update.md:38-40), the state table says the marker exists only after a switch (:139), but activation durably writes it before the switch (:156-159). Recovery defines only the switched state (selector=to, previous=from; :173-181), not a crash before the switch or a crash after a switch-back and before marker removal. Define the complete fail-closed state machine and reconcile table, including selector/previous/pending states, retry behavior with a high-water already written, mismatches/corruption, and the atomic durable-write requirements for both marker and high-water. A prepared pre-switch marker must not wedge the next click, and an ambiguous state must never be silently cleared or lower the high-water.

  2. Preserve the stated monotonicity on the explicit-tag path. lazurio update --version currently promises only “the same verification” (:107-110), not the normal comparison/high-water rule (:41-43, :87-89). State that exact tags are normalized against the manifest and must still meet the durable ordering policy (including the intentional equal-high-water retry after rollback); they must not create a network downgrade path.

  3. Scope the UX promises honestly. “Never silently stays on an old version” and “No failed attempt needs manual repair” (:16-20, :210) conflict with the explicitly accepted TLS-freeze case (:119-124) and the alive-but-unhealthy-after-power-loss case that requires lazurio update rollback (:182-184). Qualify availability as the newest release successfully observed under the GitHub/TLS assumption, and make the manual-recovery exception visible in the top-level guarantee. Also name the full external trust base: repository governance is the product authorization policy, but GitHub Actions OIDC and Sigstore’s verification roots are cryptographic trust dependencies too.

  4. Make publisher ordering an enforceable invariant. “Greater than every existing final release” (:62-64) is racy without a serialized release-concurrency group and a final check immediately before promotion. Parallel tag workflows can otherwise both pass and a lower final release can publish later and become latest, leaving new clients behind. Specify fail-closed serialization/recheck and how latest is set after it.

  5. Propagate F13 into active cross-document truth. docs/acceptance.md:63,72-77,88-91 still says trust/signing/rotation/channel decisions are unselected prerequisite work, while F13 selects this contract and explicitly removes product channels and product-held signing keys. ARCHITECTURE.md:53-58 still inherits the pilot metadata/expired-transcript recovery model, and :82 calls for a real release channel. Amend these active documents to name F13 as accepted, retain only implementation/qualification and OS-publisher-signing gates, replace obsolete TUF metadata wording with attestation/high-water semantics, and call the path a GitHub Release/product-update path rather than a channel. The release-cycle and pilot documents may remain historical because their new supersession banners make that status explicit.

No merge, release, deployment, activation, or implementation-PR update is authorized by this review.

…or every network path, serialized publishing, honest guarantees, F13 propagated

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head source re-review — CHANGES_REQUESTED

Reviewed exact commit 69338267d4f6414d3ca1e5c5d0d5f8ca2331491b against live main / PR base f3ad8a5bfef26b18b0a8a2fae77a3f800652fa0f. The prior REQUEST_CHANGES was bound to 12fc067a67e68ace233cc0f76112b6111123e861 and was not reused.

The five original issues are substantively repaired in the new product-update contract:

  1. pending.json has a complete reconciliation table, bounded state-invalid behavior, and durable temp → fsync → rename → directory-fsync writes.
  2. Exact tags normalize to the manifest version and use the same monotonic floor; only local rollback crosses below it.
  3. Availability, recovery exceptions, repository governance, GitHub Actions OIDC and Sigstore trust dependencies are now stated with their limits.
  4. Publishing is specified as repository-wide queued concurrency in the protected release environment, with the final-version comparison immediately before publication.
  5. The changed acceptance and architecture surfaces correctly name F13, GitHub Releases, attestations and the version floor.

However, F13 is still not a coherent source of truth across the active documentation. The new contract says there are no product update channels (docs/update.md:128, docs/update.md:280; docs/acceptance.md:63), while active, non-superseded surfaces still make a channel an accepted product input:

  • docs/decisions.md:103 retains independently implemented update channels; :243 retains channel promotion; and accepted F10 at :446-453 retains a default update channel.
  • docs/workspace-presets.md:3,23,54,63,72 is an accepted direction and stores/selects a default update channel.
  • docs/environment-tools.md:3,12 is an active bounded pilot procedure that tells the operator to approve a channel/target.
  • docs/stack-evidence.md:3,14-15 is active evidence/proposal text but still calls the npm route a developer channel and the standalone executable the preferred initial channel.

The legacy TUF documents (release-cycle.md, pilot-repair.md, expired-trust-recovery.md) have appropriate supersession banners and are not this finding. The listed surfaces do not: they currently teach an incompatible configuration and selection model. A future agent can therefore legitimately create, persist or approve a channel even though F13 says the product has none.

Required change

Revise the active F1/F10/open-gates/preset/operator/stack wording so every active surface has exactly the F13 model: GitHub Releases are the sole origin; latest or an explicit exact tag selects a release; there is no configured/preset/typed-request update channel and no channel promotion. Preserve historical terms only in clearly superseded material. Do not introduce a second selector while removing these terms.

Evidence

  • git diff --check f3ad8a5b...69338267 passed; scope is documentation-only (8 Markdown files against the base).
  • bun install --frozen-lockfile && bun run check passed: 416 pass, 3 platform skips, 0 fail, 2,933 expectations; public-input guard, compiled proof and isolated smoke passed.
  • Local Markdown link audit checked 116 local links with no missing target.
  • Fresh live-main merge tree is clean (a18e11af5bfd841d4ef4ad3803dbd74fa2f68777).
  • Added-line safety scan found no private keys, destructive commands, conflict markers, client transfers or absolute paths.
  • Provider checks: check (ubuntu-24.04) and check (macos-14) are SUCCESS; Macroscope - Correctness Check is SKIPPED (not treated as green execution evidence). There are no commit statuses.

No merge, release, deployment, activation, or host mutation was performed.

Comment thread docs/update.md Resolved
… stack documents

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{"event": "APPROVE", "body": "Exact-head F13 documentation review for eb93ee0. The prior active-surface channel finding is repaired. F1 uses neutral \u201cupdate paths\u201d; the F13 contract is unambiguous that latest or one explicit exact tag selects a GitHub Release, with no update channel or channel promotion. F10/presets, profile rendering, typed requests and environment-tool approval no longer carry an update-channel selector. README/stack evidence use distribution where that is the intended shipping meaning. The remaining active \u201cchannel\u201d occurrences are explicit negative F13/acceptance/update statements. The otherwise extensive legacy references sit in documents visibly headed \u201cSuperseded for product update (2026-09-19)\u201d and describe the retired TUF pilot, not the current product contract. No second selector is introduced.\n\nImmediate GitHub gate: PR OPEN/non-draft on this exact SHA; ubuntu and macOS check jobs SUCCESS; no failing/pending context; and zero unresolved review threads after resolution of the repaired prior finding. APPROVED for source documentation only. This review does not merge, release, deploy or authorize those actions."}

@immakermatty
immakermatty merged commit 31847d0 into main Sep 21, 2026
3 checks passed
immakermatty added a commit that referenced this pull request Sep 21, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@immakermatty
immakermatty deleted the claude/DEV-6594-update-simple branch September 21, 2026 21:13
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