ops(archive): TASK prompts and REPORT verifications, studies through V1
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
# REPORT — self-host core: `harness loop` replaces the bash stack — 2026-08-28 21:31
|
||||
|
||||
Deliverable for "get to be self hosting asap — smallest core that can
|
||||
bootstrap itself (redmine/gitea interaction fine, discourse later)".
|
||||
Pushed to ukrrs/MOPAC main as
|
||||
`86c39c8` (module rename) → `c869ac1` (keyproxy/config) → `ecc0ee8`
|
||||
(loop daemon) → `2901bb8` (docs + dev.sh loop runner).
|
||||
|
||||
## What runs now
|
||||
|
||||
The MOPAC harness (Go, stdlib only, built in the digest-pinned Docker
|
||||
builder — host stays toolchain-free) drives ITSELF. Redmine is the SoR,
|
||||
the conductor is the worker. Per issue in the released scope whose
|
||||
(id, updated_on) has not been processed:
|
||||
|
||||
1. one bounded turn (same conductor `harness once` uses; sequential,
|
||||
one at a time — v0, no concurrency knob yet);
|
||||
2. REPORT file lands in `reports/` (as before);
|
||||
3. REPORT body is POSTed back onto the issue as a Redmine journal note
|
||||
(the previously-stubbed note writeback is now implemented);
|
||||
4. status transitions per `[redmine.status_map]` (default shipped:
|
||||
`"In Progress" = "Done"`; names resolved via `/issue_statuses.json`);
|
||||
5. optional Gitea REPORT commit (`[gitea] commit_reports`, OFF by
|
||||
default);
|
||||
6. dedup marker refreshed to the post-writeback `updated_on`, so the
|
||||
loop's own note never re-triggers itself (self-retrigger hazard
|
||||
handled + test-asserted).
|
||||
|
||||
State: append-only `state/loop/loop.jsonl` — one JSON line per action
|
||||
(dispatch / report / note / status / commit / refresh / error), dedup
|
||||
index rebuilt at startup, restarts keep exactly-once-reaction semantics.
|
||||
One line per action goes to stdout as well. A FAILED turn is recorded,
|
||||
NOT retried (update the issue to re-release it) — a down proxy cannot
|
||||
hot-loop the poll.
|
||||
|
||||
Secrets: `key_ref = "mpk:mpk-redmine"` style refs resolve through
|
||||
mopac-keyproxy `POST /v1/resolve` (bearer from `[keyproxy] token_ref`,
|
||||
60s in-memory cache). `env:`/`file:`/`literal:` refs keep working, so
|
||||
the loop runs with or without keyproxy up. No hosts hardcoded — all in
|
||||
harness.toml. Also folded in: module renamed
|
||||
`git.knownelement.com/reachableceo/MOPAC/harness` → `ukrrs.com/mopac/harness`
|
||||
(the doc-rot finding), verified build+vet+test in the builder.
|
||||
|
||||
Tests: loop end-to-end against a fake Redmine (mutable: notes bump
|
||||
updated_on like the real SoR) + fake OpenAI server — dispatch/note/
|
||||
status happy path, dedup on rescan, re-dispatch on issue update, failed
|
||||
turn without hot-loop, dry-run zero-trace, restart dedup survival,
|
||||
status-map miss, gitea create/update, keyproxy 401/404/cache. Full
|
||||
`./dev.sh check` (build + vet + test) clean on go1.26.
|
||||
|
||||
## Exact command to start the loop
|
||||
|
||||
From `/home/reachableceo/projects/meta/MOPAC/harness` (harness.toml is
|
||||
already in place; it is gitignored):
|
||||
|
||||
./dev.sh build
|
||||
HARNESS_REDMINE_KEY=<key> HARNESS_LITELLM_KEY=<vertical virtual key> \
|
||||
./dev.sh loop
|
||||
|
||||
That runs the daemon in the Docker builder container with the repo
|
||||
bind-mounted (REPORTs + state land in the repo). Verify first with a
|
||||
zero-cost scan:
|
||||
|
||||
HARNESS_REDMINE_KEY=<key> HARNESS_LITELLM_KEY=<key> \
|
||||
./dev.sh loop --dry-run # prints "would dispatch <id>" per new issue, no turns, no state
|
||||
./dev.sh loop --once # single scan (cron-able), exit 2 if the intake itself fails
|
||||
|
||||
Stop: Ctrl-C (SIGINT) in the foreground, or `docker stop mopac-loop`.
|
||||
Interval default 120s (`[loop] poll_interval_secs`), override with
|
||||
`-interval 60s`. With keyproxy up instead of env keys:
|
||||
`[keyproxy] url/token_ref` in harness.toml + `mpk:` refs (see
|
||||
harness.toml.example, all commented).
|
||||
|
||||
## What it replaces — the die list (NOT deleted yet, pending your sign-off)
|
||||
|
||||
1. `/home/_crossfeed/tooling/agent-stack/semaphore.sh` + slot-file
|
||||
concurrency cap → replaced by the loop's in-process discipline
|
||||
(v0: one turn at a time; concurrency knob later if load justifies).
|
||||
2. `~/.coordinate/scripts/queue-next.sh`, `queue-after.sh`,
|
||||
`pmo-heartbeat.sh` → replaced by the loop + its own wake discipline
|
||||
(poll interval; `--once` for cron). The heartbeat screen
|
||||
(`pmo-heartbeat`, PID 2924085) can be killed whenever you say so.
|
||||
3. `dispatch-turn.sh` doorbell `screen -S reachableceo-PMO -X stuff` —
|
||||
note: ALREADY dead. The screen is named `RCEO-PMO`, so the message
|
||||
was silently dropped all along. Mentioned for the record; deletion
|
||||
after your sign-off.
|
||||
|
||||
Nothing in `/home/_crossfeed` or `~/.coordinate/scripts` was touched
|
||||
this turn. `harness once` (manual/chained path) also unchanged in
|
||||
behavior — file-only writeback, no notes.
|
||||
|
||||
## Rollback
|
||||
|
||||
Just stop the loop (`Ctrl-C` / `docker stop mopac-loop`). The bash stack
|
||||
is fully present and untouched — relaunch it exactly as before. The only
|
||||
new artifacts are `state/loop/loop.jsonl` (delete to forget all dedup
|
||||
history) and REPORT files. No config the old stack reads was modified.
|
||||
|
||||
## Suggested verification (PMO)
|
||||
|
||||
1. `./dev.sh loop --dry-run` with the real Redmine — should list the
|
||||
released-scope issues it would dispatch, zero LLM calls.
|
||||
2. Pick one low-stakes issue, drop it to "In Progress" in scope, run
|
||||
`./dev.sh loop --once` with keys: expect turn → REPORT file →
|
||||
journal note on the issue → status → Done.
|
||||
3. Check `state/loop/loop.jsonl` for the one-line-per-action trail.
|
||||
|
||||
— Work stack, 2026-08-28 ~22:30
|
||||
Reference in New Issue
Block a user