@agentskit/harness 0.12.0 → 0.14.0

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
@@ -1,5 +1,100 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.14.0] - 2026-09-19
4
+
5
+ A queue that several machines can drain, a review whose strictness matches the risk, and four fixes that
6
+ were sitting unpublished. Motivated by a real 24/7 loop that had been silently doing nothing: the config
7
+ was invalid, the queue asked for the wrong assignee, and the diagnostic misnamed its own subject.
8
+
9
+ ### The queue stops being "my issues"
10
+
11
+ - **`linear.queueOwnership`** (`person` | `unassigned`, default `person`, nothing changes unless you opt
12
+ in). Under `unassigned` the queue lists with `--assignee null` and the assignee becomes a **transient
13
+ claim**: written right after a dispatch succeeds, cleared when the item comes back. That is what lets
14
+ several machines share one priority-ordered queue without two of them picking the same issue.
15
+ The claim is non-fatal and gets its own `queue.claim-failed` event — what actually removes an issue from
16
+ the queue is the status transition, so a failed claim must not cost the transition or the comment.
17
+ - **`linear.anyLabels`** — "at least one of these" (OR), because `requireLabels` is AND: listing two
18
+ layers there demands both on the same issue and matches **nothing**. A queue that returns zero is
19
+ indistinguishable from "no work to do", which is the worst failure mode this loop has.
20
+ - `loop doctor` now says **which** queue it read. Under `unassigned` ownership it used to print
21
+ "for \<person\>" — the opposite of what it listed, and that is how an empty queue goes unnoticed.
22
+
23
+ ### Review strictness that matches the risk
24
+
25
+ - **`reviewOverrides`** — stricter review for the slices that deserve it, keyed by label. First match
26
+ wins and only the named fields are replaced: an override that raises `votes` must not silently reset
27
+ the deadline or swap the CLI. The matched label travels to the deliver log, because a gate that costs
28
+ more without explaining itself reads as a bug.
29
+ - The labels come from the **dispatch record**, not a fresh Linear read, so editing a label mid-flight
30
+ cannot change the gate a running item is judged by.
31
+
32
+ ### Telling the worker the truth about the base branch
33
+
34
+ - **`knownFailures`** — suites already red on the base, declared with the tracking issue (mandatory: a
35
+ quarantine without an owner becomes permanent). The harness does **not** run `verifyCommand` — the
36
+ worker does, in its own worktree — so tolerating known breakage is information in the brief, not output
37
+ parsing. Without it, every item touching a broken package fails verification for someone else's defect.
38
+
39
+ ### Memory: recurrence instead of guesswork
40
+
41
+ - Learning ids are content-derived, so a lesson that reappeared was silently deduplicated and a pattern
42
+ looked exactly like a one-off. **`sightings` now counts**, and `loop retro` offers the lessons that hit
43
+ `memory.recurrence.minSightings` with the promote command already filled in.
44
+ - Promotion still requires a human (`HUMAN_APPROVAL_REQUIRED`, ADR-0019). Memory is read into every
45
+ worker brief: a wrong lesson promoted without a human is a wrong instruction on every future task.
46
+
47
+ ### One human approval covers the goal's own effects
48
+
49
+ - **`tracking.authorization`** (`goal` | `separate`, default `goal`). Approving the verification result
50
+ now authorizes the declared external effect too, recording `authorization.recorded` at the same
51
+ instant. `separate` keeps the old two-gate behaviour.
52
+
53
+ ### Fixes that had never shipped
54
+
55
+ - Phase age and worker age are different numbers: `ageMin` counts from dispatch, `phaseAgeMin` from the
56
+ event that started the phase. An item in review for 10 minutes used to show the dispatch age and looked
57
+ stuck for hours.
58
+ - Stale delivery state is reset on redispatch, dead stage locks recover, queue alerts are ignored during
59
+ scheduled stages, and expected pre-PR delivery gaps stop being reported as problems.
60
+
61
+ ## [0.13.0] - 2026-09-14
62
+
63
+ A full-codebase test-coverage sweep (every module in `src/kernel/`, `src/execution/`, `src/adapters/`, and most of
64
+ `src/loop/` brought to 90%+ statements/branches) that surfaced eight real bugs along the way, each fixed in its own
65
+ focused PR rather than folded silently into a test change.
66
+
67
+ - **Per-issue state files are now written atomically**: `dispatch.json`, `delivery.json`, and `contract.json` were
68
+ each written with a plain `writeFileSync` straight to the final path. `tick` and `deliver` run as separate
69
+ scheduled processes against the same state directory, and `readDeliveryState` already treats malformed JSON as
70
+ "no state yet" rather than erroring — so a crash mid-write or a read racing a write could silently reset
71
+ `fixRounds`/`nudges`/`finalOutcome` instead of surfacing the corruption. Consolidated the three duplicated unsafe
72
+ writes into one shared `src/loop/fs-atomic.ts` (temp file + atomic rename).
73
+ - **`events.ndjson` rotation is now serialized**: `appendLoopEvent`'s size-based rotation (`statSync` →
74
+ `renameSync` → `appendFileSync`) had no lock, so two scheduled processes rotating the same file near-
75
+ simultaneously could overwrite one process's archive or drop events. Only the rotation decision is now gated
76
+ behind a lock file; a busy lock skips rotation for that call rather than racing it, and a lock older than 5s is
77
+ treated as an abandoned crash artifact and cleared.
78
+ - **PII scanner recognizes current-format secrets**: added `sk-proj-...` (current OpenAI project keys), fine-
79
+ grained GitHub PATs, Google API keys, Stripe live keys, PEM private-key blocks, and the AWS secret-access-key
80
+ half (previously only the `AKIA` access-key id was matched).
81
+ - **`Ctrl-C` now actually stops `loop watch`**: its SIGINT handler only set `process.exitCode` without calling
82
+ `process.exit()`, so the long-running poll loop (and its `gh`/`orca` shell-outs) kept running in the background
83
+ after a cancelled watch.
84
+ - **Raw throws reclassified as `HarnessError`**: `retro.ts`'s `--since` parsing and `doc-bridge.ts`'s index
85
+ freshness/readability checks threw plain `Error`, so these bad-input/bad-state failures fell through the CLI's
86
+ generic exit-1 catch-all instead of the classified exit-code path every other validation failure uses.
87
+ - **Fixed two `execution/agent.ts` session-recorder bugs**: a dead `executing` Set that could never affect
88
+ control flow (removed), and a structurally-invalid-but-non-throwing runtime result that was being swallowed into
89
+ a generic, retryable `RUNTIME_ERROR` instead of surfacing as its own distinct failure.
90
+ - **`findExecutable` now checks the execute bit**: a non-executable regular file sitting on `PATH` with a matching
91
+ name was reported as a runnable binary, only to fail with `EACCES` at actual spawn time.
92
+ - **`loop debrief --issue X` no longer returns an empty report** for a normal, not-yet-dispatched issue: the
93
+ "always include an explicitly requested issue" fast path was shadowed by an unconditional second skip check
94
+ right after it.
95
+
96
+ Everything else in this release is test-only: no other production behavior changed.
97
+
3
98
  ## [0.12.0] - 2026-09-13
