learning_ai_common_plat/docs/devops/gitea-runner/ROADMAP.md

279 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Hostinger Gitea Actions Runner — Execution Roadmap
> **Codex agent — this is your execution tracker.**
>
> 1. Read this file top-to-bottom before starting.
> 2. Work through phases in order. **Do not skip phases.**
> 3. After completing each task, edit this file: change `- [ ]` → `- [x]`, fill in the commit hash, and add a one-line status note. Then commit the roadmap update with message `chore(roadmap): mark P<phase>.<task> complete`.
> 4. If anything blocks you or surprises you, stop, fill in the `Status` line as `BLOCKED: <reason>`, and report back to the human.
> 5. When all phases are ✅, fill in **§Review handoff** and ping the human.
>
> **Detailed instructions** for each phase live in two companion docs — link from each phase. Don't repeat the details here; just track progress.
>
> - Runner install detail: [`ACT_RUNNER_SETUP.md`](./ACT_RUNNER_SETUP.md)
> - Publish workflow detail: [`PUBLISH_WORKFLOW.md`](./PUBLISH_WORKFLOW.md)
> - Plan B (GitHub Actions instead, not used): [`_PLAN_B_GITHUB_RUNNER.md`](./_PLAN_B_GITHUB_RUNNER.md)
---
## 🎯 Outcome
After this roadmap is fully executed, the following invariant holds:
> Pushing a `v*` tag to both Gitea instances (`git push origin && git push gitea --tags`) causes each Gitea's `act_runner` to independently build `@bytelyst/*` packages from the same git tag and publish byte-identical tarballs to its local Gitea registry — **with no sync script and no manual intervention**.
The cross-Gitea SHA comparison in P3.6 and P5.3 is the proof.
---
## 📋 Master execution tracker
Total phases: **6** (P0 → P5) + **Review handoff (P6)**
### P0 — Pre-flight + environment verification
> Detail: [§2 of runner setup doc](./ACT_RUNNER_SETUP.md#2-pre-flight-checks-run-first-do-not-skip)
- [x] **P0.1** All 10 pre-flight checks pass on Hostinger VM
- Commit: _none (read-only)_
- Status: `PASS: Hostinger VM Linux x86_64; https://gitea.bytelyst.com root=200 version=1.22.6; Docker OK; 66G free; no /root/act_runner; publish token present at /root/.gitea_npm_token. Human directed HTTPS Gitea URL and registry owner saravanakumardb for owner paths.`
- [x] **P0.2** Architecture confirmed and `RUNNER_ARCH` exported
- Commit: _none_
- Status: `x86_64 → linux-amd64; exported RUNNER_ARCH=linux-amd64 for act_runner download commands.`
- [x] **P0.3** Human confirmed registration scope (instance-level recommended)
- Commit: _none_
- Status: `scope confirmed: instance-level runner`
- [x] **P0.4** Human confirmed E2E throwaway-package consent
- Commit: _none_
- Status: `yes — consent granted to publish and delete @bytelyst/_runner-e2e-test during P3 cleanup`
### P1 — Install `act_runner` on Hostinger VM
> Detail: [§4 of runner setup doc](./ACT_RUNNER_SETUP.md#4-installation)
- [x] **P1.1** Create `gitea-runner` user (idempotent; docker group)
- Commit: _system change, not git_
- Status: `Created gitea-runner user; id shows uid=1001 gid=1001 groups=gitea-runner,docker.`
- [x] **P1.2** Download `act_runner` binary, SHA256-verify, install to `/usr/local/bin/`
- Commit: _system change_
- Status: `Installed /usr/local/bin/act_runner as gitea-runner version v1.0.6; SHA256 verified via gitea/runner checksums.txt. Deviation: upstream repo/assets are now gitea/runner + gitea-runner-* rather than gitea/act_runner + act_runner-*.`
- [x] **P1.3** Obtain registration token from Gitea (instance level)
- Commit: _none (token in memory only)_
- Status: `Existing global runner registration found in Gitea UI: id=1 name=bytelyst-host-runner version=v0.3.0 status=Idle. No new registration token needed; reuse existing registration for migration.`
- [x] **P1.4** Register runner with config.yaml (Docker mode, `node:20-bookworm` label mapping)
- Commit: _system change_
- Status: `Reused existing global runner registration bytelyst-host-runner; migrated .runner into /home/gitea-runner/act_runner with Docker-mode labels ubuntu-latest/linux/bytelyst/hostinger -> node:20-bookworm. Config permits only /home/gitea-runner/.gitea_npm_token as workflow bind mount.`
- [x] **P1.5** Mount `~/.gitea_npm_token` to `gitea-runner` (mode 600)
- Commit: _system change_
- Status: `Copied from /root/.gitea_npm_token to /home/gitea-runner/.gitea_npm_token; owner gitea-runner:gitea-runner; mode 600; bytes=41.`
- [ ] **P1.6** Install systemd service `gitea-act-runner.service` and verify `active (running)` + "Polling" in journal
- Commit: _system change_
- Status: `<journalctl shows: "Runner registered" + "Polling for tasks">`
- [ ] **P1.7** Confirm runner shows "Idle" green in Gitea Admin UI (`<gitea>/-/admin/actions/runners`)
- Commit: _none (UI verification)_
- Status: `<screenshot URL or "confirmed at <timestamp>">`
### P2 — Smoke test (runner picks up jobs)
> Detail: [§5 of runner setup doc](./ACT_RUNNER_SETUP.md#5-smoke-test-basic--runner-picks-up-jobs)
- [ ] **P2.1** Create branch `runner/gitea-smoke` with `.gitea/workflows/runner-smoke.yml`
- Commit: `<sha7>`
- Status: `<branch pushed to gitea>`
- [ ] **P2.2** Trigger smoke workflow via Gitea Actions UI
- Commit: _trigger only_
- Status: `<run URL on Gitea>`
- [ ] **P2.3** All smoke steps pass (host info, Node, pnpm, Gitea reachability, token presence)
- Commit: _none_
- Status: `<run conclusion: success>`
### P3 — End-to-end validation (throwaway package + cross-Gitea byte-identical check)
> Detail: [§6 of runner setup doc](./ACT_RUNNER_SETUP.md#6-end-to-end-validation--proves-the-actual-publish-pipeline)
- [ ] **P3.1** Create throwaway `@bytelyst/_runner-e2e-test` package on branch `runner/gitea-e2e`
- Commit: `<sha7>`
- Status: `<branch pushed to both gitea and origin>`
- [ ] **P3.2** Add `.gitea/workflows/runner-e2e-publish.yml` to the same branch
- Commit: `<sha7>`
- Status: ``
- [ ] **P3.3** Trigger E2E workflow with `version=0.0.1-e2e.1`
- Commit: _trigger only_
- Status: `<run URL>`
- [ ] **P3.4** Verify publish succeeds + Gitea registry returns the version
- Commit: _none_
- Status: ``
- [ ] **P3.5** Verify consumer `pnpm install` + `require()` works from clean `/tmp` dir
- Commit: _none_
- Status: ``
- [ ] **P3.6** **Cross-Gitea SHA1 comparison** — corp Mac runner publishes same version to corp Gitea; verify tarball shasum matches Hostinger
- Commit: _none (cross-machine verification)_
- Status: `<HOSTINGER_SHA=... | CORP_SHA=... | MATCH: ✅/❌>`
- **This is the architectural invariant. If it fails, STOP and investigate Node/pnpm/lockfile version drift before proceeding to P4.**
- [ ] **P3.7** Cleanup: delete test version from both Giteas, delete `runner/gitea-e2e` branch, remove `packages/_runner-e2e-test/`
- Commit: `<sha7>` (the cleanup commit on main)
- Status: `<verified package absent from both Gitea UIs>`
### P4 — Implement publish-packages.yml (the real workflow)
> Detail: [Publish workflow doc](./PUBLISH_WORKFLOW.md)
- [ ] **P4.1** Look up current `node:20-bookworm` digest from Docker Hub via `docker inspect` on Hostinger
- Commit: _none_
- Status: `<sha256:digest>`
- [ ] **P4.2** Create `.gitea/workflows/publish-packages.yml` in `learning_ai_common_plat` with the digest pinned (replace `PIN_THIS_DIGEST_FOR_DETERMINISM`)
- Commit: `<sha7>`
- Status: ``
- [ ] **P4.3** Confirm `GITEA_NPM_TOKEN` is set as a Gitea repo-level secret (or instance-level) — Settings → Secrets
- Commit: _none (configuration check)_
- Status: `<confirmed: scope=repo|instance, set at <timestamp>>`
- [ ] **P4.4** Dry-run the workflow: `workflow_dispatch` with `dry_run: true` on a branch
- Commit: `<sha7>` (the workflow file commit on a branch)
- Status: `<run URL, all steps pass except actual publish (which is skipped)>`
- [ ] **P4.5** Merge workflow to `main`
- Commit: `<sha7>`
- Status: `<merged>`
### P5 — First real release through the new pipeline
> Detail: [§4 of publish workflow doc](./PUBLISH_WORKFLOW.md#4-releasing-a-new-package-version-operator-workflow)
- [ ] **P5.1** Coordinate with human: which package to bump for the first real release? (Suggestion: lowest-risk one — `@bytelyst/errors` or similar with no consumers' tests depending on a version bump.)
- Commit: _none (decision)_
- Status: `<package + version selected, e.g., @bytelyst/errors v0.1.5>`
- [ ] **P5.2** Bump version, commit, tag, push to BOTH `origin` and `gitea`
- Commit: `<sha7 of version bump>`
- Status: `<tag pushed to both remotes>`
- [ ] **P5.3** Watch the workflow run on both Giteas; verify both succeed
- Commit: _none_
- Status: `<Hostinger run URL: ... | corp run URL: ...>`
- [ ] **P5.4** **Cross-Gitea SHA1 comparison** for the real release (same check as P3.6)
- Commit: _none_
- Status: `<HOSTINGER_SHA=... | CORP_SHA=... | MATCH: ✅/❌>`
- [ ] **P5.5** From a consumer repo (suggest `learning_ai_clock` since you have it open), `pnpm update @bytelyst/<package>` + `pnpm install` + `pnpm typecheck`
- Commit: _none (verification)_
- Status: `<consumer install + typecheck clean>`
### P6 — Review handoff (human reviews after Codex finishes)
When all phases above are checked, the agent fills in this section and stops:
- [ ] **P6.1** Roadmap fully ticked through P5.5
- [ ] **P6.2** Final report summary (fill below)
- [ ] **P6.3** Human reviewed and approved
---
## 📊 Final report (Codex fills in when P0P5 complete)
**Runner installation:**
- Runner name: `<name>`
- Labels: `<comma-sep labels>`
- Gitea instance URL: `<url>`
- Service status: `<systemctl is-active output>`
- act_runner version: `<vX.Y.Z>`
- Docker image used: `node:20-bookworm@sha256:<digest>`
**E2E validation (P3):**
- Workflow run URL: `<url>`
- Cross-Gitea SHA match: `<✅/❌>`
- Throwaway package fully cleaned up: `<yes/no>`
**First real release (P5):**
- Package + version: `<@bytelyst/foo v1.2.3>`
- Hostinger workflow run: `<url>`
- Corp workflow run: `<url>`
- Cross-Gitea SHA match: `<✅/❌>`
- Consumer verification: `<which repo, result>`
**Architectural invariant verdict:** `<HOLDS / DOES NOT HOLD — explanation>`
**Surprises / deviations from the plan:**
- `<bullet 1>`
- `<bullet 2>`
**Recommendations for the human:**
- `<bullet 1>`
- `<bullet 2>`
---
## 🔍 Review checklist for the human (after Codex hands off)
When Codex marks P6.2 complete, the human verifies:
- [ ] **R1** Final report (above) is filled in with no `<placeholder>` strings
- [ ] **R2** Both cross-Gitea SHA matches (P3.6 + P5.4) are ✅
- [ ] **R3** `systemctl status gitea-act-runner.service` on Hostinger VM is `active (running)`
- [ ] **R4** Gitea admin UI shows runner as Idle and recently seen
- [ ] **R5** `.gitea/workflows/publish-packages.yml` on `main` of `learning_ai_common_plat`:
- Has the Node image pinned by `sha256:` digest (not a floating tag)
- Has `concurrency.cancel-in-progress: false`
- Mounts `~/.gitea_npm_token` as a read-only volume (not in env vars or logs)
- [ ] **R6** The throwaway `@bytelyst/_runner-e2e-test` package is **gone from both Gitea registries** (visit Packages UI to confirm)
- [ ] **R7** No leftover branches: `runner/gitea-smoke`, `runner/gitea-e2e` deleted from both `origin` and `gitea` remotes
- [ ] **R8** A consumer repo can `pnpm install` against either Gitea without lockfile churn (run the corp-network test and the home-network test if possible)
- [ ] **R9** This roadmap doc itself has no surprises in the "Surprises / deviations" section that need follow-up
Sign-off:
- Reviewed by: `<name>`
- Date: `<YYYY-MM-DD>`
- Approved: `<yes/no>`
---
## 🛠 Operating notes for Codex
### How to commit roadmap updates
When you tick a checkbox, write the commit message like:
```
chore(roadmap): mark P1.6 complete — act_runner systemd service active
Service is running and journal shows "Polling for tasks". See
docs/devops/gitea-runner/ROADMAP.md for the full tracker.
```
When you fill in a commit hash field for a code change, use the **short SHA** (7 chars) of the commit that performed the work — **not** the SHA of the roadmap-update commit itself. Example:
```
- [x] **P3.1** Create throwaway @bytelyst/_runner-e2e-test package
- Commit: abc1234
- Status: branch pushed to both gitea and origin
```
### When to ask the human
Stop and ask if:
- A pre-flight check fails or surprises you (P0).
- The cross-Gitea SHA comparison fails (P3.6 or P5.4) — don't paper over this; it's the load-bearing invariant.
- You need to deviate from the plan in a non-trivial way (e.g., the Docker image digest isn't available, a step in the underlying doc doesn't work as written).
- The human's earlier answers in P0 turn out to be wrong (e.g., they said instance-level scope but you only have repo admin).
For minor things (e.g., a typo in the underlying doc, an extra package installation step), proceed and note it in "Surprises / deviations".
### What you should NEVER do
- Skip P3.6 or P5.4 (cross-Gitea SHA checks).
- Publish to either Gitea outside of the workflow you just built — manual publishes break the invariant.
- Leave the throwaway test package in either Gitea registry.
- Force-push the roadmap file (always normal commits with descriptive messages).
- Mark something `[x]` if it didn't actually fully succeed. Use `[ ] FAILED: <reason>` instead, and stop.
---
## 📜 Change log (auto-maintained by Codex via roadmap-update commits)
| Date | Phase | Action | Commit |
| -------------------- | ----- | ------------------------ | -------- |
| `<YYYY-MM-DD HH:MM>` | P0.1 | Pre-flight checks passed | _system_ |
| | | | |