279 lines
14 KiB
Markdown
279 lines
14 KiB
Markdown
# 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.`
|
||
- [x] **P1.6** Install systemd service `gitea-act-runner.service` and verify `active (running)` + "Polling" in journal
|
||
- Commit: _system change_
|
||
- Status: `Installed/enabled gitea-act-runner.service; stopped/disabled legacy root act-runner.service; service active running as gitea-runner. Journal shows labels updated to node:20-bookworm and runner bytelyst-host-runner v1.0.6 declared successfully.`
|
||
- [ ] **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 P0–P5 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_ |
|
||
| | | | |
|