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

13 KiB
Raw Blame History

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.


🎯 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

  • 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.
  • 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.
  • P0.3 Human confirmed registration scope (instance-level recommended)
    • Commit: none
    • Status: <scope confirmed: instance | org | repo>
  • P0.4 Human confirmed E2E throwaway-package consent
    • Commit: none
    • Status: <yes/no, and any constraints>

P1 — Install act_runner on Hostinger VM

Detail: §4 of runner setup doc

  • P1.1 Create gitea-runner user (idempotent; docker group)
    • Commit: system change, not git
    • Status: ``
  • P1.2 Download act_runner binary, SHA256-verify, install to /usr/local/bin/
    • Commit: system change
    • Status: <version installed, e.g., v0.2.10>
  • P1.3 Obtain registration token from Gitea (instance level)
    • Commit: none (token in memory only)
    • Status: <token length confirmed nonzero>
  • P1.4 Register runner with config.yaml (Docker mode, node:20-bookworm label mapping)
    • Commit: system change
    • Status: <runner name: hostinger-bytelyst-1, labels: ...>
  • P1.5 Mount ~/.gitea_npm_token to gitea-runner (mode 600)
    • Commit: system change
    • Status: <copied from <user>, owner gitea-runner:gitea-runner, mode 600, bytes=...>
  • 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

  • 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

  • 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

  • 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

  • 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