[ci] Adopt canonical lab-publish.yaml for releases (lab build + auto-publish to releases/tag/latest) #14
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Adopt the canonical
.forgejo/workflows/lab-publish.yamlso every push todevelopment(and everyv*tag) auto-publisheslinux-musl-x86_64binaries toreleases/tag/latest— matching the pattern shipped in hero_slides/.forgejo/workflows/lab-publish.yaml and the org-wide rollout tracked at hero_skills#268.This replaces the existing tag-triggered
.forgejo/workflows/build-linux.yaml(which uses rawcargo build -p ...per-bin and only fires onv*tags). The new workflow is push-triggered, useslab build --workspace, and republishesreleases/tag/lateston everydevelopmentpush.Pre-flight (local) — two known concerns
This workspace is not the standard shape. Local
lab build --release --install --workspacemay need adjustments:crates/hero_assistance_ui_wasmandcrates/hero_assistance_admin_ui_wasmare workspacemembersbut excluded from[workspace.default-members](Cargo.toml:25-34) because they're wasm32-only (built viadx build/make dist, not hostcargo build). Open question: doeslab build --workspacehonour[workspace.default-members]or iterate allmembers? Needs to be empirically confirmed.crates/hero_assistance_appIS indefault-membersand pulls indioxus-desktop→wry→webkit2gtk-sys. The CI builder imageghcr.io/despiegk/builder:latestdoes not ship GTK/webkit system libraries. The existingbuild-linux.yamlworks around this with explicit-p hero_assistance_server -p hero_assistance_ui -p hero_assistance(skips_app).lab build --workspacewill hit the same wall unless either:_appto[workspace.exclude]or a separate workspace (likely overkill), ORWorkspace shape:
service.tomlfiles (predates the convention).forgejo/workflows/build-linux.yaml(tag-triggered, manual per-bin) to be removedCI step
Pending pre-flight resolution: drop the canonical
lab-publish.yaml(verbatim from hero_slides) into.forgejo/workflows/,git rmthe existingbuild-linux.yaml. RequiresFORGEJO_TOKENsecret in repo Actions settings (write:repository scope).If the desktop-crate wall makes the verbatim canonical workflow impossible, we file a follow-up on hero_skills to add a
--skip-memberknob tolab build(or to add a workflow-level apt-install lane for GTK deps).Acceptance
lab build --release --install --workspaceexits 0 locally (or a documentedlab buildinvocation that excludes_appproduces all server/ui/cli/admin binaries).forgejo/workflows/lab-publish.yamllands ondevelopment;build-linux.yamlremoved in the same commitreleases/tag/latestshows refreshedlinux-musl-x86_64binaries + md5 sidecarsCoordination
labfeature gap; if so, the gap gets filed as a separatehero_skillsissue and this issue blocks on it.Signed-by: mik-tf mik-tf@noreply.invalid
Pre-flight findings (lab build local run)
Ran
lab build --release --install --workspacefrom the workspace root. Result: 8 binary targets discovered, 1 built, 0 skipped, 7 failed (6m47s wall). The single passing target wasembed_smoke. The state is materially worse than the issue body anticipated — going beyond the originally-flagged Dioxus-desktop / WASM-default-members concerns. CI cannot land onlab-publish.yamluntil the underlying gaps close.Wall 1 —
hero_assistance_serverreal compile failure (49 errors)rusqlitedropped theu64: ToSqlimpl in 0.31 (storage type isi64; SQLite can't represent u64 natively). The handler createslet id = db.last_insert_rowid() as u64;and then tries to pass thatu64back throughrusqlite::params!. Pre-existing source bug — surfaced now because the s49 0.5.0→0.6.0 dep-lift moved rusqlite to a version past 0.31 (likely). Affectsworkspace.rs:108,workspace.rs:148, plus 47 other call sites for a total of 49E0277s.Fix shape: cast
u64 → i64at theparams!boundary, or changeidfield types toi64end-to-end. Mechanical sweep acrosshandlers/workspace.rs. Not a CI concern —cargo builditself fails, no version of CI will help.Wall 2 —
--infocontract not implemented on 4 binariesThe Hero stack convention (per the
herolib_baseskill + thehero_service_check_fixskill) requires every Hero binary to support<bin> --info(and--info --json) which emits a structured manifest derived from an embeddedservice.toml.lab buildruns this after each build as a smoke test:hero_assistance(cli)error: unexpected argument '--info' found(clap-level rejection — flag not defined)hero_assistance_uierror: unexpected argument '--info' foundhero_assistance_adminerror: unexpected argument '--info' foundhero_assistance_app(desktop)--infoaccepted, but binary runs the actual app instead of emitting JSON ("aggregator stream ended")hero_assistance_admin_ui_wasm--infohero_assistance_ui_wasmThree of these (
hero_assistance,_ui,_admin) needservice_base!()macro adoption perherolib_base— which also requires aservice.tomlnext tosrc/main.rs(none exist in this repo today — see Wall 3)._appneeds a sub-flag dispatch where--infoshort-circuits before window boot.Wall 3 — no
service.tomlfiles anywhere in the workspaceEvery other D-10-effective-clean Hero service ships a
service.tomlper crate (4 in hero_cockpit, 3 in hero_onboarding for reference). Theservice_base!()macro reads it viainclude_str!("../service.toml"), and--infoemits its contents as JSON. Adopting the canonical pattern requires writing oneservice.tomlper service-style crate:hero_assistance_server,hero_assistance_ui,hero_assistance_admin,hero_assistance(cli), and possiblyhero_assistance_app.Wall 4 —
lab build --workspacedoes NOT honour[workspace.default-members]Empirically confirmed: lab discovered 8 binary targets including
hero_assistance_admin_ui_wasmandhero_assistance_ui_wasm— which are workspacemembersbut deliberately excluded from[workspace.default-members](Cargo.toml:25-34) because they're wasm32-only and don't make sense on the host target.This is a real
labtooling gap and the answer to the Q in the original issue body. Two ways forward:lab buildhonour[workspace.default-members](correct fix — matchescargo buildsemantics).[package.metadata.lab] skip = trueannotation per WASM crate (or similar opt-out), if lab already supports such a knob.[workspace.members]and split them into a sibling workspace (deviates from the current layout intentionally chosen post-s8).Wall 5 —
policy-mode applyside-effectslab builddefaults to--policy-mode applywhich rewrote 4Cargo.tomls in-place and dropped.hero_builder_backupfiles alongside (and acrates/hero_assistance_sdk/src/generated/directory). I reverted all of this — it's a separate pipeline (hero_assistancehas its own multi-session discipline at CLAUDE.md) and policy edits there belong inside an hero_assistance-pipeline session, not as drive-by mutation from hero_work.If the hero_assistance pipeline picks up the lab-publish work, the very first session should use
--policy-mode warn(audit-only) until the dep policy is understood and intentionally adopted.Recommendation
Close this issue as "blocked / needs upstream work" and re-open scoped under the hero_assistance pipeline once Walls 1-3 are resolved. Specifically:
u64 → i64sweep onworkspace.rs(and likely siblings).hero_service_check_fixskill across all service-style crates. ~1 session of focused work.[workspace.default-members]. Until that lands, the workaround is per-crate metadata or workspace restructuring.Once Walls 1-3 close and Wall 4 has either a knob or workaround, the drop-in
lab-publish.yamllands cleanly per this issue's original goal.Sibling repos status (for context):
Signed-by: mik-tf mik-tf@noreply.invalid
Comprehensive pickup plan for the next session
This comment is the single-source pickup brief for the next session that tackles this issue. Bookmarked from the issue body. Reading order on session start: this comment top-to-bottom, then #issuecomment-35892 for finding detail, then the linked reference files. Everything below is concrete enough to execute from.
Pickup target: this work belongs in the hero_assistance pipeline (
~/.claude/projects/-home-pctwo-Documents-temp-assistance-work/), not hero_work. The hero_work session that filed this issue already did the org-wide rollout for hero_cockpit#3 + hero_onboarding#15 (both landed; CI configured + releases publishing on push). Both close in this session as drive-by drop-ins because their workspaces are convention-clean. This repo is not — the walls below have to close first.Authorship + branching for this work follows this repo's CLAUDE.md (mik-tf, no AI/co-author trailers;
development_<topic>feature branches squash-merged todevelopment). Do NOT inherit hero_work'sSigned-by: mik-tf <mik-tf@noreply.invalid>trailer — that's a hero_work pipeline convention, not this repo's.TL;DR of the pickup
5 walls block the canonical
.forgejo/workflows/lab-publish.yamldrop-in. Wall 1 is a real source compile failure (49 errors) — fixing it unblocks every later phase. Walls 2 + 3 are Hero stack convention adoption (--info+service.toml) per thehero_service_check_fixskill. Wall 4 is an upstreamlabtooling gap (--workspaceignores[workspace.default-members]). Wall 5 is an environment quirk (policy-mode applyrewrites Cargo.toml in-place — use--policy-mode warnduring dev). Estimated 1 focused session if the rusqlite fix is mechanical and Wall 4's mitigation is the lab--packagesflag; 2 sessions if a workspace restructure is needed.What's already been done in the hero_work session (2026-05-22)
lab-publish.yamlto replace tag-triggeredbuild-linux.yaml.lab build --release --install --workspacelocally fromdevelopment_mik— surfaced 5 walls (full detail at #issuecomment-35892).policy-mode applymutations on 4Cargo.tomls + cleaned thecrates/hero_assistance_sdk/src/generated/artifacts. Repo is atorigin/developmentclean.The 5 walls (recap — full detail in #issuecomment-35892)
hero_assistance_serverwon't compile (49 ×u64: ToSql)cargo buildfails--infoservice_base!()adoption per binaryservice.tomlfiles anywhereservice_base!()service.tomlslab --workspaceignoresdefault-memberslab builddefault--policy-mode applymutates Cargo.toml--policy-mode warnduring devPhase plan
The phases are strictly sequential up through Phase 3. Phases 4 and 5 can interleave once Phase 3 has produced a clean local
lab build --release --install --workspace.Phase 1 — Fix the rusqlite
u64: ToSqlcompile failureScope.
crates/hero_assistance_server/src/handlers/workspace.rs(lines 108 + 148 confirmed; 49 totalE0277errors — likely siblings in the same file + related handlers).Root cause.
rusqlite≥ 0.31 removedimpl ToSql for u64(SQLite's storage type isi64;u64can't be losslessly represented). The 0.5.0 → 0.6.0 dep-lift in s49 pulled in a rusqlite version past 0.31. Code currently doeslet id = db.last_insert_rowid() as u64;and then tries to pass thatu64back throughrusqlite::params![input.id].Decision needed (lock at session start). Two fix shapes:
params![input.id as i64]everywhereidfields becomei64end-to-end (struct → handler → JSON)Recommendation: 1a for this session. The id range never exceeds i64::MAX in any realistic scenario (
last_insert_rowid()is i64-native), so the cast is functionally identical. Filing a follow-up issue for 1b lets it land cleanly in a future session that owns the SDK regen.Deliverable. Single commit on
development_<topic>:crates/hero_assistance_server/src/handlers/workspace.rs(and any sibling handler that fails the same way — discover viacargo build --release -p hero_assistance_server 2>&1 | grep -E "u64.*ToSql").Acceptance.
cargo build --releaseexits 0. The Phase 1 unit test that pins the workspace.rs behavior continues to pass (or one gets added if the regression boundary isn't currently pinned).Estimated effort. 1 hour.
Phase 2 — Add
service.tomlto each service-style binaryScope. Five binaries need a
service.tomlnext to theirsrc/main.rs:crates/hero_assistance_servercrates/hero_assistance_ui/rpcproxy +app.sockcrates/hero_assistance_adminadmin.sock+ ip-whitelist gatecrates/hero_assistancecrates/hero_assistance_appSpec source of truth.
hero_service_toml_infoskill defines the schema + typed enums + the mandatory--infocontract. Use the skill's authoritative format; do NOT reverse-engineer from sibling repos.Deliverable. 5 new files under
crates/*/service.toml. Each commits cleanly (single small commit per crate, or one bundled commit per Phase 2 — operator's choice).Acceptance. Every file passes
lab infocheck(the lab tool's smoke check that the embedded toml deserializes against the canonical schema). Reference: hero_skills#265 caveat —lab infocheckonly inspectssrc/main.rs, so if a service has its main atsrc/bin/<name>.rsit'll miss the file. Hero_assistance's structure should be checked at session start.Estimated effort. ~2 hours.
Phase 3 — Wire
service_base!()+ the--infocontract in each binary'smain.rsScope. The macro in
herolib_baseinlines:static SERVICE_TOML: &str = include_str!("../service.toml");static BUILD_NR: u32 = …;(compile-time embedded build number)--infoflag handler that emits the service.toml as structured JSON when called as<bin> --info --json(or human-readable on plain--info)Critical lesson #20 (from CLAUDE.md / s110+s119):
service_base!()hard-codesinclude_str!("../service.toml")which breaks when main lives atsrc/bin/<name>.rs(two-level deep). Workarounds: (a) inline SERVICE_TOML/BUILD_NR with../../service.toml, OR (b) move the bin tosrc/main.rs. Hero_assistance's binary layout needs to be confirmed at session start — if any binary lives atsrc/bin/, choose (b) over (a) forlab infocheckcompatibility.Special handling for
hero_assistance_app(Dioxus desktop). Per the Phase 2 lab probe, this binary's current--inforuns the actual app instead of emitting JSON. Fix shape:The check must precede any blocking init (the current
--infoinvocation produced log output aboutaggregator stream ended— the app was running normally).Deliverable.
crates/*/src/main.rsupdated in each of the 5 binaries. TheCargo.tomlof each needsherolib_base(orservice_base— whichever the skill defines) as a dep at the pinned shared version perrust_versions.Acceptance. Each binary's
--infoand--info --jsonreturns valid output that parses against the schema.lab buildsmoke check passes for all 5.Estimated effort. ~2 hours (mechanical once Phase 2 service.tomls exist).
Phase 4 — Resolve
lab --workspaceiterating WASM crates (Wall 4)The problem. Empirically:
lab build --release --install --workspacediscovers 8 binary targets includinghero_assistance_admin_ui_wasmandhero_assistance_ui_wasm(both aremembersbut excluded from[workspace.default-members]). These are wasm32-only and have no native main; they exit 101 when lab tries--infoon them.Three paths (lock decision before starting Phase 4):
(4a) File upstream lab fix, use per-package workaround in the meantime. File a hero_skills issue: "
lab build --workspaceshould honour[workspace.default-members](matches cargo's semantics, but documented)". Until that lands, use either:lab build --release --install --packages hero_assistance_server,hero_assistance_ui,hero_assistance_admin,hero_assistance,hero_assistance_app(if lab exposes--packages— needs verification; see hero_skills#268)for bin in server ui admin cli app; do lab build --release --install --bin hero_assistance_$bin; doneThe CI workflow YAML would mirror whichever local pattern works.
(4b) Workspace restructure — move the two WASM crates to a sibling workspace at
crates_wasm/. Pros: clean separation; lab can't see them. Cons: bigger commit, touches[workspace.members], may affect existing tooling (themake distflow currently runs from the same root). Effort: ~half-day.(4c) Per-crate
[package.metadata.lab] skip = trueannotation — if lab supports such an opt-out. Cleanest if it exists; needs verification by reading lab's source under hero_skills.Recommendation: 4c if it exists, else 4a. 4b is the safety net if both fail.
Deliverable. Either the
[package.metadata.lab]annotations OR the workflow-level package list OR the workspace split. Either way,lab build --release --install --workspacefrom the repo root should iterate exactly the 5 native-targetable binaries (server, ui, admin, cli, app) — not the 2 WASM crates.Acceptance.
lab build --release --install --workspacefrom a clean checkout discovers 5 binaries, builds 5, fails 0.Estimated effort. 4a: ~1 hour (file the issue, adjust workflow YAML). 4b: ~half-day. 4c: ~1 hour (verify + apply).
Phase 5 — Handle
hero_assistance_appGTK/webkit deps in the CI builder imagePre-flight finding from hero_work session.
webkit2gtk-4.1IS installed on the workstation (probed viapkg-config --exists webkit2gtk-4.1), and the desktop crate built fine locally. The wall is only the CI builder image (ghcr.io/despiegk/builder:latest) which doesn't ship GTK/webkit deps for server-CI workloads.Two options:
(5a) Add an apt-install step to lab-publish.yaml. Insert before the "Build + upload" step:
This deviates from the canonical drop-in shape of hero_slides/cockpit/onboarding workflows. The deviation is principled (one repo has a desktop crate; the other ~33 don't) — file as a known divergence in the commit message and in this issue's closing comment so future readers understand why hero_assistance's workflow isn't byte-identical to the canonical.
(5b) Exclude
hero_assistance_appfrom thelab build --workspaceset entirely; build it separately on a tag-triggered desktop-only workflow. Pros: keeps the canonical workflow byte-identical for hero_assistance's server/ui/admin/cli (the customer-facing pieces). Cons: desktop binary doesn't ship onlatest— only on tagged releases. Acceptable if desktop is a tag-release-only artifact anyway (consistent with how desktop apps are normally distributed).Recommendation: 5a if the team wants the desktop binary on
latest(matches the rest of the Hero binary set's cadence); 5b if the desktop binary is acceptable as a tag-release-only artifact.Deliverable. Modified
.forgejo/workflows/lab-publish.yaml(5a) OR a second tag-triggered workflow file for desktop builds (5b).Acceptance. CI run on a push to
developmentproduces all targeted binaries onreleases/tag/latestwith md5 sidecars.Estimated effort. ~30 min either way.
Phase 6 — Drop in the workflow, remove the old one
Scope.
cp <hero_slides reference> .forgejo/workflows/lab-publish.yaml(with the Phase 5 modification if 5a was chosen). Reference for canonical YAML: hero_slides/.forgejo/workflows/lab-publish.yaml.git rm .forgejo/workflows/build-linux.yaml— superseded.Pre-flight check. Verify
FORGEJO_TOKENis present in this repo's Actions secrets (or inherited org-wide). Both hero_cockpit and hero_onboarding inherited it org-wide and didn't need a per-repo add; this repo should be the same, but worth checking before the run.Deliverable. One commit on
development_<topic>that lands the workflow + removes the old file. Squash-merge todevelopmentper this repo's standing rules.Acceptance.
releases/tag/latestexists on this repo withlinux-musl-x86_64binaries + md5 sidecars for all 5 native-targetable binaries (or 4 if Phase 5b was chosen).Closeskeyword.Estimated effort. 30 min.
Decisions to lock at session start
Don't start writing code until these are nailed down — re-deciding mid-session costs more than the few minutes of upfront discussion. The recommendation column is the hero_work session's read; the operator decides.
latest; 5b otherwiseAnti-patterns to avoid (warnings from sibling sessions)
lab buildwith default--policy-mode apply. Use--policy-mode warnuntil the dep policy is intentionally adopted. (Wall 5.)Signed-by: mik-tf <mik-tf@noreply.invalid>trailer convention. This repo's CLAUDE.md is explicit:mik-tf <logismos@protonmail.ch>, no co-author trailers. Use this repo's pattern.development. This repo's hero-stack-wide rule:git pull && git merge developmentinto the feature branch.git commit -s. Per the Hero stack standing rule, this auto-injectsSigned-off-bywith a real email. Use plaingit commit -m "..."with the message body.lab build --release --install --workspaceis clean. Phase 6 is the last step, not the first. CI is a regression gate, not a build orchestrator.Reference materials (read before starting)
hero_service_check_fixskill — primary recipe for Phases 2 + 3.herolib_baseskill —service_base!()macro +--infocontract.hero_service_toml_infoskill — service.toml schema.rust_versionsskill — pinned dep versions forherolib_baseetc.naming_conventionskill — verify all 5 binary names match the standard before committing.hero_skills#268— org-wide lab-publish rollout context.hero_cockpit/crates/hero_cockpit_server/service.toml— canonical server service.toml.hero_slides/.forgejo/workflows/lab-publish.yaml— canonical workflow YAML (Phase 6 source).Estimated total effort
Acceptance for closing this issue
cargo build --releaseexits 0 from a freshcargo update(Phase 1 closes)lab build --release --install --workspaceexits 0 with 5 (or 4 if 5b) native binaries built + installed (Phases 2-4 close).forgejo/workflows/lab-publish.yamllands ondevelopment;build-linux.yamlis removed in the same commit (Phase 6)releases/tag/latestwith the expected binary set + md5 sidecars (Phase 6)Closing — all 3 acceptance bullets met ✅
Round 1 —
f81aecc(CI run #6, partial)First push landed lab-publish.yaml + 4× service.toml + 4×
service_base!()+git rm build-linux.yaml. CI ran but uploaded only 2/4 binaries before hitting two walls the prior session's local check did NOT catch:u64: ToSqlerrors inhero_assistance_server. Root cause: locallab build --policy-mode warnflags-but-doesn't-rewrite; CI defaults to--policy-mode applywhich silently liftedrusqlite 0.31 → 0.39(where theu64: ToSqlimpl was removed).openssl-syscross-compile failure forhero_assistanceCLI onlinux-musl-x86_64. Root cause:reqwestpulled inhyper-tls → native-tls → openssl-sysvia default features; the canonical builder image doesn't ship musl libssl-dev.Round 2 —
c059c1a(CI run #7, GREEN)Fix-forward closing both walls:
rusqlite 0.31 → 0.39explicitly so local + CI build the same thing; addedas i64casts at everyrusqlite::params!call site that took a u64 expression (49+ sites across 9 handler files; functionally identical — same i64 round-tripped at SELECT time via the existingr.get::<_, i64>(0).map(|v| v as u64)pattern).reqwestto[workspace.dependencies]withdefault-features = false, features = ["json", "rustls-tls"]mirroring hero_cockpit's canonical pattern. Post-swapcargo tree -i openssl-sysshows the dep only reaches_appdesktop +_ui_wasm(both excluded from the CI--packagefilter).Local acceptance gates run before push:
cargo build --release(default-members native) clean in 34scargo build --release --target x86_64-unknown-linux-musl --package <4 CI bins>clean in 1m45s, all 4 produced as static-pie musl ELF64cargo test --releaseworkspace green except pre-existingphase24b_ui_add_access_fails_when_hero_proc_unreachable(environmental — depends on hero_proc NOT being reachable)Acceptance walked
lab build --release --install --workspaceexits 0 locally (via--packagefilter for_server,_ui,_admin,hero_assistance— the deviation from canonical--workspacedocumented in the workflow YAML comment because_appDioxus desktop binary requires glibc-onlywebkit2gtk-sys).forgejo/workflows/lab-publish.yamllands ondevelopment;build-linux.yamlremoved in the same commitreleases/tag/latestshows refreshedlinux-musl-x86_64binaries + md5 sidecars — 8 assets total:(Binaries UPX-compressed by lab-publish.yaml; ~25% of original size, consistent with the org-wide pattern.)
Follow-up — naming-suffix divergence from #13
Canonical asset suffix is now
linux-musl-x86_64. This is INCOMPATIBLE withsvc_install_download's legacy expectation oflinux-amd64. See #13 for the three options (recommended: update svc_install_download in hero_skills to accept both suffixes; aligns with hero_skills#268).Closing this issue.
Signed-by: mik-tf mik-tf@noreply.invalid