@xingular/harness 1.1.1 → 1.3.1-unstable.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.
Files changed (264) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +36 -28
  3. package/dist/cli.js +10837 -6159
  4. package/dist/sdk/accounts/accounts.d.ts +27 -3
  5. package/dist/sdk/accounts/accounts.js +78 -24
  6. package/dist/sdk/accounts/secrets.d.ts +12 -0
  7. package/dist/sdk/accounts/secrets.js +114 -7
  8. package/dist/sdk/accounts/store.d.ts +26 -1
  9. package/dist/sdk/accounts/store.js +1 -1
  10. package/dist/sdk/agents/builtin.js +18 -4
  11. package/dist/sdk/agents/planResearch.d.ts +27 -0
  12. package/dist/sdk/agents/planResearch.js +82 -0
  13. package/dist/sdk/agents/profiles.d.ts +5 -1
  14. package/dist/sdk/agents/profiles.js +21 -5
  15. package/dist/sdk/annotations/pageScript.js +349 -48
  16. package/dist/sdk/annotations/part.js +34 -23
  17. package/dist/sdk/annotations/store.d.ts +7 -0
  18. package/dist/sdk/annotations/store.js +13 -5
  19. package/dist/sdk/browser/backend.d.ts +16 -0
  20. package/dist/sdk/browser/backend.js +17 -0
  21. package/dist/sdk/browser/contracts.d.ts +19 -0
  22. package/dist/sdk/browser/contracts.js +116 -0
  23. package/dist/sdk/browser/tools.d.ts +1 -4
  24. package/dist/sdk/browser/tools.js +14 -91
  25. package/dist/sdk/capabilities/runSnapshot.js +10 -4
  26. package/dist/sdk/cli.js +5 -4
  27. package/dist/sdk/commands/list.d.ts +3 -0
  28. package/dist/sdk/commands/list.js +75 -0
  29. package/dist/sdk/commands/registry.d.ts +258 -0
  30. package/dist/sdk/commands/registry.js +48 -0
  31. package/dist/sdk/commands/routes.d.ts +16 -0
  32. package/dist/sdk/commands/routes.js +33 -0
  33. package/dist/sdk/core/commandBudget.d.ts +23 -0
  34. package/dist/sdk/core/commandBudget.js +57 -0
  35. package/dist/sdk/core/index.js +17 -1
  36. package/dist/sdk/core/interactiveProfile.d.ts +46 -0
  37. package/dist/sdk/core/interactiveProfile.js +143 -0
  38. package/dist/sdk/core/shell.d.ts +20 -0
  39. package/dist/sdk/core/shell.js +73 -0
  40. package/dist/sdk/core/workspace.d.ts +13 -0
  41. package/dist/sdk/core/workspace.js +88 -0
  42. package/dist/sdk/core/workspaceBashTool.d.ts +20 -0
  43. package/dist/sdk/core/workspaceBashTool.js +50 -0
  44. package/dist/sdk/core/workspaceSandbox.d.ts +41 -0
  45. package/dist/sdk/core/workspaceSandbox.js +360 -0
  46. package/dist/sdk/core/workspaceWriteOperations.d.ts +33 -0
  47. package/dist/sdk/core/workspaceWriteOperations.js +224 -0
  48. package/dist/sdk/doctor/checks.js +71 -12
  49. package/dist/sdk/doctor/types.d.ts +2 -2
  50. package/dist/sdk/harness.d.ts +7 -0
  51. package/dist/sdk/harness.js +42 -2
  52. package/dist/sdk/hub/hub.js +5 -3
  53. package/dist/sdk/index.d.ts +8 -3
  54. package/dist/sdk/index.js +4 -1
  55. package/dist/sdk/pi/runtime.d.ts +2 -1
  56. package/dist/sdk/pi/runtime.js +2 -2
  57. package/dist/sdk/plugins/builtin.js +32 -15
  58. package/dist/sdk/plugins/builtinRegistry.d.ts +10 -3
  59. package/dist/sdk/plugins/builtinRegistry.js +30 -8
  60. package/dist/sdk/plugins/catalogue.js +2 -1
  61. package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
  62. package/dist/sdk/plugins/commandPrefix.js +21 -0
  63. package/dist/sdk/plugins/firstParty.d.ts +1 -1
  64. package/dist/sdk/plugins/firstParty.js +8 -2
  65. package/dist/sdk/plugins/install.d.ts +6 -2
  66. package/dist/sdk/plugins/install.js +29 -5
  67. package/dist/sdk/plugins/inventory.js +6 -5
  68. package/dist/sdk/plugins/manifest.d.ts +2 -0
  69. package/dist/sdk/plugins/manifest.js +2 -1
  70. package/dist/sdk/plugins/surfaces.d.ts +5 -0
  71. package/dist/sdk/plugins/surfaces.js +11 -0
  72. package/dist/sdk/plugins/types.d.ts +15 -0
  73. package/dist/sdk/prompt/compile.d.ts +14 -0
  74. package/dist/sdk/prompt/compile.js +65 -31
  75. package/dist/sdk/prompt/standard.d.ts +17 -0
  76. package/dist/sdk/prompt/standard.js +21 -0
  77. package/dist/sdk/server/methods.js +22 -2
  78. package/dist/sdk/server/remote.js +36 -11
  79. package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
  80. package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
  81. package/dist/sdk/sessions/continuation.d.ts +7 -2
  82. package/dist/sdk/sessions/continuation.js +11 -6
  83. package/dist/sdk/sessions/contracts.d.ts +190 -4
  84. package/dist/sdk/sessions/contracts.js +71 -8
  85. package/dist/sdk/sessions/control.d.ts +72 -0
  86. package/dist/sdk/sessions/control.js +158 -0
  87. package/dist/sdk/sessions/initialBash.d.ts +7 -0
  88. package/dist/sdk/sessions/initialBash.js +7 -0
  89. package/dist/sdk/sessions/planMode.d.ts +14 -3
  90. package/dist/sdk/sessions/planMode.js +74 -17
  91. package/dist/sdk/sessions/registry.d.ts +1 -1
  92. package/dist/sdk/sessions/registry.js +2 -2
  93. package/dist/sdk/sessions/runStore.d.ts +14 -0
  94. package/dist/sdk/sessions/runStore.js +38 -1
  95. package/dist/sdk/sessions/runner.d.ts +40 -2
  96. package/dist/sdk/sessions/runner.js +161 -13
  97. package/dist/sdk/sessions/sessions.d.ts +23 -3
  98. package/dist/sdk/sessions/sessions.js +225 -22
  99. package/dist/sdk/sessions/subagentService.d.ts +24 -0
  100. package/dist/sdk/sessions/subagentService.js +225 -26
  101. package/dist/sdk/sessions/subagents.d.ts +10 -1
  102. package/dist/sdk/sessions/subagents.js +4 -0
  103. package/dist/sdk/sessions/workSlice.d.ts +106 -0
  104. package/dist/sdk/sessions/workSlice.js +329 -0
  105. package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
  106. package/dist/sdk/sessions/workspaceBoundary.js +46 -0
  107. package/dist/sdk/terminal/browserControl.js +2 -1
  108. package/dist/sdk/terminal/controller.d.ts +31 -3
  109. package/dist/sdk/terminal/controller.js +81 -29
  110. package/dist/sdk/terminal/opentui/ansi.d.ts +25 -0
  111. package/dist/sdk/terminal/opentui/ansi.js +192 -0
  112. package/dist/sdk/terminal/opentui/model.d.ts +163 -0
  113. package/dist/sdk/terminal/opentui/model.js +482 -0
  114. package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +3 -3
  115. package/dist/sdk/terminal/opentui/subagentsWidget.js +7 -5
  116. package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
  117. package/dist/sdk/terminal/opentui/theme.js +88 -0
  118. package/dist/sdk/terminal/piExtension.d.ts +6 -1
  119. package/dist/sdk/terminal/piExtension.js +177 -63
  120. package/dist/sdk/terminal/standalone.d.ts +7 -0
  121. package/dist/sdk/terminal/standalone.js +72 -13
  122. package/dist/sdk/terminal/subagentMonitor.d.ts +28 -6
  123. package/dist/sdk/terminal/subagentMonitor.js +61 -9
  124. package/dist/sdk/terminal/terminals.d.ts +26 -2
  125. package/dist/sdk/terminal/terminals.js +325 -43
  126. package/dist/sdk/terminal/trajectory.d.ts +6 -1
  127. package/dist/sdk/terminal/trajectory.js +8 -0
  128. package/dist/sdk/terminal/tui/annotateCommand.d.ts +1 -1
  129. package/dist/sdk/terminal/tui/annotateCommand.js +3 -3
  130. package/dist/sdk/terminal/tui/chrome.d.ts +4 -0
  131. package/dist/sdk/terminal/tui/chrome.js +13 -0
  132. package/dist/sdk/terminal/tui/commandPages.d.ts +3 -1
  133. package/dist/sdk/terminal/tui/commandPages.js +17 -4
  134. package/dist/sdk/terminal/tui/commands.d.ts +6 -0
  135. package/dist/sdk/terminal/tui/commands.js +213 -124
  136. package/dist/sdk/terminal/tui/list.d.ts +14 -1
  137. package/dist/sdk/terminal/tui/list.js +96 -14
  138. package/dist/sdk/terminal/tui/pageOverlay.js +21 -5
  139. package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +1 -1
  140. package/dist/sdk/terminal/tui/pages/browserPage.js +5 -4
  141. package/dist/sdk/terminal/tui/pages/hubPage.d.ts +14 -1
  142. package/dist/sdk/terminal/tui/pages/hubPage.js +192 -28
  143. package/dist/sdk/terminal/tui/pages/notesPage.d.ts +5 -5
  144. package/dist/sdk/terminal/tui/pages/notesPage.js +18 -18
  145. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +8 -6
  146. package/dist/sdk/terminal/tui/pages/pluginsPage.js +206 -28
  147. package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +1 -0
  148. package/dist/sdk/terminal/tui/pages/subagentsPage.js +104 -19
  149. package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
  150. package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
  151. package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
  152. package/dist/sdk/terminal/tui/piAdapter.js +3 -5
  153. package/dist/sdk/terminal/tui/pluginCommands.d.ts +2 -0
  154. package/dist/sdk/terminal/tui/pluginCommands.js +13 -9
  155. package/dist/sdk/terminal/tui/runtime.js +23 -3
  156. package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
  157. package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
  158. package/dist/sdk/tools/checkpoint.d.ts +27 -0
  159. package/dist/sdk/tools/checkpoint.js +154 -0
  160. package/dist/sdk/tools/getCapabilities.d.ts +31 -0
  161. package/dist/sdk/tools/getCapabilities.js +34 -0
  162. package/dist/sdk/tools/sessionName.d.ts +2 -0
  163. package/dist/sdk/tools/sessionName.js +5 -3
  164. package/dist/sdk/tools/spawnSubagent.js +11 -8
  165. package/dist/sdk/tools/todo.d.ts +15 -0
  166. package/dist/sdk/tools/todo.js +64 -0
  167. package/dist/sdk/usage/analytics.d.ts +20 -0
  168. package/dist/sdk/usage/analytics.js +151 -0
  169. package/dist/sdk/usage/ledger.d.ts +38 -0
  170. package/dist/sdk/usage/ledger.js +142 -0
  171. package/dist/sdk/usage/limits/adapters.d.ts +11 -0
  172. package/dist/sdk/usage/limits/adapters.js +349 -0
  173. package/dist/sdk/usage/limits/capture.d.ts +8 -0
  174. package/dist/sdk/usage/limits/capture.js +47 -0
  175. package/dist/sdk/usage/limits/http.d.ts +12 -0
  176. package/dist/sdk/usage/limits/http.js +51 -0
  177. package/dist/sdk/usage/limits/normalize.d.ts +15 -0
  178. package/dist/sdk/usage/limits/normalize.js +211 -0
  179. package/dist/sdk/usage/limits/service.d.ts +30 -0
  180. package/dist/sdk/usage/limits/service.js +176 -0
  181. package/dist/sdk/usage/limits/types.d.ts +65 -0
  182. package/dist/sdk/usage/limits/types.js +1 -0
  183. package/dist/sdk/usage/serverMethods.d.ts +3 -0
  184. package/dist/sdk/usage/serverMethods.js +22 -0
  185. package/dist/sdk/usage/service.d.ts +32 -0
  186. package/dist/sdk/usage/service.js +66 -0
  187. package/dist/sdk/usage/settings.d.ts +7 -0
  188. package/dist/sdk/usage/settings.js +28 -0
  189. package/dist/sdk/usage/types.d.ts +60 -0
  190. package/dist/sdk/usage/types.js +4 -0
  191. package/dist/terminal-opentui.js +9204 -4812
  192. package/dist/terminal-pi.js +1848 -272
  193. package/docs/architecture/00-overview.md +1 -1
  194. package/docs/architecture/01-extension-points.md +1 -1
  195. package/docs/architecture/02-sessions-and-runs.md +169 -36
  196. package/docs/architecture/04-prompt.md +55 -15
  197. package/docs/architecture/06-plugins-and-capabilities.md +36 -15
  198. package/docs/architecture/07-tools-and-gate.md +131 -25
  199. package/docs/architecture/08-memory-and-history.md +4 -2
  200. package/docs/architecture/09-accounts-and-connectors.md +39 -3
  201. package/docs/architecture/10-server-protocol.md +71 -9
  202. package/docs/architecture/11-terminal.md +148 -60
  203. package/docs/architecture/12-storage.md +30 -2
  204. package/docs/architecture/13-world-tools.md +22 -1
  205. package/docs/architecture/14-surfaces-and-parity.md +58 -8
  206. package/docs/architecture/README.md +20 -17
  207. package/docs/architecture/proposals/PROP-0006-run-checklist.md +2 -0
  208. package/docs/architecture/proposals/PROP-0017-page-annotations.md +6 -2
  209. package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +1 -1
  210. package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
  211. package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
  212. package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
  213. package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
  214. package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
  215. package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
  216. package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
  217. package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
  218. package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
  219. package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
  220. package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +258 -0
  221. package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
  222. package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
  223. package/docs/architecture/proposals/PROP-0044-work-slice-defaults.md +93 -0
  224. package/docs/architecture/proposals/PROP-0045-rename-checklist-to-todo.md +132 -0
  225. package/docs/architecture/proposals/PROP-0046-progress-aware-stall-guards.md +82 -0
  226. package/docs/architecture/proposals/PROP-0047-plugins-hub-separation.md +122 -0
  227. package/docs/architecture/proposals/README.md +24 -6
  228. package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
  229. package/docs/decisions/ADR-0021-required-command-namespaces.md +1 -1
  230. package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
  231. package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
  232. package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
  233. package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
  234. package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
  235. package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
  236. package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
  237. package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
  238. package/docs/decisions/ADR-0039-progress-aware-stall-guards.md +39 -0
  239. package/docs/decisions/ADR-0040-architecture-change-workflow.md +31 -0
  240. package/docs/decisions/ADR-0041-plugins-hub-separation.md +41 -0
  241. package/docs/decisions/ADR-0042-windows-shell-without-sandbox.md +40 -0
  242. package/docs/decisions/ADR-0043-parents-continue-stopped-subagents.md +49 -0
  243. package/docs/doctor.md +14 -1
  244. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
  245. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
  246. package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
  247. package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
  248. package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
  249. package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
  250. package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
  251. package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
  252. package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
  253. package/docs/parity.md +83 -27
  254. package/docs/releases/1.1.1.md +28 -0
  255. package/docs/releases/1.2.0.md +49 -0
  256. package/docs/releases/1.3.0.md +21 -0
  257. package/docs/releases/4.0.0.md +10 -9
  258. package/docs/releases/README.md +35 -30
  259. package/docs/study/00-index.md +3 -0
  260. package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
  261. package/docs/terminal-tui.md +162 -82
  262. package/package.json +4 -3
  263. package/dist/sdk/tools/checklist.d.ts +0 -9
  264. package/dist/sdk/tools/checklist.js +0 -54