4
99
 
5
100
  Closes gaps found reusing Orca instead of reinventing it. Orchestration mutations (`run-create`, `task-create`,
package/README.md CHANGED
@@ -36,7 +36,7 @@ ak-harness doctor --json
36
36
  ak-harness plan approved --by human
37
37
  ak-harness start
38
38
  ak-verify run --json
39
- ak-verify approve <run-id> approved --by human --json
39
+ ak-verify approve approved --by human --json
40
40
  ak-harness cancel <run-id> --by human --reason "Requirements changed"
41
41
  ak-harness benchmark --manifest benchmarks/harness-phase-0.json --json
42
42
  ```
@@ -90,7 +90,12 @@ that must match the `verification.completed` event before human approval. Human
90
90
  approvals, rejections, and tracking authorizations are then recorded as
91
91
  hash-chained `approval.recorded` or `authorization.recorded` events bound to
92
92
  that digest, source revision, and contract hash. The stable `run.json` remains
93
- the CLI projection and evidence index.
93
+ the CLI projection and evidence index. The run ID and hashes are audit fields,
94
+ not inputs a human needs to provide: `ak-verify approve approved` resolves the
95
+ latest pending run. By default, a declared tracking target is covered by the
96
+ same goal approval and records both lifecycle events. Set
97
+ `tracking.authorization` to `"separate"` only when a project explicitly needs
98
+ a second human decision.
94
99
 
95
100
  Use `ak-harness audit [run-id]` to reconcile a run projection with its verified
96
101
  events. `ak-harness status` performs the same reconciliation before reporting
@@ -157,7 +162,7 @@ contract is frozen:
157
162
 
158
163
  `runtime.kind` chooses the executor used by an integration: `process` is a bounded shell-free local child process; `docker` adds the Docker sandbox. The choice is frozen in the resolved contract and therefore changes its hash. Docker remains fail-closed when its daemon or image is unavailable.
159
164
 
160
- `autonomy: "yolo"` removes the generic final review only after every applicable check passes, tracking is disabled, and the frozen contract has no ambiguity. It never auto-approves a material decision, external tracking, or a tool rule that requires approval.
165
+ `autonomy: "yolo"` removes the generic final review only after every applicable check passes, tracking is disabled, and the frozen contract has no ambiguity. It never auto-approves a material decision, external tracking, or a tool rule that requires approval. A human goal approval covers declared intermediate work and goal-scoped tracking; it does not waive evidence, freshness, or ambiguity gates.
161
166
 
162
167
  The phase executor applies the same rule to a declarative SDLC profile. A profile
163
168
  declares dependencies, inputs/outputs, gates, bounded retries, budgets, and an