Files
claude@clouddev1 56e3456cfc
ci / gate (push) Successful in 1m58s
ci / manifests (push) Successful in 4s
docs: handoff 75 — D3 package managers complete (Scoop/Homebrew/winget)
Covers the session that finished the D3 rollout: install.ps1 Windows 5.1
fixes, Scoop + Homebrew wiring and validation, the Homebrew-403 presigned-URL
saga fixed via a server-side Caddy HEAD rule, and the winget job + komac
bootstrap (PR #391335). Records the infra created off-repo (Caddy rule, the
lazyeval Gitea/GitHub bots + tokens), the gotchas, and the parked signing
tracks.
2026-06-21 22:05:00 +00:00

8.4 KiB
Raw Permalink Blame History

Session handoff — 2026-06-21 (75)

Continues from handoff-74 (v0.2.0 live on crates.io). This session finished the D3 package-manager rollout — Scoop, Homebrew, and winget — plus the Windows install.ps1 fixes, and included a deep presigned-URL / Homebrew debugging saga that's fixed by a server-side Caddy rule. Five commits; one new ADR amendment arc (ADR-0056 Amendments 24).

§1. State

Branch main. No crate (Rust) code changed this session — only .gitea/workflows/, scripts/, and docs/. So the cargo test baseline from handoff-74 (2509 pass / 0 fail / 1 ignored, clippy + fmt --check clean) stands unchanged by construction; not re-run (nothing in the build graph moved). New coverage this session is scripts/test-package-renders.sh (shellcheck-clean, green), now gated on every push by a new ci.yaml manifests job (bash + node; ruby-absent in CI degrades gracefully).

Commits this session (cabc8130208c67; the workflow-bearing ones were pushed, since the live publish dispatches + raw-URL installs the user tested needed them on main):

  • 42b40bc install.ps1 → Windows PowerShell 5.1 compat
  • c0531aa install.ps1 → immediate-use PATH + honest messaging
  • 6d54c1e Scoop + Homebrew jobs (D3 §3b/§3c)
  • 6bb2288 Scoop/Homebrew validated + Caddy fix recorded (Amendment 3)
  • 0208c67 winget job via komac (D3 §3d, Amendment 4)

External / infra state created this session (NOT all in the repo):

  • Caddy Tier-A HEAD rule on the Gitea serverload-bearing for Homebrew, lives in the Gitea edge config, not this repo (see §4). If lost on a server rebuild, brew 403s again.
  • Gitea: lazyeval org with repos scoop-bucket + homebrew-tap; lazyeval-ci Gitea bot user (org team, Write to those repos); LAZYEVAL_PKG_TOKEN secret on oli/rdbms-playground.
  • GitHub: lazyeval-ci bot account; classic public_repo PAT → WINGET_GITHUB_TOKEN secret on oli/rdbms-playground; fork lazyeval-ci/winget-pkgs.
  • winget bootstrap PR #391335 submitted, in Microsoft review.
  • komac 2.16.0 installed locally at ~/.local/bin/komac.

