@xingular/harness 1.1.1 → 1.2.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 (223) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +28 -25
  3. package/dist/cli.js +6675 -2501
  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 +15 -1
  11. package/dist/sdk/agents/planResearch.d.ts +5 -0
  12. package/dist/sdk/agents/planResearch.js +19 -0
  13. package/dist/sdk/agents/profiles.d.ts +2 -1
  14. package/dist/sdk/agents/profiles.js +9 -4
  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/cli.js +5 -4
  26. package/dist/sdk/commands/list.d.ts +3 -0
  27. package/dist/sdk/commands/list.js +75 -0
  28. package/dist/sdk/commands/registry.d.ts +250 -0
  29. package/dist/sdk/commands/registry.js +47 -0
  30. package/dist/sdk/commands/routes.d.ts +16 -0
  31. package/dist/sdk/commands/routes.js +33 -0
  32. package/dist/sdk/core/commandBudget.d.ts +23 -0
  33. package/dist/sdk/core/commandBudget.js +57 -0
  34. package/dist/sdk/core/index.js +17 -1
  35. package/dist/sdk/core/interactiveProfile.d.ts +46 -0
  36. package/dist/sdk/core/interactiveProfile.js +143 -0
  37. package/dist/sdk/core/workspace.d.ts +13 -0
  38. package/dist/sdk/core/workspace.js +88 -0
  39. package/dist/sdk/core/workspaceBashTool.d.ts +4 -0
  40. package/dist/sdk/core/workspaceBashTool.js +36 -0
  41. package/dist/sdk/core/workspaceSandbox.d.ts +31 -0
  42. package/dist/sdk/core/workspaceSandbox.js +320 -0
  43. package/dist/sdk/core/workspaceWriteOperations.d.ts +22 -0
  44. package/dist/sdk/core/workspaceWriteOperations.js +206 -0
  45. package/dist/sdk/doctor/types.d.ts +2 -2
  46. package/dist/sdk/harness.d.ts +7 -0
  47. package/dist/sdk/harness.js +42 -2
  48. package/dist/sdk/index.d.ts +6 -1
  49. package/dist/sdk/index.js +3 -0
  50. package/dist/sdk/pi/runtime.d.ts +2 -1
  51. package/dist/sdk/pi/runtime.js +2 -2
  52. package/dist/sdk/plugins/builtin.js +29 -12
  53. package/dist/sdk/plugins/builtinRegistry.d.ts +10 -3
  54. package/dist/sdk/plugins/builtinRegistry.js +30 -8
  55. package/dist/sdk/plugins/catalogue.js +2 -1
  56. package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
  57. package/dist/sdk/plugins/commandPrefix.js +21 -0
  58. package/dist/sdk/plugins/firstParty.d.ts +1 -1
  59. package/dist/sdk/plugins/firstParty.js +8 -2
  60. package/dist/sdk/plugins/inventory.js +4 -3
  61. package/dist/sdk/plugins/manifest.d.ts +2 -0
  62. package/dist/sdk/plugins/manifest.js +2 -1
  63. package/dist/sdk/plugins/surfaces.d.ts +5 -0
  64. package/dist/sdk/plugins/surfaces.js +11 -0
  65. package/dist/sdk/plugins/types.d.ts +15 -0
  66. package/dist/sdk/prompt/compile.d.ts +14 -0
  67. package/dist/sdk/prompt/compile.js +65 -29
  68. package/dist/sdk/prompt/standard.d.ts +17 -0
  69. package/dist/sdk/prompt/standard.js +21 -0
  70. package/dist/sdk/server/methods.js +18 -0
  71. package/dist/sdk/server/remote.js +36 -11
  72. package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
  73. package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
  74. package/dist/sdk/sessions/continuation.d.ts +3 -0
  75. package/dist/sdk/sessions/continuation.js +5 -1
  76. package/dist/sdk/sessions/contracts.d.ts +168 -0
  77. package/dist/sdk/sessions/contracts.js +59 -1
  78. package/dist/sdk/sessions/control.d.ts +72 -0
  79. package/dist/sdk/sessions/control.js +158 -0
  80. package/dist/sdk/sessions/initialBash.d.ts +7 -0
  81. package/dist/sdk/sessions/initialBash.js +7 -0
  82. package/dist/sdk/sessions/planMode.d.ts +14 -3
  83. package/dist/sdk/sessions/planMode.js +73 -16
  84. package/dist/sdk/sessions/registry.d.ts +1 -1
  85. package/dist/sdk/sessions/registry.js +2 -2
  86. package/dist/sdk/sessions/runStore.d.ts +14 -0
  87. package/dist/sdk/sessions/runStore.js +35 -0
  88. package/dist/sdk/sessions/runner.d.ts +40 -2
  89. package/dist/sdk/sessions/runner.js +161 -13
  90. package/dist/sdk/sessions/sessions.d.ts +23 -3
  91. package/dist/sdk/sessions/sessions.js +202 -17
  92. package/dist/sdk/sessions/subagentService.d.ts +9 -0
  93. package/dist/sdk/sessions/subagentService.js +63 -4
  94. package/dist/sdk/sessions/workSlice.d.ts +103 -0
  95. package/dist/sdk/sessions/workSlice.js +297 -0
  96. package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
  97. package/dist/sdk/sessions/workspaceBoundary.js +46 -0
  98. package/dist/sdk/terminal/browserControl.js +2 -1
  99. package/dist/sdk/terminal/controller.d.ts +11 -3
  100. package/dist/sdk/terminal/controller.js +40 -13
  101. package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
  102. package/dist/sdk/terminal/opentui/theme.js +87 -0
  103. package/dist/sdk/terminal/piExtension.d.ts +6 -1
  104. package/dist/sdk/terminal/piExtension.js +154 -54
  105. package/dist/sdk/terminal/standalone.d.ts +7 -0
  106. package/dist/sdk/terminal/standalone.js +72 -13
  107. package/dist/sdk/terminal/subagentMonitor.d.ts +11 -2
  108. package/dist/sdk/terminal/subagentMonitor.js +32 -1
  109. package/dist/sdk/terminal/terminals.d.ts +19 -2
  110. package/dist/sdk/terminal/terminals.js +245 -35
  111. package/dist/sdk/terminal/tui/annotateCommand.d.ts +1 -1
  112. package/dist/sdk/terminal/tui/annotateCommand.js +3 -3
  113. package/dist/sdk/terminal/tui/commandPages.d.ts +3 -1
  114. package/dist/sdk/terminal/tui/commandPages.js +3 -0
  115. package/dist/sdk/terminal/tui/commands.d.ts +2 -0
  116. package/dist/sdk/terminal/tui/commands.js +205 -124
  117. package/dist/sdk/terminal/tui/list.d.ts +14 -1
  118. package/dist/sdk/terminal/tui/list.js +96 -14
  119. package/dist/sdk/terminal/tui/pageOverlay.js +13 -4
  120. package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +1 -1
  121. package/dist/sdk/terminal/tui/pages/notesPage.d.ts +5 -5
  122. package/dist/sdk/terminal/tui/pages/notesPage.js +18 -18
  123. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +0 -5
  124. package/dist/sdk/terminal/tui/pages/pluginsPage.js +9 -3
  125. package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +1 -0
  126. package/dist/sdk/terminal/tui/pages/subagentsPage.js +98 -16
  127. package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
  128. package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
  129. package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
  130. package/dist/sdk/terminal/tui/piAdapter.js +3 -5
  131. package/dist/sdk/terminal/tui/pluginCommands.d.ts +2 -0
  132. package/dist/sdk/terminal/tui/pluginCommands.js +13 -9
  133. package/dist/sdk/terminal/tui/runtime.js +23 -3
  134. package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
  135. package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
  136. package/dist/sdk/tools/checklist.js +1 -0
  137. package/dist/sdk/tools/checkpoint.d.ts +27 -0
  138. package/dist/sdk/tools/checkpoint.js +154 -0
  139. package/dist/sdk/tools/getCapabilities.d.ts +31 -0
  140. package/dist/sdk/tools/getCapabilities.js +34 -0
  141. package/dist/sdk/tools/spawnSubagent.js +4 -3
  142. package/dist/sdk/usage/analytics.d.ts +20 -0
  143. package/dist/sdk/usage/analytics.js +151 -0
  144. package/dist/sdk/usage/ledger.d.ts +38 -0
  145. package/dist/sdk/usage/ledger.js +142 -0
  146. package/dist/sdk/usage/limits/adapters.d.ts +11 -0
  147. package/dist/sdk/usage/limits/adapters.js +349 -0
  148. package/dist/sdk/usage/limits/capture.d.ts +8 -0
  149. package/dist/sdk/usage/limits/capture.js +47 -0
  150. package/dist/sdk/usage/limits/http.d.ts +12 -0
  151. package/dist/sdk/usage/limits/http.js +51 -0
  152. package/dist/sdk/usage/limits/normalize.d.ts +15 -0
  153. package/dist/sdk/usage/limits/normalize.js +211 -0
  154. package/dist/sdk/usage/limits/service.d.ts +30 -0
  155. package/dist/sdk/usage/limits/service.js +176 -0
  156. package/dist/sdk/usage/limits/types.d.ts +65 -0
  157. package/dist/sdk/usage/limits/types.js +1 -0
  158. package/dist/sdk/usage/serverMethods.d.ts +3 -0
  159. package/dist/sdk/usage/serverMethods.js +22 -0
  160. package/dist/sdk/usage/service.d.ts +32 -0
  161. package/dist/sdk/usage/service.js +66 -0
  162. package/dist/sdk/usage/settings.d.ts +7 -0
  163. package/dist/sdk/usage/settings.js +28 -0
  164. package/dist/sdk/usage/types.d.ts +60 -0
  165. package/dist/sdk/usage/types.js +4 -0
  166. package/dist/terminal-opentui.js +5207 -1883
  167. package/dist/terminal-pi.js +1658 -271
  168. package/docs/architecture/02-sessions-and-runs.md +128 -26
  169. package/docs/architecture/04-prompt.md +50 -12
  170. package/docs/architecture/06-plugins-and-capabilities.md +24 -7
  171. package/docs/architecture/07-tools-and-gate.md +104 -24
  172. package/docs/architecture/08-memory-and-history.md +4 -2
  173. package/docs/architecture/09-accounts-and-connectors.md +31 -1
  174. package/docs/architecture/10-server-protocol.md +58 -3
  175. package/docs/architecture/11-terminal.md +105 -42
  176. package/docs/architecture/12-storage.md +30 -2
  177. package/docs/architecture/13-world-tools.md +22 -1
  178. package/docs/architecture/14-surfaces-and-parity.md +54 -7
  179. package/docs/architecture/README.md +3 -1
  180. package/docs/architecture/proposals/PROP-0017-page-annotations.md +6 -2
  181. package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +1 -1
  182. package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
  183. package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
  184. package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
  185. package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
  186. package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
  187. package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
  188. package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
  189. package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
  190. package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
  191. package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
  192. package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +247 -0
  193. package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
  194. package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
  195. package/docs/architecture/proposals/README.md +14 -0
  196. package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
  197. package/docs/decisions/ADR-0021-required-command-namespaces.md +1 -1
  198. package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
  199. package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
  200. package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
  201. package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
  202. package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
  203. package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
  204. package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
  205. package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
  206. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
  207. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
  208. package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
  209. package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
  210. package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
  211. package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
  212. package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
  213. package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
  214. package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
  215. package/docs/parity.md +80 -24
  216. package/docs/releases/1.1.1.md +28 -0
  217. package/docs/releases/1.2.0.md +49 -0
  218. package/docs/releases/4.0.0.md +10 -9
  219. package/docs/releases/README.md +35 -30
  220. package/docs/study/00-index.md +3 -0
  221. package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
  222. package/docs/terminal-tui.md +100 -59
  223. package/package.json +4 -3