@@ -0,0 +1,210 @@
1
+ ---
2
+ id: STUDY-0003
3
+ title: Why a long run takes hours — measured diagnosis of two long sessions
4
+ status: measured-diagnosis; fix proposed in PROP-0041
5
+ created: 2026-10-26
6
+ updated: 2026-10-26
7
+ related:
8
+ - PROP-0033
9
+ - PROP-0041
10
+ ---
11
+
12
+ # Why a long run takes hours
13
+
14
+ **Answer.** Neither session was looping on a single action — both kept changing files and running checks. But both ran as **one unbroken reply**: 448 and 274 tool calls, 5 and 2 context compactions, and a single assistant message at the very end, or none at all. The 75-minute session produced one final report and said **"release is still blocked"**. The other was **still running at 114 minutes when measured, with 448 tool calls and not one word to the person**. 41 of those minutes were three Playwright runs, 25 of them on two timeouts, and 55 minutes were 307 model requests averaging 10.7 s each over a ~140k-token context.
15
+
16
+ The loop is in the **shape of the reply**, not in the goal. The fix is not a better prompt; it is a bounded reply, a durable checkpoint, and a loop guard. [PROP-0041](../architecture/proposals/PROP-0041-bounded-work-slices.md)
17
+ proposes them.
18
+
19
+ ## What was measured
20
+
21
+ Both sessions are ordinary records under the dev data root
22
+ (`~/.xingular-harness-dev/data/runs/<id>/`), read together with their native Pi session. Nothing was
23
+ re-run; every number below comes from `events.jsonl`, `run.json` and the native `*.jsonl`.
24
+
25
+ | | A — "Finish App Harness parity integration" | B — "Complete secure Harness release candidate" |
26
+ |---|---|---|
27
+ | Run | `64cdd5f0` | `2d62eaec` |
28
+ | User text that started it | "continue where you left of" | "continue where left of" |
29
+ | Started / last event | 17:50:43Z / 19:44:57Z at the cut, still active | 18:27:46Z / 19:42:40Z |
30
+ | Wall clock | **114.3 min at the cut, still running** | **74.9 min** |
31
+ | How it ended | no end: the same reply was still going | one final report, `completed` |
32
+ | Recorded state afterwards | `running` | `completed` |
33
+ | Model requests | 307 | 197 |
34
+ | Model time | 3299 s (55.0 min), mean 10.7 s, p90 20.0 s | 2924 s (48.7 min), mean 14.8 s, p90 30.4 s |
35
+ | Tool calls | 448 | 274 |
36
+ | Tool time | 3491 s (58.2 min), 51 % of the run | ~1420 s (23.7 min), 32 % |
37
+ | Reads | 163 over 96 paths (`host.rs` 11×) | 101 over 56 paths (`verify-terminal.py` 6×) |
38
+ | Edits | 61 over 35 files (`app.test.ts` 10×) | 78 over 30 files (`07-tools-and-gate.md` 9×) |
39
+ | Identical repeated calls | 42 instances, 20 signatures | 10 instances, 5 signatures |
40
+ | Billed tokens | 18.85 M input + 25.01 M cache read | 16.70 M input + 12.94 M cache read |
41
+ | Output tokens | 221 k, of which 175 k reasoning (79 %) | 205 k, of which 173 k reasoning (84 %) |
42
+ | Cost recorded by the harness | $2.23 | $1.66 |
43
+ | Compactions inside the run | **5**, at 255 852–269 591 tokens | **2** (7 across the 5-hour thread) |
44
+ | Cold re-sends (no cache read, >20 k input) | 9 requests, 1.58 M uncached tokens | 9 requests, 1.51 M uncached tokens |
45
+ | Assistant text inside the run | **0 characters** | **0 characters until 74.9 min**, then one 2 028-character report |
46
+ | Approvals | 49, all remembered, 0.0 s wait | 2, both remembered |
47
+
48
+ Run A was still producing events while this was written (314 model requests at 19:48Z); every number
49
+ for it is frozen at 19:44:57Z, 114.3 minutes in. Run B had already settled.
50
+
51
+ ### Where run A's 114 minutes went
52
+
53
+ | Bucket | Time | Share |
54
+ |---|---|---|
55
+ | Model requests (307) | 55.0 min | 48 % |
56
+ | Bash (129 calls) | 57.6 min | 50 % |
57
+ | — three Playwright runs: 600 s timeout, 900 s timeout, 986 s success | 41.4 min | 36 % |
58
+ | Reads, edits, searches, subagent waits | ~0.5 min | 1 % |
59
+ | Unaccounted idle | ~1.2 min | 1 % |
60
+
61
+ The harness was busy for 98.5 % of the wall clock. Nothing was hung; the reply was simply too long,
62
+ and every step paid full-context latency. The same browser suite ran three times because it timed out
63
+ twice without narrowing itself, and each retry cost the full command budget.
64
+
65
+ That 986-second command is also why a heartbeat matters: from request 306 at 19:27:56 to request 307
66
+ at 19:44:29 there is **no event for 16.6 minutes**. A busy run and a wedged one look identical on the
67
+ record.
68
+
69
+ ### Was it progressing?
70
+
71
+ Yes, measurably:
72
+
73
+ - 57 `file.changed` events in A at a steady rate (13, 6, 9, 6, 4, 9, 10 per ten minutes), longest gap
74
+ between changes 23.6 min; 74 in B, longest gap 17.5 min.
75
+ - 57 successful test/typecheck commands in A; 28 of 129 Bash calls failed and were retried.
76
+ - The checklist moved (B: 3 of 7 items completed across 9 checklist writes, and items were added as
77
+ gaps were found).
78
+ - B's last message is a real report: what changed, which checks passed (1 255 Harness tests, 586 App
79
+ tests, 185 Rust tests), and what remains blocked. That is genuine incremental work with an honest
80
+ ending — after 75 minutes and 274 tool calls.
81
+
82
+ But the same data shows the waste:
83
+
84
+ - 42 calls in A were byte-identical repeats of an earlier call; 20 distinct signatures were repeated.
85
+ - `host.rs` was read 11 times; `07-tools-and-gate.md` was edited 9 times as the checklist reworded
86
+ what "done" meant.
87
+ - Run B read its own trajectory 63 times and searched it 8 times — recovering, inside the run, state
88
+ that earlier compactions had dropped.
89
+ - Neither session produced a commit. The worktree is still dirty: B's own report counts 119 tracked
90
+ changes and 267 untracked files, which failed release preflight's clean-tree check. So "continue
91
+ where you left off" had no unambiguous answer — the work is real, but it is not a deliverable.
92
+ - A's checklist was rewritten 7 times (B's 9) and its items were reworded each time
93
+ ("Complete Harness launch…" → "Complete App commands…" → "Complete App shared-profile…" →
94
+ "Close profile-root migration…" → "Finish App shared-profile…"). That is scope drift, not a
95
+ maintained plan.
96
+
97
+ So: **incremental work, at roughly half efficiency, with no visible progress and no way to stop
98
+ cleanly.** A person watching saw tool rows for 75–114 minutes, then either a single report or nothing
99
+ at all.
100
+
101
+ ## The mechanisms that are missing
102
+
103
+ Measured against the code (all verified in this tree):
104
+
105
+ | Mechanism | State in this tree | Consequence |
106
+ |---|---|---|
107
+ | Reply budget | Only the opt-in `budget-guard` plugin (`src/plugins/firstParty.ts:31,105-140`), **off by default** and a blunt stop: it refuses tools and terminates the reply with no checkpoint | One reply ran 114 min and 448 calls |
108
+ | Checkpoint | PROP-0033's checkpoint exists (`src/sessions/compactionCheckpoint.ts`), but it restores only *goal + checklist + plan*, and `renderCompactionCheckpoint` returns `null` when there is no checklist (`src/prompt/compile.ts:196`) | No files, no failing commands, no decisions; A wrote no assistant text at all |
109
+ | Compaction discipline | Pi compacts at ~94 % of the window; the harness only observes it (`src/sessions/runner.ts:470-478`) | 5 compactions in one reply, each a cold re-send; state rebuilt by re-reading files |
110
+ | Command ceiling | Bash `timeout` is optional, "no default timeout" (`src/core/workspaceBashTool.ts:23`) | 41 minutes in three Playwright runs; 36 % of run A |
111
+ | Loop / stall detection | None (`rg loop|stuck|repeat` finds nothing in `src/sessions`) | 42 duplicate calls; 9 edits to one document |
112
+ | Liveness | Reconciliation runs only at startup and is keyed on the owner pid (`src/sessions/runStore.ts:228`); `owner.json` holds a bare pid | A run that stops producing events while its process lives is never settled, and a recycled pid can make a dead owner look alive. A long command already writes nothing for 16.6 minutes |
113
+ | Progress visibility | No mid-reply text requirement; `REPORTING_GUIDANCE` shapes only the final reply | 0 characters in 114 minutes and counting for A; one message at 74.9 minutes for B |
114
+
115
+ The layer boundary matters for the fix: task and goal lifecycle belong to the application
116
+ (`docs/study/feature-gap-review.md:7,35`). Everything above is **run execution**, which the harness
117
+ owns. PROP-0041 keeps it there.
118
+
119
+ ## What other harnesses do about this
120
+
121
+ Fetched 2026-10-26; URLs are the primary sources.
122
+
123
+ | Mechanism | Who | Trigger | What it prevents |
124
+ |---|---|---|---|
125
+ | Stop hook that blocks the turn from ending until a check passes, with a cap on consecutive blocks | [Claude Code](https://code.claude.com/docs/en/best-practices) | Turn end | "Looks done" endings and endless turns |
126
+ | Auto-compaction thrash guard: after a few refills, stop compacting and report the offending oversized result | [Claude Code troubleshooting](https://code.claude.com/docs/en/troubleshooting) | Repeated compaction in one turn | Summarise–refill loops |
127
+ | Post-compaction re-injection of the plan file and up to five recently touched files (path only above 5k tokens) | [Claude Code context window](https://code.claude.com/docs/en/context-window) | Compaction | State lost to the summarizer |
128
+ | Tool-result clearing before summarisation | [Anthropic context engineering](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) | Context pressure | Unbounded context growth |
129
+ | Subagents with a 1–2k-token return contract | [Claude Code sub-agents](https://code.claude.com/docs/en/sub-agents) | Model decision | Exploration flooding the main context |
130
+ | `todo.md` recitation at the end of context; restorable compression (drop content, keep URL/path); keep failed actions | [Manus](https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus) | Every step / compression | Goal drift, repeated mistakes |
131
+ | Loop detection by hashing `toolName + args`, cycle length 1–5 repeated 5×, plus an LLM judge after 30 turns | [Gemini CLI loopDetectionService.ts](https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/services/loopDetectionService.ts) | Every streamed tool call | Oscillation and repeated failing commands |
132
+ | Stop hook with `loop_count` and `MAX_ITERATIONS = 5` | [Cursor](https://cursor.com/blog/agent-best-practices) | Turn end | Unbounded single turn |
133
+ | `max_requeries = 3` on malformed or blocked actions | [SWE-agent config](https://swe-agent.com/latest/reference/agent_config/) | Action error | Infinite retry |
134
+ | Repo map under a 1k-token budget (PageRank over the dependency graph) | [Aider repomap](https://aider.chat/docs/repomap.html) | Every request | Re-reading files to re-orient |
135
+ | Auto-commit, lint and test after each edit | [Aider git](https://aider.chat/docs/git.html) | Each edit | Long stretches with no checkpoint |
136
+ | Event-count condenser that keeps the first events | [OpenHands context condenser](https://docs.openhands.dev/sdk/guides/context-condenser) | History size | Cost and latency growth |
137
+ | Pre/post-turn compaction phases and pre/post-compact hooks | [Codex compact.rs](https://raw.githubusercontent.com/openai/codex/main/codex-rs/core/src/compact.rs) | Turn boundaries | Unpredictable compaction |
138
+ | Truncate-then-summarise plan saved to memory because the window will truncate | [Anthropic multi-agent research](https://www.anthropic.com/engineering/multi-agent-research-system) | Context limit | Losing the plan |
139
+
140
+ Two reference scales are worth stating plainly: Manus reports **~50 tool calls per task**, and
141
+ Claude Code's published loop cap is **5 iterations**. Both runs here exceeded those by 5–9× inside a
142
+ single reply that addressed the person once, at the end, or not at all.
143
+
144
+ Context rot compounds it: performance degrades as input grows and is worst for content in the middle
145
+ of a long context ([Chroma](https://www.trychroma.com/research/context-rot),
146
+ [Lost in the middle](https://arxiv.org/abs/2307.03172)). A 250k-token context is therefore both slow
147
+ and less reliable — the re-reads and reworded checklists are what that looks like.
148
+
149
+ ## What to adopt, in order
150
+
151
+ 1. **P0, configuration only, today.** Switch on `output-trim` (20 000 chars) and `budget-guard`
152
+ (120 requests) in the plugin attachments of the affected account/project. That alone caps the
153
+ reply and shrinks tool results. No architecture change, reversible per account and per project.
154
+ 2. **P0b, small foundation fixes.** A default Bash timeout that returns partial output, and a stall
155
+ watchdog keyed on heartbeat age rather than only the owner pid. Both are narrow and independent of
156
+ the slice design below.
157
+ 3. **P1, bounded work slices (PROP-0041).** A reply budget of 160 tool calls / 40 min / 320k new
158
+ tokens, a validated checkpoint at the boundary, and a continuation that starts from that
159
+ checkpoint. This is the structural fix.
160
+ 4. **P2, the checkpoint as state, not prose.** Bounded, evidence-linked (files, failing checks,
161
+ decisions, next step) and injected at every slice start and after compaction, so the model never
162
+ re-derives state by archaeology.
163
+ 5. **P3, deterministic loop guard.** Identical `tool + args` three times, the same command failing
164
+ twice, or 25 steps with no file change and no passing check: nudge once with the evidence, then
165
+ end the slice as `blocked`.
166
+ 6. **P4, command budget.** Hard ceiling, and long suites (Playwright, full CI) as background work
167
+ rather than 16 blocking minutes.
168
+ 7. **P5, compaction pipeline.** Clear old tool results first; summarise with restorable references
169
+ (path + line range); stop after three compactions in one reply and hand off instead.
170
+ 8. **P6, visible progress.** Record narration as `progress` events and a heartbeat with steps,
171
+ elapsed time, slice and compactions; show "next checkpoint in N steps" in both surfaces.
172
+
173
+ ## How to judge whether it worked
174
+
175
+ Baseline from these two runs, to compare after PROP-0041:
176
+
177
+ | Metric | Baseline |
178
+ |---|---|
179
+ | Time to first user-visible text | never (A) / 74.9 min (B) |
180
+ | Tool calls per user-visible text | ∞ (A) / 274 (B) |
181
+ | Longest reply | 114 min and counting / 448 calls |
182
+ | Compactions per reply | 2–5 |
183
+ | Repeated identical calls | 42 per 448 (9 %) |
184
+ | Reads per distinct file | 1.7 (163/96), worst 11 |
185
+ | Time in three Playwright runs | 36 % of run A |
186
+ | Runs left `running` after owner death | 1 of 2 |
187
+
188
+ A working slice policy should keep the longest reply under ~45 minutes, put text in front of the
189
+ person at every boundary, hold compactions to at most one per slice, and never leave a run
190
+ `running` after its owner is gone.
191
+
192
+ ## What this does not fix
193
+
194
+ Model latency per token, the correctness of the work itself, or a task whose acceptance criteria
195
+ were never written down. A slice boundary cannot invent a definition of done; it can only make the
196
+ absence of one visible early.
197
+
198
+ ## Appendix: how to reproduce
199
+
200
+ Read-only, from the dev data root:
201
+
202
+ ```sh
203
+ R=~/.xingular-harness-dev/data/runs/64cdd5f0-da45-43a1-9130-89c54f298f21
204
+ jq -r 'select(.type=="usage.updated") | .payload.request.durationMs' "$R/events.jsonl" | awk '{s+=$1/1000; n++} END {print n" requests, "s" s"}'
205
+ jq -r 'select(.type=="tool.completed") | .payload.name' "$R/events.jsonl" | sort | uniq -c | sort -rn
206
+ jq -r 'select(.type=="message.completed") | .payload.role' "$R/events.jsonl"
207
+ ```
208
+
209
+ The assistant's own text lives in the native session named by `run.json`
210
+ (`nativeSessionId`), as `message` entries whose `content` blocks have `type: "text"`.