§2. D3 — the package-manager set (the session's throughline)

Channel State
crates.io / cargo binstall live (handoff-74)
install.sh / install.ps1 live — PS1 validated on ARM Windows 11 (5.1 + 7.6)
Scoop (lazyeval/scoop-bucket) live + validated (install + run)
Homebrew (lazyeval/homebrew-tap) live + validated — needs the Caddy rule (§4)
winget (LazyEvaluation.RdbmsPlayground) wired; PR #391335 awaiting Microsoft merge

How Scoop/Homebrew/winget are wired: sibling jobs in .gitea/workflows/publish.yaml (manual workflow_dispatch, tag input), each idempotent + independent. Scoop/Homebrew render dependency-free bash manifests (scripts/render-{scoop-manifest,homebrew-formula}.sh) from the release .sha256 sidecars and push to the org repos via LAZYEVAL_PKG_TOKEN. winget runs komac update --submit to PR microsoft/winget-pkgs, guarded against duplicate PRs. ADR-0056 Amendments 24 carry the full design.

§3. The Homebrew 403 saga + Caddy fix (don't lose this)

Homebrew brew install 403'd while every other tool worked. Root cause, reproduced: Gitea (≥1.25; here 1.26.2) 303-redirects release downloads to a method-bound AWS-SigV4 presigned S3 URL (OVH), signed for the incoming request's HTTP verb. Homebrew resolves with a HEAD, captures the returned HEAD-signed URL, then runs the download GET against it → GET-on-a-HEAD-signed URL → 403. (GET on HEAD-resolved = 403, HEAD on HEAD-resolved = 200, GET on GET-resolved = 200.) GET-only tools (install.sh/ps1, binstall, curl) are unaffected. This is a Homebrew defect (reusing an ephemeral method-scoped credential as a durable locator); Gitea's per-request signing is correct, and SigV4 cannot sign one URL for two verbs. SERVE_DIRECT=false would fix it but was declined (don't reshape storage for one client).

Fix (deployed, "Tier A"): a Caddy rule answering HEAD on …/releases/download/… directly (200, no redirect, no body) so brew's resolve records the original URL and its download GET redirects fresh → GET-signed → 200. GET untouched; a HEAD carries no payload so nothing can break (a HEAD-probing download manager at most loses a progress-bar size). Reference Caddyfile is in ADR-0056 Amendment 3.

§4. Immediate next steps

  1. winget PR #391335: watch validation — the one likely speed bump is an AV/SmartScreen manual-review label (unsigned binary); usually clears. Once a moderator merges, winget is live.
  2. Post-merge check (Windows): winget install LazyEvaluation.RdbmsPlayground, confirm the command is rdbms-playground (it is — a direct single-exe portable takes its PATH alias from Commands[0], which komac set; see §5).
  3. After merge, future releases are hands-off: the CI winget job's komac update carries each version (alias inherited from the merged manifest). The release ritual is unchanged from ADR-0054, with the publish dispatch now also doing Scoop/Homebrew/winget.

§5. Gotchas learned (don't relearn the hard way)

  • The Caddy HEAD rule is server-side, not in this repo. Homebrew (and any HEAD-then-GET client) depends on it. Record/back it up.
  • GitHub tokens: komac needs a classic public_repo PAT — fine-grained tokens can't open the cross-fork PR (komac #310: the PR is created on the target repo you don't administer, which the fine-grained model can't express). A classic token can't be repo-scoped, so it lives on a dedicated bot (lazyeval-ci) to bound the blast radius.
  • komac fork must pre-exist: komac new auto-fork races on winget-pkgs (huge repo) → "Could not resolve to a Repository 'lazyeval-ci/winget-pkgs'". Fork manually first (gh repo fork microsoft/winget-pkgs --clone=false), wait, then re-run. Pre-fill komac new flags to skip the long interactive prompt parade.
  • Direct portable alias = Commands[0], NOT PortableCommandAlias. The latter is archive/nested-portable-only; adding it to a bare-exe portable is wrong (komac correctly omits it). The "Commands" prompt → rdbms-playground is the on-PATH command. Verified vs winget-cli logic + the 1.6.0 schema.
  • install.ps1 / Windows PowerShell 5.1 (the in-box shell — PS7 is opt-in): arch via PROCESSOR_ARCHITECTURE env (not RuntimeInformation::OSArchitecture, which is absent under 5.1's .NET-Framework facade + StrictMode); force TLS 1.2; -UseBasicParsing. Also update $env:Path in-session (the persisted User PATH only reaches new processes; "restart your shell" was wrong — sign-out/in or the in-session update).
  • Gitea release downloads go through OVH S3 presigned URLs — method-bound, 300 s expiry. Never assume HEAD-resolve-then-GET works against them.

§6. Parked / deferred (user decisions)

  • macOS Developer-ID signing + notarization — pending the Apple account → Organization conversion. Ad-hoc signing covers all package-manager paths (brew-installed binary runs on Apple Silicon); Developer-ID only matters for browser-download Gatekeeper trust.
  • Windows code signing (Trusted Signing) — not required to ship winget (portable; only MSIX needs signing). Unsigned can earn an AV/SmartScreen manual-review label + a user-run warning. Lazy Evaluation Ltd (since 2012) clears Trusted Signing's 3-year-org bar when the user wants to remove the warning (individual onboarding is currently paused; org path is open).
  • Release notes / CHANGELOG — raised this session, not done. If wanted: a CHANGELOG.md and/or populated Gitea release bodies, then the CI winget job can pass komac --release-notes-url …/releases/tag/$TAG.

§7. How to take over

  1. Read handoffs 73 → 74 → 75, CLAUDE.md, docs/requirements.md (D1/D3), and ADR-0056 (esp. Amendments 14) + the GA plan docs/plans/20260616-public-availability.md.
  2. Workflow unchanged: phased, test-first, /runda + DA before commits, ADR amendment + README index-upkeep for decided-area changes, confirm commit messages, never push.
  3. If cargo test is needed, the baseline is 2509 / 1 ignored (handoff-74).
  4. Consider a cargo sweep at this milestone (target/ grows).