harness loop: self-hosting daemon — Redmine SoR drives its own turns

`harness loop` polls the /issues.json intake on an interval (default
120s, --once for cron-style single scans), runs one bounded turn per
new/updated issue — deduped by issue id + updated_on in an append-only
loop.jsonl — then writes the REPORT back as a Redmine journal note,
transitions status per [redmine.status_map] (In Progress -> Done by
name, resolved via /issue_statuses.json), and refreshes the dedup marker
to the post-writeback updated_on so its own notes never re-trigger it.
Turns are sequential (v0); failed turns are recorded, not retried, so a
down proxy cannot hot-loop the poll. The optional Gitea REPORT commit
([gitea] commit_reports, off) rides the same flow. No slot files, no
doorbell screens, no queue scripts — the bash middle layer is replaced,
not wrapped.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
This commit is contained in:
2026-08-28 22:17:03 -05:00
parent c869ac1b06
commit ecc0ee874b
10 changed files with 1359 additions and 22 deletions
+8
View File
@@ -9,4 +9,12 @@ type Task struct {
Prompt string `json:"prompt"`
Class string `json:"class"`
Source string `json:"source"` // "redmine" | "demo"
// UpdatedOn is the Redmine `updated_on` at intake. The `harness loop`
// dedups on issue id + updated_on: an issue update re-releases the
// task; an unchanged issue is never re-dispatched.
UpdatedOn string `json:"updated_on,omitempty"`
// Status is the Redmine status NAME at intake ("In Progress", ...);
// the loop's status map keys off it. Empty for non-Redmine tasks.
Status string `json:"status,omitempty"`
}