@@ -0,0 +1,109 @@
1
+ ---
2
+ id: EXP-0003
3
+ title: Layered Xingular terminal and Harness runtime performance audit
4
+ status: completed
5
+ created: 2026-10-25
6
+ updated: 2026-10-25
7
+ related: [EXP-0002]
8
+ ---
9
+
10
+ # EXP-0003 — Layered performance audit
11
+
12
+ ## Question and falsifiable hypothesis
13
+
14
+ How much of the user-visible delay belongs to terminal input/rendering, fresh-process startup, and
15
+ Harness session orchestration? After the OpenTUI work in EXP-0002, the hypothesis is that steady
16
+ keystroke-to-screen latency is comparable to Pi and OpenCode, while the Harness layers show up more
17
+ strongly in cold startup and memory. A long transcript should not materially increase Harness input
18
+ latency.
19
+
20
+ The comparison can falsify this: if Harness p95 grows after history, stays above OpenCode during
21
+ streaming, or Harness session calls contribute large repeatable latency with the injected session,
22
+ those are separate regression candidates.
23
+
24
+ ## Targets and controls
25
+
26
+ - **Xingular Harness:** built `node dist/cli.js`, with temporary `--state` and `--data` roots, an
27
+ isolated API-key account, and a loopback OpenAI-compatible model.
28
+ - **Pure Pi:** `@earendil-works/pi-coding-agent` 1.2.0 with an isolated `PI_CODING_AGENT_DIR`.
29
+ - **OpenCode:** v2.1.4 with `--standalone`, isolated XDG roots and a loopback-compatible provider.
30
+ - Each terminal target runs in its own PTY and temporary profile. A local deterministic SSE provider
31
+ supplies the same fixture response to all targets. No external provider, OAuth profile, or
32
+ credential is used.
33
+ - Main terminal runs use a 160×45 PTY, 35 ms key interval, two rounds of 30 typed characters and
34
+ five independent launches for idle, stream and burst. The first eight keys in each round are
35
+ excluded from latency scoring; each idle run therefore scores 44 keys and each stream/burst run
36
+ scores 22. Target order rotates between repeats.
37
+ - History uses three launches per target. Each history is an 80-turn local tool loop (about 240
38
+ transcript messages) before typing is measured. The question scenario is Harness-only and uses
39
+ plan mode. A separate 80×24 run checks a compact terminal once per target; it is sensitivity data,
40
+ not a repeated comparison.
41
+ - The runtime benchmark runs in a separate Node process with temporary state/data and a deterministic
42
+ injected session. It measures SDK import, Harness initialization, cold/warm `terminal.prepare`,
43
+ run-to-first-persisted-delta/completion, and one local tool-event path. It does not start Bun or a
44
+ real model.
45
+
46
+ ## Metrics
47
+
48
+ - Input latency is the time between writing a key to the PTY and the first time its typed prefix is
49
+ visible on a `pyte` virtual screen (p50/p95/p99/max). Missed keys are reported separately. This
50
+ includes the PTY and `pyte` parser, not a terminal emulator's physical paint.
51
+ - Startup is measured from process launch to first output, first nonblank visible screen, and a
52
+ quiet screen (750 ms with no further output). Process-tree RSS is sampled at that initial stable
53
+ screen. CPU and RSS are process-tree measurements; typing CPU is measured over the typing window.
54
+ - Terminal comparison summaries take the median of each run's metric (including each run's p95); they
55
+ are not pooled per-key percentiles. Session-runtime summaries use the median of measured samples.
56
+ - No credentialed run is required. The profiler rejects `--real` unless it is exactly one Xingular
57
+ run; this audit does not invoke `--real`.
58
+
59
+ ## Reproduction
60
+
61
+ Build the CLI and create an isolated Python environment for the PTY screen parser:
62
+
63
+ ```sh
64
+ npm run build
65
+ python3 -m venv /tmp/harness-perf-venv
66
+ /tmp/harness-perf-venv/bin/python -m pip install -r scripts/requirements-performance.txt
67
+ ```
68
+
69
+ Main repeated comparison:
70
+
71
+ ```sh
72
+ /tmp/harness-perf-venv/bin/python scripts/profile-terminal-latency.py \
73
+ --targets xingular,pi,opencode --repeats 5 --scenarios idle,stream,burst \
74
+ --rounds 2 --length 30 --interval 0.035 --width 160 --height 45 \
75
+ --warm-idle-seconds 2 --idle-seconds 2 --stream-seconds 4 \
76
+ --output /tmp/harness-perf-wide
77
+ ```
78
+
79
+ History and compact-terminal sensitivity runs:
80
+
81
+ ```sh
82
+ /tmp/harness-perf-venv/bin/python scripts/profile-terminal-latency.py \
83
+ --targets xingular,pi,opencode --repeats 3 --scenarios history \
84
+ --rounds 2 --length 30 --interval 0.035 --width 160 --height 45 \
85
+ --warm-idle-seconds 1 --idle-seconds 1 --stream-seconds 2 \
86
+ --output /tmp/harness-perf-history
87
+
88
+ /tmp/harness-perf-venv/bin/python scripts/profile-terminal-latency.py \
89
+ --targets xingular,pi,opencode --repeats 1 --scenarios idle,stream,burst \
90
+ --rounds 2 --length 30 --interval 0.035 --width 80 --height 24 \
91
+ --warm-idle-seconds 2 --idle-seconds 1 --stream-seconds 4 \
92
+ --output /tmp/harness-perf-compact
93
+ ```
94
+
95
+ Harness-only question latency and deterministic runtime overhead:
96
+
97
+ ```sh
98
+ /tmp/harness-perf-venv/bin/python scripts/profile-terminal-latency.py \
99
+ --targets xingular --repeats 1 --scenarios question --rounds 2 --length 30 \
100
+ --width 160 --height 45 --warm-idle-seconds 1 --idle-seconds 1 \
101
+ --stream-seconds 3 --output /tmp/harness-perf-question
102
+
103
+ npm run profile:session-runtime -- --iterations 5 --warmup 1 \
104
+ --output /tmp/harness-session-runtime.json
105
+ ```
106
+
107
+ For terminal behavior verification, run `python scripts/verify-terminal.py` with the same Python
108
+ environment. `npm run profile:terminal-input` measures the local draft-control socket separately;
109
+ it is not a substitute for the PTY latency run.
@@ -0,0 +1,151 @@
1
+ # EXP-0003 — Results
2
+
3
+ - **Status:** audit completed; one terminal behavior verification check failed (details below).
4
+ - **Run date:** 2026-10-25.
5
+ - **Code:** base commit `6f72a07` with a dirty worktree (81 changed/untracked paths were present).
6
+ Product changes in that worktree predate this audit; this audit added benchmark tooling and report
7
+ artifacts only.
8
+ - **Machine/runtime:** macOS 27.0, arm64, 8 logical CPUs; Node v26.8.2; Bun 1.4.2; Harness
9
+ 1.1.1; Pi 1.2.0; OpenCode v2.1.4; Python 3.12.12; pyte 0.8.2.
10
+ - **Credentials/network:** terminal comparisons used a loopback model in isolated temporary
11
+ profiles. The session-runtime benchmark used an injected deterministic session. No provider,
12
+ OAuth credential, or user profile was used; `--real` was not run.
13
+
14
+ Raw terminal and runtime JSON is in [`data/`](data/): `terminal-wide.json`,
15
+ `terminal-history.json`, `terminal-compact.json`, `terminal-question.json`,
16
+ `session-runtime.json`, and `session-runtime-replication.json`. The OpenCode executable field is
17
+ normalized to `opencode` to avoid publishing a machine-specific path; measurements are unchanged.
18
+
19
+ ## Terminal comparison
20
+
21
+ Main repeated comparison: 160×45 PTY, five launches per target, 2 rounds of 30 characters at 35 ms
22
+ per key, 2 s warm-idle and 2 s idle measurement. The table shows the median of per-launch values;
23
+ latency is milliseconds p50/p95 and CPU is process-tree CPU during the typing window. Every target
24
+ had zero missed keys.
25
+
26
+ | Scenario | Target | p50 / p95 (ms) | CPU (%) |
27
+ |---|---|---:|---:|
28
+ | Idle typing | Xingular | 5.11 / 9.98 | 7.7 |
29
+ | | Pure Pi | 5.32 / 6.39 | 3.1 |
30
+ | | OpenCode | 7.17 / 10.41 | 26.5 |
31
+ | After ~240 transcript messages | Xingular | 5.09 / 10.05 | 8.9 |
32
+ | | Pure Pi | 5.44 / 10.34 | 4.3 |
33
+ | | OpenCode | 9.47 / 12.70 | 32.6 |
34
+ | Regular stream | Xingular | 9.13 / 19.91 | 14.2 |
35
+ | | Pure Pi | 3.18 / 22.26 | 10.5 |
36
+ | | OpenCode | 10.02 / 24.87 | 41.5 |
37
+ | Burst stream | Xingular | 5.01 / 10.73 | 12.3 |
38
+ | | Pure Pi | 4.72 / 6.31 | 5.5 |
39
+ | | OpenCode | 10.42 / 21.85 | 33.2 |
40
+
41
+ History setup took a median 7.5 s for Xingular, 6.5 s for Pi, and 9.8 s for OpenCode. Xingular's
42
+ idle p95 was 9.98 ms before history and 10.05 ms after it, so this run found no meaningful
43
+ history-related typing regression. The median streaming p95 was lower than both comparisons; burst
44
+ p95 was below OpenCode but above Pi. Xingular idle p95 was roughly on par with OpenCode and 1.56×
45
+ Pure Pi; burst p95 was 1.70× Pure Pi. Thus the prior EXP-0002 p95 criterion of “no worse than
46
+ OpenCode” held for these four scenarios, while “within 1.5× Pi” did not hold for idle or burst.
47
+
48
+ The five-run p95 ranges show why the medians should not be read as precise rankings: idle ranges
49
+ were 9.64–10.19 ms (Xingular), 6.04–9.92 ms (Pi), and 9.58–11.08 ms (OpenCode); stream ranges
50
+ were 18.32–20.25, 22.02–23.38, and 19.00–26.36 ms; burst ranges were 8.87–12.08, 5.81–33.23,
51
+ and 12.86–26.00 ms respectively. Each run scores 44 idle keys and 22 stream/burst keys; p95 values
52
+ are medians of per-run p95, not pooled per-key percentiles.
53
+
54
+ ### Fresh launch and memory
55
+
56
+ `first visible` is the first nonblank PTY screen; `stable screen` is measured after 750 ms without
57
+ output. Process-tree RSS is sampled at that initial stable screen.
58
+
59
+ | Target | First visible (ms) | Stable screen (ms) | Process-tree RSS (MiB) |
60
+ |---|---:|---:|---:|
61
+ | Xingular | 2,814 | 3,768 | 392 |
62
+ | Pure Pi | 261 | 1,035 | 134 |
63
+ | OpenCode | 304 | 1,107 | 489 |
64
+
65
+ On this machine, Xingular's end-to-end first-visible time was about 10.8× Pi and 9.3× OpenCode;
66
+ its process-tree RSS was about 2.9× Pi and 0.8× OpenCode. This launch comparison includes the
67
+ Harness CLI and its terminal child, while Pi and OpenCode have different process architectures. It
68
+ measures the user-visible path, not the renderer alone. A separate 80×24 single-run sensitivity
69
+ check showed idle p95 of 4.66/5.08/8.11 ms and stream p95 of 10.95/5.72/18.61 ms for
70
+ Xingular/Pi/OpenCode respectively; it supports the same broad pattern but is not a repeated result.
71
+
72
+ The Harness-only plan-question scenario passed after the profiler was changed to enter plan mode:
73
+ 44 keys, no misses, p50 5.03 ms, p95 9.53 ms (one run; not a cross-target comparison). The raw
74
+ record is `data/terminal-question.json`.
75
+
76
+ A separate 2 s post-warm-up idle-resource window in the wide run measured median process-tree CPU
77
+ of 2.0% for Xingular, 0.5% for Pi, and 1.5% for OpenCode. These short windows are coarse and should
78
+ not be treated as a stable ranking.
79
+
80
+ ## Harness runtime overhead
81
+
82
+ Two invocations of the isolated runtime benchmark contributed ten measured samples per warm
83
+ operation (five iterations and one warmup per invocation). It imports the built SDK and uses a fake
84
+ session seam; these values exclude model/provider latency and real Pi startup.
85
+
86
+ | Operation | Median | Sample range |
87
+ |---|---:|---:|
88
+ | Warm `terminal.prepare` | 9.65 ms | 7.69–11.78 ms |
89
+ | `sessions.run` to first persisted delta | 25.65 ms | 21.78–29.44 ms |
90
+ | `sessions.run` to completion | 33.86 ms | 27.96–39.06 ms |
91
+ | Tool run to `tool.started` | 29.12 ms | 25.74–31.92 ms |
92
+ | Tool run to `tool.completed` | 29.50 ms | 26.12–47.31 ms |
93
+ | Tool run to completion | 38.96 ms | 37.07–58.24 ms |
94
+
95
+ Across the two process starts, SDK import was 246–347 ms and Harness initialization was 27.8–28.5
96
+ ms. Cold `terminal.prepare` varied substantially, from 261 to 1,158 ms; its description includes
97
+ first socket-listener setup. Treat the warm path as the repeatable figure and cold preparation as a
98
+ signal to instrument further, not as a stable estimate. Every run verified the persisted event
99
+ sequence; the temporary state/data roots were removed.
100
+
101
+ ## CPU profile notes
102
+
103
+ Profiles were captured separately from the comparison runs and are not included in their latency
104
+ medians. A one-run Bun profile of Xingular during startup and streaming (16.19 s, 846 samples) had
105
+ highest self-time in terminal output writing (`writeBuffered` 14.0%, Node `_write` 9.3%), key
106
+ matching (`matchesKey` 5.6%), OpenTUI stdout draining (4.5%), and the terminal socket `send` (3.2%).
107
+ This identifies output/key/event plumbing worth inspecting, but does not isolate one application
108
+ function as the cause of input latency.
109
+
110
+ A separate one-run Node profile of the Harness process (6.98 s, 5,576 samples) was 69% idle in the
111
+ profiler, with `spawnSync` at 11.2% and `readdir` at 3.2%. This is consistent with a startup path
112
+ that includes process and I/O waits rather than being dominated by one CPU-heavy JavaScript loop;
113
+ it is not a phase-by-phase startup trace. Profiles are diagnostic single runs and profiling itself
114
+ adds overhead.
115
+
116
+ ## Verification
117
+
118
+ - `npm run typecheck` — passed.
119
+ - `npm test` — passed: 150 test files, 1,140 tests passed, 3 skipped.
120
+ - `npm run build` — passed.
121
+ - `npm run prove` — passed all 15 standalone proof cases.
122
+ - `npm run profile:terminal-input` — passed; 120 local draft-control socket requests, p50 0.022 ms,
123
+ p95 0.053 ms. This measures the socket path, not key-to-screen rendering.
124
+ - `profile-terminal-latency.py --real --targets pi` — rejected before launch as intended; `--real`
125
+ is restricted to one Xingular run.
126
+ - `python scripts/verify-terminal.py` — **failed** during `/settings` at a narrow terminal width.
127
+ The verifier expected `Esc close` on the last row; the observed footer was truncated to
128
+ `Enter change · type to search · Tab/`. This is a terminal behavior verification failure, not a
129
+ performance measurement. No product UI code was changed as part of this audit.
130
+
131
+ ## Conclusions and follow-up
132
+
133
+ - **Steady typing:** competitive with OpenCode at 160×45, especially for streaming p95; history
134
+ does not increase Xingular's measured p95. Xingular still trails Pi on idle and burst p95, and
135
+ has higher CPU than Pi while typing/streaming.
136
+ - **Fresh start:** the clearest gap. Xingular takes about 2.8 s to first visible output and uses
137
+ about 392 MiB at the initial screen. The runtime benchmark makes warm Harness preparation look
138
+ inexpensive, but cold preparation is variable. Break startup into Node CLI, Harness account and
139
+ context setup, terminal preparation, Bun launch, and first render before attributing or optimizing
140
+ the gap.
141
+ - **Next measurements:** add phase markers for fresh startup and process-by-process RSS; repeat on a
142
+ slower machine; investigate burst input alongside `matchesKey`/output writes; and triage the
143
+ narrow `/settings` footer verification failure separately.
144
+
145
+ ## Limits
146
+
147
+ One arm64 machine and a dirty worktree; no clean-commit A/B or slower-device run. The loopback stream
148
+ is regular and excludes network/provider delay. PTY/pyte timing excludes physical terminal paint.
149
+ The compact-screen and question results are single runs. CPU profiles are single instrumented runs.
150
+ The runtime benchmark's session is injected and deterministic, so it measures Harness runtime and
151
+ persistence costs, not real model inference or the complete Pi AgentSession startup path.
@@ -0,0 +1,202 @@
1
+ # Handoff: App parity with the Harness, and the Solo sidebar and tabs (updated 2026-11-19)
2
+
3
+ The scoped implementation and documentation are in place; full parity acceptance remains open.
4
+ Nothing is committed. The working trees contain substantial pre-existing uncommitted work; preserve
5
+ it and do not revert unrelated files.
6
+
7
+ | Repository | Branch | State |
8
+ |---|---|---|
9
+ | `Xingular Agent/Harness` | `release/1.0.0` | Code and architecture docs updated; typecheck, full tests and `prove` pass |
10
+ | `Xingular UI` | (current) | Shared tab-manager change; typecheck and full tests pass |
11
+ | `Xingular Agent/App` | `app-as-frontend` | Profile safety, commands, Solo tabs, browser refusal and docs updated; automated checks pass |
12
+ | `Xingular Workspace` | (current) | Shared-UI consumers typecheck and UI check pass; four test failures were observed |
13
+
14
+ Approved plan: `~/.claude/plans/i-wanna-make-change-velvet-nova.md`.
15
+
16
+ ## What the owner asked for
17
+
18
+ 1. Solo sidebar: **Project › Session**, with no folder or worktree level. People never configure
19
+ worktrees. A new session runs in the project folder, as `xagent` does in a terminal.
20
+ 2. Each session card has two rows: the title, then a muted row such as `2h ago · 5.1MB`.
21
+ 3. One shared top bar over the chat, with tabs and an icon-only view switch:
22
+ - **Split**: every open session is its own panel (the earlier behaviour).
23
+ - **Single**: one panel; clicking a tab replaces what it shows.
24
+ 4. The sidebar shows which sessions are open. A middle click on a tab closes it. Closing a tab
25
+ only closes the tab; it never archives the session.
26
+ 5. Every Harness terminal slash command works in the App.
27
+ 6. The prompt, runtime, plugins and skills are the same in both front ends. Features that work
28
+ better in the App (annotate capture, the WebKit browser, computer control) are labelled as
29
+ add-ons in their plugin descriptions.
30
+
31
+ Choices the owner made:
32
+ - Parity: same core, plus labelled add-ons.
33
+ - Build every command now.
34
+ - Closing a tab only closes it.
35
+
36
+ ## Done
37
+
38
+ ### Harness
39
+
40
+ - **Shared command registry.** `src/commands/registry.ts` holds `CORE_COMMANDS`, plain data, each
41
+ with `kind` (session, page or local) and `methods`. The terminal's `BUILTINS` now comes from it
42
+ (`src/terminal/tui/commands.ts`).
43
+ - **`commands.list` server method** (`src/commands/list.ts`). It returns core commands, built-in
44
+ plugin commands (`annotate:…`), extension commands with their owner prefix, prompt templates
45
+ and `skill:` entries.
46
+ - **Session control methods** (`src/sessions/control.ts`, wired in `src/server/methods.ts`):
47
+ - `sessions.tree`, `sessions.navigate` (no summary; the move is saved as a `xingular-navigation`
48
+ custom entry so the next turn opens on it)
49
+ - `sessions.fork`, `sessions.clone` (both into a `targetDir`)
50
+ - `sessions.rename`, `sessions.lastReply`, `sessions.export` (JSONL)
51
+ - `sessions.reload`
52
+ - **Session command runs.** `SessionRunInput.command` / `TurnParams.command` accepts `compact`,
53
+ `navigate` (with a summary) or `export` (HTML). `runTurn` runs the command instead of a prompt
54
+ and skips the context update. `checkCommand` in `src/sessions/sessions.ts` validates it.
55
+ - **One launch path for prompts and tools:**
56
+ - `Launch.standard` (`src/prompt/standard.ts`) adds the same role, working-folder (with the
57
+ project name) and connections text for every front end.
58
+ - The terminal always uses it; the App now asks for it.
59
+ - The terminal-only `xagent-wiki` wording is gone from `compile.ts`. There is one files-and-shell
60
+ paragraph for every caller, and a standard session always gets it.
61
+ - A new Annotations tool group carries the `page_notes_*` guidance, moved from the App.
62
+ - **The terminal gets the same tools:**
63
+ - The Harness History, Wiki and skill tools go over the socket (`ownTools` in
64
+ `src/terminal/terminals.ts`), which closes PAR-002.
65
+ - Output trim and Budget guard load in the terminal (`firstParty.list` socket call plus
66
+ `piExtension.ts`), which closes PAR-006. Budget guard now resets its count per reply
67
+ (`agent_start`).
68
+ - The terminal-only `ask_user_question` alias is removed; `ask_user` covers it.
69
+ - The `pi` command's own extensions (llama.cpp, codemode, tool-search, mcp) are no longer loaded
70
+ in the terminal, because a host session cannot have them. See `catalogue.ts` and
71
+ `inventory.ts`.
72
+ - **`xagent --variant <scope>`** (`src/terminal/standalone.ts`, `src/cli.ts`). With the App's
73
+ `--data`, the terminal runs on the same variant as an App agent.
74
+ - **Add-on labels.** New `PluginDescriptor.surfaces` / `Plugin.surfaces` field
75
+ `{ preferred: 'host', terminal: 'fallback' | 'unavailable', note }`, with helpers in
76
+ `src/plugins/surfaces.ts`.
77
+ - The annotations plugin is labelled. The layer check forbids naming the App inside the
78
+ Harness, so its text says "a desktop app built on this harness".
79
+ - The terminal's `/plugins` and `/harness` pages show the note and a badge.
80
+ - **New exports** in `src/index.ts`: the registry, `SessionCommand`, `SessionTree`,
81
+ `PluginSurfaces`, `describePlugin`, `STANDARD_CONNECTIONS`.
82
+ - **Tests:**
83
+ - Added: `src/commands/registry.test.ts`, `src/sessions/control.test.ts`,
84
+ `src/prompt/surfaceParity.test.ts` (a terminal and a host session compile to identical text
85
+ and tool groups), and session-command tests in `sessions.test.ts`.
86
+ - Updated: terminal, catalogue, standalone, runtime-socket and lifecycle tests.
87
+
88
+ ### Xingular UI
89
+
90
+ - `WorkspaceTabManager` (`src/ui/document-workspace.tsx`): new `addLabel`, and `activeTabId` may
91
+ be `null`. Test added in `tests/workspace-tabs.test.tsx`. Middle-click close already existed.
92
+
93
+ ### App
94
+
95
+ - **Solo model rewritten:**
96
+ - `src/modes/solo/soloLayout.ts` (version 2): one layout across projects. Every open tab has a
97
+ pane; `view` is `split` or `single`. Functions: `openSoloTab`, `closeSoloTab`, `focusSoloTab`,
98
+ `visibleSoloTree`, `restoreSoloLayout` (migrates version 1).
99
+ - `soloWorkspaceState.ts`: storage key `…:v2`, migrated from the v1 key.
100
+ - `soloThreads.ts`: `groupSoloProjects`, `projectDefaultGroup`, `tabGroup`, `tabProjectId`.
101
+ - **Sidebar** (`SoloThreadList.tsx`):
102
+ - Project › Session, with two-row cards (`sessionMeta`) and an open/active indicator
103
+ (`data-open`, `data-active`, `data-solo-open-indicator`).
104
+ - Each session's ⋯ menu has Archive and Remove.
105
+ - The project's + button starts a session in the project's default folder group.
106
+ - The group rows and worktree controls are removed, and `SoloGroupDialog.tsx` is deleted.
107
+ - **Center** (`SoloCenter.tsx`):
108
+ - `SoloTabBar` and `SoloViewToggle` sit in the shared `PageFrame` compact header, wired in
109
+ `SoloWorkspace.tsx`.
110
+ - Per-pane headers are removed.
111
+ - ⌘W / ⌘T now call `closeFocusedTab` / `newSession` (`src/shell/frameControls.ts`,
112
+ `src/App.tsx`).
113
+ - **Session size.** `ThreadSummary.size_bytes` (Rust `history_bytes` in `agents.rs`) and
114
+ `sizeBytes` in `shared/contracts.ts`. `formatSessionSize` in `shared/files.ts` matches the
115
+ terminal's format.
116
+ - **Slash commands from the Harness:**
117
+ - `src/modes/solo/soloCommands.ts` has a handler for every non-sending core command.
118
+ `soloCommands.test.ts` fails if the registry gains one without a handler.
119
+ - `SoloCommandPicker.tsx` is the picker or page dialog.
120
+ - `SoloConversation.tsx`:
121
+ - The `/` menu and highlighting come from `commands.list`.
122
+ - Aliases (`/side`, `/tree`, `/resume`) work.
123
+ - A bare `/plan` toggles a persistent plan mode, and a bare `/btw` dismisses the side question.
124
+ - `chatCommands.ts` is reduced to `isStopCommand` and `chatCommandInput`. The duplicate
125
+ extension-command helpers in `pluginModel.ts` are removed.
126
+ - **Host side:**
127
+ - New Tauri commands in `src-tauri/src/agents.rs`, registered in `lib.rs`: `session_tree`,
128
+ `session_fork`, `session_clone` (fork and clone copy the transcript too), `session_rename`,
129
+ `session_compact`, `session_export`, `session_reload`.
130
+ - New sidecar `agent.command` (`createSessionCommand` in `sidecar/src/agentRuns.ts`).
131
+ - `RENDERER_METHODS` (`src-tauri/src/harness.rs`) gained `commands.list`, `doctor.*`,
132
+ `worktrees.list/status` and `agents.list/get`.
133
+ - Bridge: `bridge.commands`, `bridge.session` and `bridge.harnessPages` in
134
+ `src/bridge/commands.ts`. The schemas are in `shared/sessionCommands.ts`.
135
+ - **Prompt:**
136
+ - `src-tauri/src/prompts.rs` no longer writes identity, role, working-project or its own
137
+ connections text.
138
+ - It keeps only the add-on groups: App browser and computer, Files, Capabilities, Reactions.
139
+ - It adds a `folder-access` section for trusted folders.
140
+ - `agents.rs` sets `launch.standard = { cwd }`.
141
+ - **Plugin labels:**
142
+ - `sidecar/src/appPlugins.ts` labels every App part as an add-on, with `surfaces`.
143
+ - `app-identity` and `app-web-guidance` are removed, and `app-folder-access` is added.
144
+ - The Plugins screen shows a "Better in the app" or "App only" badge (`pluginModel.ts`,
145
+ `PluginCatalog.tsx`, `PluginInspector.tsx`).
146
+ - The plugin schema gains `surfaces`.
147
+ - **Guide demo** (`src/modes/guide/SoloWorkspaceExample.tsx`) and the Playwright fixtures and
148
+ specs (`tests/browser/solo-*.{fixture.tsx,spec.ts}`) are rewritten.
149
+ - **Shared interactive profile and root safety:** production App and standalone use the Harness
150
+ profile at `~/.xingular-harness/profile.json`; development uses the isolated
151
+ `~/.xingular-harness-dev/profile.json`. Existing App roots are adopted by reference, explicit
152
+ `dataRoot` overrides remain authoritative, and conflicting populated roots block startup rather
153
+ than merge. Historical account/variant/path/cwd pins are not rewritten. Legacy App Support moves
154
+ only if the destination is absent; if both trees exist, startup reports a recovery error and
155
+ leaves both untouched. Development paths are checked against production, including symlink
156
+ traversal. The App resolves the selected host credential backend through Keychain and fails
157
+ closed; the terminal also fails closed without a host adapter. Disposable App identifiers remain
158
+ blocked until an isolated Keychain adapter exists. Sidecar startup requires and validates the
159
+ selected profile and state-directory paths. Coverage is in `sidecar/src/profile.test.ts` and
160
+ `src-tauri/src/{state.rs,host.rs,secrets.rs}`.
161
+ - **Browser safety:** unsupported native WebKit operations (refs, accessibility snapshots,
162
+ screenshots, waits, and key presses) return an explicit refusal before effects; the App does not
163
+ switch automatically to the isolated Harness browser.
164
+ - **Current App documentation:** accepted ADR-0033 records Project › Session and shared tabs;
165
+ ADR-0027 and the obsolete pane-header portion of ADR-0031 are marked superseded. FEAT-0010,
166
+ FEAT-0018, the Solo glossary, architecture/implementation pages, and this handoff now describe
167
+ shared profile defaults, remaining gaps, and current verification.
168
+
169
+ ## Check results (2026-11-19)
170
+
171
+ | Check | Result |
172
+ |---|---|
173
+ | Harness `npm run typecheck` | pass |
174
+ | Harness `npm test` | pass: 163 files, 1,255 passed, 3 skipped |
175
+ | Harness `npm run prove` | pass: build and standalone proof suite; no provider request |
176
+ | App `npm run typecheck` | pass |
177
+ | App `npm test` | pass: renderer 90 files/586 tests; sidecar 11 files/86 tests |
178
+ | App `npm run check:layers` | pass |
179
+ | App `npm run check:ui` | pass: 38 recorded findings, baseline 38 |
180
+ | App `cargo test` | pass: 186 passed, 1 ignored; compiler warnings remain |
181
+ | App `cargo test --features dev-profile` | pass: 189 passed, 1 ignored; compiler warnings remain |
182
+ | App Playwright | pass: all 61 tests with installed Chrome |
183
+ | Xingular UI typecheck and `npm test` | pass: 21 files, 124 tests; the package has no `check:ui` script |
184
+ | Xingular Workspace typecheck | pass |
185
+ | Xingular Workspace `check:ui` | pass: 79 findings, baseline 87 |
186
+ | Xingular Workspace `npm run test:run` | **4 failed, 993 passed**: three `assistantService.test.ts` cases hit the Harness Pi-version guard (requires Pi 1.2.0, found 1.4.0), leaving the fake provider's `release` callback unset; one `commandPaletteNoteItem.test.ts` assertion expects an inline SVG style string that is absent |
187
+ | Xingular Workspace `electron-vite build` | pass (targeted tab-E2E run) |
188
+ | Xingular Workspace tab Playwright (three selected tests) | **3 failed before tab assertions**: shared `launchWithFixture` clicked the Notes sidebar control, then `expectNotePanelReady` timed out. The run used temporary `HOME`, `TMPDIR`, vault and user-data paths; no root cause was established |
189
+
190
+ Browser command: `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" npx playwright test --reporter=list`.
191
+
192
+ No provider calls or owner profiles were used. Tests use fixture or temporary data. The Workspace test failures were not changed as part of this task; the shared-tab tests in Xingular UI and App Playwright passed.
193
+
194
+ ## Remaining gaps and decisions
195
+
196
+ 1. **Parity acceptance is not complete.** The source routes and command handlers are present, but each fixed core command still needs its own acceptance. `PAR-002` (Harness History/Wiki/skill tools) and `PAR-006` (first-party hooks) are implemented on both surfaces but acceptance has not been recertified. `get_capabilities` is now Harness-owned; the App has no duplicate tool.
197
+ 2. **The session catalog remains separate (`PAR-008`).** App `/session` lists App-owned Solo threads; terminal `/session` lists native Pi histories. The read-only audit recommends a Harness-owned catalog of opaque references to existing native histories—not merging or copying transcripts or IDs. Keep logical/App and native Pi IDs distinct; retain the exact locator privately, preserve account/path/cwd guards, fail rather than substitute an unknown account, and serialize shared writes. This is a recommendation, not an implementation; do not claim `/session` parity.
198
+ 3. **Other registered gaps remain:** `PAR-001` App checklist surface; `PAR-003` continuation; `PAR-004` terminal variant/refinement actions; `PAR-005` App-only Wiki browsing; `PAR-007` host-backed computer/files capabilities; `PAR-009` shared recent-folder choice; `PAR-010` Solo `/agents` detail/management; `PAR-011` native WebKit annotation-gesture acceptance; `PAR-012` Solo worktree status/create/remove; and `PAR-015` native WebKit browser coverage. Unsupported browser refs, accessibility snapshots, screenshots, waits, and key presses explicitly refuse before effects; there is no automatic switch to the isolated Harness browser.
199
+ 4. **Profile interoperability is intentionally bounded.** Production App and standalone share profile-selected data/state defaults; explicit roots, `--variant`, and historical run pins remain authoritative. The App's per-agent variant is still an App-supplied override. App credentials use the host Keychain backend; a frontend without that host adapter fails closed, and disposable App identifiers are blocked until an isolated Keychain adapter exists. Shared roots do not mean credential-store copying or automatic account substitution.
200
+ 5. **Native App acceptance was not performed.** The full Playwright suite ran against isolated browser fixtures, not a Tauri window. No real-model request or user profile was used; the native Keychain and WebKit surfaces therefore remain unverified in a running App.
201
+ 6. **Workspace test failures need a separate follow-up.** `assistantService.test.ts` requires the pinned Pi runtime but this Workspace installation resolves Pi 1.4.0; `commandPaletteNoteItem.test.ts` has an SVG markup expectation mismatch. Typecheck and `check:ui` pass.
202
+ 7. **Commits:** one per repository, in order Harness → Xingular UI → App, only when the owner asks. No files were committed in this work.