Handoff: promote the heartbeat decision and deploy-key gotcha to durable sections, prune Current state

Current state had grown into a running log of two adjudication cycles. The
2026-07-29 heartbeat drop is a decision, so it lives in Decisions with its
reopen condition; the per-repo deploy-key requirement is a durable gotcha, so it
sits with the Deploy command. What remains is present-tense status plus three
ordered next steps: the orphaned-thread prune fix, triaging this repo's 3 inbox
items, and the 2nd/3rd-repo poll-cycle check.
This commit is contained in:
Keysat
2026-07-29 20:12:51 -05:00
parent 907b83388b
commit e8144ae872
+26 -31
View File
@@ -45,6 +45,9 @@ flat JSON in a writable `state/` mount.
**NVIDIA Sync** alias — host `spark-32d0`, user `modelo`, key-based; injected into `~/.ssh/config` **NVIDIA Sync** alias — host `spark-32d0`, user `modelo`, key-based; injected into `~/.ssh/config`
via an `Include`. `modelo27`/`spark-27ea` is a second Spark on another LAN). `reset --hard` is safe: via an `Include`. `modelo27`/`spark-27ea` is a second Spark on another LAN). `reset --hard` is safe:
`.env`/`config.toml`/`state/` are gitignored. `.env`/`config.toml`/`state/` are gitignored.
**Deploy-key gotcha:** each repo the Spark clones needs its *own* Gitea deploy key plus its own
`Host` alias — Gitea refuses to reuse one SSH key across two repos' deploy keys, and the default
`immense-voyage.local` block already carries matrix-bridge's key.
- **Onboard a repo:** create a Matrix room named like the repo, invite this bot → it auto-joins, - **Onboard a repo:** create a Matrix room named like the repo, invite this bot → it auto-joins,
maps the room to `<owner>/<roomname>` (+ `~/Projects/<roomname>` on the Mac), and posts an maps the room to `<owner>/<roomname>` (+ `~/Projects/<roomname>` on the Mac), and posts an
onboarding message. Pick review agents in-chat: `agents +reviewer +security -adjudicator`. onboarding message. Pick review agents in-chat: `agents +reviewer +security -adjudicator`.
@@ -84,6 +87,13 @@ flat JSON in a writable `state/` mount.
- **Reuse matrix-bridge's Mac wrappers + Spark→Mac SSH key** (don't duplicate the seam). - **Reuse matrix-bridge's Mac wrappers + Spark→Mac SSH key** (don't duplicate the seam).
- **Auto-map by name:** room `<x>` → Gitea `<owner>/<x>` + `~/Projects/<x>`; mapping persists to - **Auto-map by name:** room `<x>` → Gitea `<owner>/<x>` + `~/Projects/<x>`; mapping persists to
`state/` (mirrors matrix-bridge D14). One room per repo. `state/` (mirrors matrix-bridge D14). One room per repo.
- **No wedge-detection heartbeat** (adjudicated 2026-07-29). A healthcheck badge restarts nothing
under this compose setup, the tile that would show it lives in spark-control (so it's a two-repo
change), and serial per-room polling with a 10-min review budget makes any staleness threshold
either too loose to be timely or noisy mid-review. Reopens only on an *observed* wedge **plus**
confirmation the spark-control tile already renders Docker health. The cheaper half of the same
goal is the ROADMAP fold-in: bound the unbounded awaits and die if the poll task dies, so
`restart: unless-stopped` handles it.
## Sovereignty ## Sovereignty
@@ -93,36 +103,21 @@ revisit this — local inference via Spark Control would be the path.
## Current state ## Current state
**LIVE and proven.** Bot runs on the Spark (`docker compose up -d`), `@reviewer` maps each review room **LIVE and in steady use.** The bot runs on the Spark, maps each review room to its repo, and is proven
to its repo, and the subagent panel is configured in-chat. Proven end-to-end on **ten31-site PR #4** end-to-end on **ten31-site PR #4** (2026-06-28): threaded review → `merge` + `yes` → force_merge →
(2026-06-28): threaded review → `merge` + `yes` → force_merge → auto-publish → thread redacted — and auto-publish → thread redacted, with headless `claude -p` genuinely spawning the reviewer / adjudicator /
the previously-unproven bit, **headless `claude -p` spawning the reviewer/adjudicator/security security subagents. ten31-site is the only repo onboarded so far.
subagents, works**. The ten31-site colleague is onboarded; the pipeline is in steady use.
Deployed to the Spark at `063e694`: a merge always redacts its thread on success, and a failed Running on the Spark at `063e694` (a merge always redacts its thread; a failed post-merge deploy warns at
post-merge deploy posts its "deploy manually" warning at top level so it survives the redaction top level rather than orphaning one; `clear`/`resolve` clears an orphan without touching the PR). `master`
instead of orphaning the thread. `clear`/`resolve` redacts an orphaned thread without touching the PR. is only docs ahead of that, so **no redeploy is pending**. No test suite: verification means exercising
the bot in a real review room.
**Deploy gotcha (still true):** the Spark needs a *dedicated* per-repo Gitea deploy key + a `Host` **Next steps, in priority order:**
alias (the default `immense-voyage.local` block uses matrix-bridge's key); Gitea won't reuse one SSH 1. **Fix the orphaned-thread prune** (`src/bot.py` ~L594): the poll loop drops a PR's thread root from
key across repos' deploy keys. Redeploy via the Spark Control tile, or `ssh modelo32`. state when the PR leaves the open list *without redacting*, so a PR merged or closed in the Gitea web
UI strands its thread and `clear` can no longer reach it. Redact before dropping the root.
**Known issue / next fix (the concrete next step):** the poll loop prunes a PR's thread root from 2. **`/triage` the 3 untriaged inbox items** tagged for this repo — adjudication never reads the inbox, so
state when it leaves the open list (`src/bot.py` ~L594) *without redacting*, so a PR merged or closed their content is still unknown here.
**outside** the bot (the Gitea web UI) still orphans its thread, un-redactable by the bot afterward. 3. Onboard a 2nd/3rd repo, then watch one poll cycle (`docker compose logs -f`) for a long review
The merge-redact fix covers bot-driven merges only; the prune should redact before dropping the root. head-of-line-blocking the next room — ROADMAP Phase 3's verify item, and the real scaling limit.
**Backlog adjudicated 2026-07-18** (`9adcdc8`): ROADMAP is down to one phase. Phase 2 (subagent panel,
`agents +/-`) deleted as finished; Phase 4 deleted because spark-control has shipped this bot's tile
since v0.28.0; deploy-on-a-non-static-repo dropped (no repo needs it, and the deploy step is hardcoded
to the static-site publish script, so a per-repo deploy-command field would have to come first).
That left two items: onboard 3 repos, and a wedged-loop heartbeat.
**Backlog adjudicated 2026-07-29:** the heartbeat is **dropped** — a healthcheck badge doesn't restart
anything here, spark-control's tile would need its own change to read it, and serial per-room polling
(a review may run 10 min) makes any staleness threshold either too loose to be timely or noisy
mid-review; no wedge has ever been observed. Reopens only on an *observed* wedge **plus** confirmation
the tile already renders Docker health. In its place ROADMAP carries a **fold-in**: bound the two
unbounded awaits in `src/bot.py` (`await proc.wait()` after the timeout kill in `ssh_run`;
`client.room_send` in `say()`) and stop the process if the poll task ever dies, so
`restart: unless-stopped` + the tile cover it. Phase 3's onboard-3-repos verify item stands.