@hasna/loops 0.4.26 → 0.4.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -42,6 +42,127 @@ unless noted.
42
42
  execution over the runner protocol, and id-preserving remote import remain
43
43
  follow-up work.
44
44
 
45
+ ## 0.4.18 (2026-07-07/08)
46
+
47
+ Drain reliability: kill the todos-task redispatch "black hole" family, then the
48
+ merge-lane routing wedge and the schema-lockout class behind it. One artifact
49
+ consolidates the whole independently-reviewed family: #82 (dead-letter at the
50
+ cap + attempt refunds + requeue reset + worktree self-heal), #88 (per-task
51
+ repository routing + candidate-window memory), #89 (schema-compat soft-open +
52
+ gate-death ceiling), plus the previously unpublished 0.4.15–0.4.17 ride-alongs
53
+ documented below.
54
+
55
+ ### Fixed
56
+
57
+ - **Merge-lane wedge — the task's own repository wins over a group-root
58
+ `--project-path`:** commit 8ab2664 made the router-level `--project-path` win
59
+ unconditionally in todos-task drains, so multi-repo routers that pass it as a
60
+ concurrency group root (a non-repository directory such as the operator's
61
+ home) sent every task to the group root and skipped it (`worktreeMode=required
62
+ but projectPath is not an existing git repository`), zeroing merge dispatch
63
+ fleet-wide. A drain
64
+ now routes each task to its own first *usable* repository path (explicit
65
+ `project_path`, metadata, the description's `Repository:` line, then
66
+ `working_dir` — first that is a real git repo, probed once per path per tick);
67
+ the router-level `--project-path` remains the rescue fallback for tasks whose
68
+ recorded path is stale or broken (8ab2664's original intent). Registry drains
69
+ are unchanged (the scanned source project still wins; task-controlled fields
70
+ cannot redirect a route).
71
+ - **Route-disallowed tasks no longer burn the candidate window:** tasks bearing
72
+ `no-auto`/`blocked`/`manual`-class tags can never route, but each occupied one
73
+ of the bounded candidate rows every tick just to be rejected by eligibility —
74
+ enough marked tasks starved a drain into `considered=N created=0` forever.
75
+ They are now held out of the window before slicing (unless the drain's own
76
+ `--tags` explicitly selects that tag) and counted as `excludedDisallowedTag`
77
+ in drain reports, so the exclusion is auditable.
78
+ - **Deterministic gate deaths are bounded by a secondary ceiling:** gate deaths
79
+ (runs that fail at worktree prep or a fast triage/planner gate before any real
80
+ work) refund their redispatch attempt — correct for transient faults, but a
81
+ deterministic fault would retry forever at the backoff floor. Work items now
82
+ count consecutive gate deaths (`gate_deaths`, additive migration
83
+ `0011_work_item_gate_deaths`, no schema `user_version` bump); at the ceiling
84
+ (20) the item is dead-lettered — visible in drain reports — instead of
85
+ spinning, and the bounded route re-admission will not requeue it. A
86
+ productive failure or an `exit 75` tempfail (runs that reached the worker)
87
+ resets the streak; `loops routes requeue` (default attempts reset) re-arms
88
+ the full ceiling. Known gap (review finding N1; fix queued for the next
89
+ patch): a non-closing SUCCESS does not yet reset the streak — bounded and
90
+ safe (it errs toward a recoverable early dead-letter, and the redispatch cap
91
+ independently bounds chronically non-closing successes).
92
+ - **Redispatch cap no longer a silent black hole** (the original #82 core: a
93
+ still-actionable task whose runs kept finishing without closing it was
94
+ deduped forever once its attempt count reached the cap): when a todos-task
95
+ work item reaches `MAX_TODOS_TASK_ROUTE_REDISPATCHES` (8) it is transitioned
96
+ to a visible `dead_letter` state instead of being deduped forever with no
97
+ signal. Drain reports gain a `deadLettered` count (and the deduped result
98
+ carries `deadLettered: true` + the reason), so a capped task is surfaced and
99
+ an operator can requeue it rather than the drain silently reporting
100
+ `created=0`.
101
+ - **Gate deaths no longer count toward the cap:** a run that dies before doing
102
+ real work — worktree preparation failure, or a fast (`<60s`) `triage`/`planner`
103
+ gate failure — has its attempt refunded by `finalizeWorkflowRun`, so an infra
104
+ fault cannot dead-letter a task that never reached its worker.
105
+ - **`exit(75)` tempfail is requeueable, not dedupe-bait:** a step that exits 75
106
+ (`EX_TEMPFAIL`, "retry later") drops its work item back to `queued` with the
107
+ attempt refunded, so the "retry next tick" contract fires instead of leaving a
108
+ terminal row that counts toward the cap.
109
+ - **`loops routes requeue` resets attempts by default:** an operator unwedge is
110
+ now durable rather than one-shot (a capped item no longer re-caps after a
111
+ single further terminal run). `--keep-attempts` preserves the count for the
112
+ cautious path; the bounded route-path re-admission still preserves attempts so
113
+ the cap keeps working.
114
+ - **Executor self-heals a stale worktree registration:** on git's "missing but
115
+ already registered worktree" error, `ensureLocalWorktree` (and the remote
116
+ worktree-prep script) now runs `git worktree prune` and retries the add exactly
117
+ once — git's own prescribed remedy — before failing honestly. This removes the
118
+ single biggest burner of the redispatch cap at its source.
119
+
120
+ ### Changed
121
+
122
+ - **Newer-schema databases soft-open when the delta is non-breaking:** an older
123
+ binary used to refuse ANY database with a newer `PRAGMA user_version` — during
124
+ the 2026-07-07 schema-8 lockout that bricked the whole CLI fleet over purely
125
+ additive migrations. The database now carries a compatibility floor
126
+ (`schema_compat.min_compatible_user_version`, raised only by BREAKING
127
+ migrations; additive ones leave it untouched): a binary opens any newer
128
+ database whose floor it meets, preserves the newer `user_version` stamp
129
+ (never downgrades it), and refuses only on a known-breaking delta or when the
130
+ floor row is absent (pre-contract/unblessed databases stay conservative).
131
+
132
+ ## 0.4.15 – 0.4.17 (2026-07-06/07 — unpublished; first shipped with 0.4.18)
133
+
134
+ These three versions were committed to `main` with version bumps but never
135
+ published to npm individually; the 0.4.18 release is the first registry artifact
136
+ that carries them. Consolidated here so the published history stays honest.
137
+
138
+ ### Added
139
+
140
+ - **0.4.15** — self-hosted client mode: the CLI routes loop reads/writes to the
141
+ hosted `/v1` API when `self_hosted` mode is configured (#74).
142
+ - **0.4.16** — id-preserving bulk import endpoint (`POST /v1/import`) for
143
+ self-hosted backfill, plus `loops self-hosted push --apply` in the CLI (#76).
144
+ - **0.4.17** — `GET /v1/loops/count` and `GET /v1/runs/count` endpoints (#77).
145
+ - Run receipt contract: run receipts table + API surface for verifiable run
146
+ evidence (`migrations/0005_run_receipts.sql` mirror).
147
+
148
+ ### Changed
149
+
150
+ - **SQLite schema `user_version` 7 → 8** via ledger migrations
151
+ `0009_run_receipts` and `0010_work_item_machine_id` (additive; applied
152
+ automatically on first open). NOTE: binaries older than this range refuse to
153
+ open a migrated database ("schema version 8 is newer than this binary
154
+ supports"), so downgrading below 0.4.15 after opening a database with this
155
+ release requires restoring a pre-upgrade backup. A version-tolerance softening
156
+ (open unless a known-breaking delta) is planned follow-up work.
157
+ - Launch-gated route drains: `--launch-gate`/`--launch-gate-blocker` hold a
158
+ drain closed until named blocker tasks are completed.
159
+
160
+ ### Fixed
161
+
162
+ - codewith agent JSON output parsing (#17).
163
+ - PR handoff: no-remote fallback repaired and handoff artifact errors scrubbed
164
+ from templates.
165
+
45
166
  ## 0.4.14 (2026-07-06)
46
167
 
47
168
  Self-hosted control-plane service brought to the full Hasna standard: all four
package/README.md CHANGED
@@ -85,6 +85,12 @@ HASNA_LOOPS_DATABASE_URL=... loops-serve migrate --dry-run
85
85
  loops-runner status
86
86
  ```
87
87
 
88
+ `loops self-hosted push` is safe by default: imported workflows are archived and
89
+ imported loops are paused with `nextRunAt`/`retryScheduledFor` cleared. Even
90
+ without `--replace`, the control-plane import boundary may rewrite existing
91
+ same-id workflows/loops into that disabled representation; use explicit
92
+ preserve flags only for an intentional activation.
93
+
88
94
  See [Deployment Modes](docs/DEPLOYMENT_MODES.md) for the full package boundary
89
95
  and machine-placement contract.
90
96