@staix/agent-hub 0.21.0 → 0.22.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 +7 -0
- package/README.md +2 -2
- package/docs/agent-notes/bus.md +1 -1
- package/docs/agent-notes/daemon.md +2 -2
- package/docs/agent-notes/tasks.md +1 -1
- package/docs/agent-notes/tests.md +1 -1
- package/docs/dogfood.md +3 -1
- package/docs/operations.md +45 -0
- package/docs/profiles.md +1 -1
- package/docs/quickstart.md +5 -1
- package/docs/smoke.md +6 -0
- package/docs/specs/2026-09-19-agent-hub-design.md +31 -0
- package/docs/verification/2026-10-30-0.22.0.md +49 -0
- package/docs/verification/2026-10-30-445-capability-probes.md +172 -0
- package/docs/verification/2026-10-30-bus-delivery-operational-settings.md +77 -0
- package/docs/verification/2026-10-30-jcode-ac4.md +24 -0
- package/docs/verification/2026-10-30-jcode-ac6.md +52 -0
- package/docs/verification/2026-10-30-recovery-wait-settings.md +141 -0
- package/docs/verified.json +12 -12
- package/package.json +1 -1
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +1 -1
- package/src/cli/help.ts +1 -0
- package/src/cli/identity.ts +3 -1
- package/src/cli/learn-output.ts +38 -0
- package/src/cli/main.ts +20 -2
- package/src/cli/recovery-waits.ts +26 -0
- package/src/cli/smoke-pty-bridge.ts +67 -18
- package/src/cli/smoke-pty.ts +10 -2
- package/src/cli/upgrade-runtime.ts +16 -14
- package/src/cli/upgrade.ts +2 -1
- package/src/hub/bus.ts +18 -10
- package/src/hub/config-apply.ts +2 -1
- package/src/hub/daemon.ts +61 -14
- package/src/hub/delivery-journal.ts +78 -57
- package/src/hub/learning.ts +33 -1
- package/src/hub/operational-settings.ts +79 -1
- package/src/hub/settings.ts +21 -1
- package/src/hub/tasks.ts +78 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# #445 C0 capability-source probes (Kimi, Qwen, Codex)
|
|
2
|
+
|
|
3
|
+
Date: 2026-10-30. Refs #445 (C0 row of the binding design, D1 "Sources, one per adapter"). Model-free probes of the native capability listings each adapter would read, run against the CLIs installed on the probe host, not the versions the card names (Kimi 2.1.x, Qwen 0.25.0, Codex pinned 0.154.0).
|
|
4
|
+
|
|
5
|
+
## Versions probed
|
|
6
|
+
|
|
7
|
+
| CLI | Version | Artifact SHA-256 |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Kimi Code (`kimi`, native macOS arm64) | 2.3.2 (served `agentInfo` `Kimi Code CLI` 2.3.2) | `d84a94c7d73405283a279348d2de78abbf31d2b1f7c92a8d739eeb40cf2a2f9f` |
|
|
10
|
+
| Qwen Code (`@qwen-code/qwen-code`) | 0.26.1 (served `agentInfo` `qwen-code` 0.26.1) | `cli-entry.js` `113efe4104a9fc66f507d34bfd6abbd896ceb77de47f4b468a0825a327fdc6a5` (same as the 0.26.1 ACP receipt) |
|
|
11
|
+
| Codex (`codex-cli`, native darwin-arm64) | 0.166.0 (initialize `userAgent` `.../0.166.0`); source tag `rust-v0.166.0` = `593389380740f7b4762771573c447ccfdc59742f` | `39acf979729dd290f9a24ee38b2914e036c91b65952872e28ae2a6b88a7db7c1` |
|
|
12
|
+
|
|
13
|
+
## Isolation
|
|
14
|
+
|
|
15
|
+
- Every probe ran through one wrapper: `env -i` with `PATH`, `HOME`, `KIMI_CODE_HOME`, `KIMI_HOME`, `QWEN_HOME`, `QWEN_RUNTIME_DIR`, `CODEX_HOME`, `XDG_CONFIG_HOME`, `XDG_DATA_HOME`, `TMPDIR`, `LANG`, `TERM` only, all homes pointing into a fresh scratch tree, cwd a scratch directory (never the repo), under `sandbox-exec` with a profile that denies all outbound IP (`(deny network-outbound (remote ip))`, checked first: a plain HTTPS fetch failed to connect).
|
|
16
|
+
- No auth file was copied. Where a leg needed a configured model to open a session, it used a fixture model on an unreachable loopback base with a literal non-key string (`fixture-not-a-key`), the same method as the earlier Qwen receipts. No session/prompt that starts a model turn was sent. Only builtin slash commands that the CLIs answer locally were prompted.
|
|
17
|
+
- Each probe was one short run (8-9 s for ACP, 3 s for Codex). The probe started the CLI in its own process group, sent SIGTERM to the group at the end, and confirmed with `pgrep -g` that the group was gone (all 7 runs: `group_gone` true). The kimi/qwen/codex process list before and after is identical, and no process referencing the scratch tree remains.
|
|
18
|
+
- The running agent-hub daemon and `.agenthub` state were not touched; the repo test suite was not run.
|
|
19
|
+
- Deviation: `kimi --version`, `qwen --version` and `codex --version` were run once on the real home before the baseline hashes were taken (version print only). Every later run used the isolated wrapper.
|
|
20
|
+
|
|
21
|
+
## Real config check (before = after)
|
|
22
|
+
|
|
23
|
+
Each file's SHA-256 was taken before the first isolated probe and after the last one; every pair matched (`diff` empty). The hashes themselves are not published, because they would fingerprint the probe host's credential and identity files.
|
|
24
|
+
|
|
25
|
+
| File | Before = after |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| `~/.kimi-code/config.toml` | unchanged |
|
|
28
|
+
| `~/.kimi-code/mcp.json` | unchanged |
|
|
29
|
+
| `~/.kimi-code/tui.toml` | unchanged |
|
|
30
|
+
| `~/.kimi-code/device_id` | unchanged |
|
|
31
|
+
| `~/.kimi-code/credentials/kimi-code-env-<id>.json` | unchanged |
|
|
32
|
+
| `~/.kimi-code/oauth/kimi-code-env-<id>` | unchanged |
|
|
33
|
+
| `~/.kimi-cu/identity.json` | unchanged |
|
|
34
|
+
| `~/.kimi-webbridge/identity.json` | unchanged |
|
|
35
|
+
| `~/.qwen/settings.json` | unchanged |
|
|
36
|
+
| `~/.qwen/.env` (symlink target) | unchanged |
|
|
37
|
+
| `~/.qwen/installation_id` | unchanged |
|
|
38
|
+
| `~/.qwen/oauth_creds.json` | absent |
|
|
39
|
+
| `~/.codex/config.toml` | unchanged |
|
|
40
|
+
| `~/.codex/auth.json` | unchanged |
|
|
41
|
+
| `~/.codex/hooks.json` | unchanged |
|
|
42
|
+
| `~/.codex/installation_id` | unchanged |
|
|
43
|
+
|
|
44
|
+
`~/.kimi-work` holds only a `bin/` directory (no config or auth files).
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## Leg 1a: Kimi 2.3.2 ACP `available_commands_update`
|
|
48
|
+
|
|
49
|
+
Command: `kimi acp` (the hub's default `kimi_cmd`), under the isolated wrapper. Client sent the same `initialize` params as `acp.ts` (`protocolVersion` 1, `fs` read/write false, `terminal` false), then `session/new { cwd, mcpServers: [] }`.
|
|
50
|
+
|
|
51
|
+
Run A, no model configured:
|
|
52
|
+
|
|
53
|
+
- `initialize` -> `agentInfo { name: "Kimi Code CLI", version: "2.3.2" }`, `authMethods` one terminal method `login` (args `--login`), `agentCapabilities.loadSession` true, `sessionCapabilities` list/resume/close/delete/fork/additionalDirectories.
|
|
54
|
+
- `session/new` -> error `-32000` `"Authentication required"`. No `session/update` of any kind arrived in the 6 s that followed: without a session there is no `available_commands_update`.
|
|
55
|
+
- Source (installed binary, `ensureAuthed`): the gate passes when `auth.ensureReady()` resolves a configured model, or any OAuth provider reports logged in. `kimi acp` has no flag that disables it.
|
|
56
|
+
|
|
57
|
+
Run B, fixture model through Kimi's documented env model (`KIMI_MODEL_NAME`, `KIMI_MODEL_API_KEY`, `KIMI_MODEL_PROVIDER_TYPE=openai`, `KIMI_MODEL_BASE_URL` = unreachable loopback):
|
|
58
|
+
|
|
59
|
+
- `session/new` succeeded (`sessionId` `session_<uuid>`, `configOptions` model/thinking/mode, `modes` default/plan/auto/yolo).
|
|
60
|
+
- Right after the response, one `session/update` with `update.sessionUpdate: "available_commands_update"`.
|
|
61
|
+
- Update fields: `sessionUpdate`, `availableCommands`.
|
|
62
|
+
- Per command: `name`, `description`, optional `input: { hint }` (only `compact` has one). No schema, no side-effect class, no source field.
|
|
63
|
+
- 14 entries in a clean home: 6 ACP builtins (`compact`, `status`, `usage`, `mcp`, `tasks`, `help`), then bundled skills (for example `check-kimi-code-docs`, `sub-skill.review`, `write-goal`). Names can contain `.`; descriptions run up to 320 chars here.
|
|
64
|
+
- Run C, same plus a fixture user skill at `$KIMI_CODE_HOME/skills/probe-fixture/SKILL.md`: the list gained `skill:probe-fixture`. User skills carry the `skill:` prefix; builtin-source skills and sub-skills use the bare name (matches source `buildAcpSkillSlashCommands`).
|
|
65
|
+
- Source: the list is re-pushed on the session's `skills.changed` event, and after `session/load`, `fork` and `resume`.
|
|
66
|
+
|
|
67
|
+
`/name` execution:
|
|
68
|
+
|
|
69
|
+
- Run B also sent `session/prompt` with text `/help`. Kimi answered locally: one `agent_message_chunk` listing the same commands, then the result `stopReason: "end_turn"`. No model turn ran (builtin path; the fixture endpoint is unreachable anyway).
|
|
70
|
+
- Source: a leading `/name` is routed builtin -> local text; skill name -> `agent.activateSkill({ name, args })`, a normal model turn; unknown -> a local `agent_message_chunk` "Unknown ACP command: /x" with `end_turn`, not a JSON-RPC error.
|
|
71
|
+
|
|
72
|
+
Verdict: `available_commands_update` SUPPORTED (live, fixture-configured session; refused with `-32000 Authentication required` without one). Builtin `/name` execution SUPPORTED (live). Skill `/name input` execution UNVERIFIED: it starts a model turn, which needs an authenticated account; not run.
|
|
73
|
+
|
|
74
|
+
## Leg 1b: Qwen Code 0.26.1 ACP `available_commands_update`
|
|
75
|
+
|
|
76
|
+
Command: `qwen --acp` (the hub's default `qwen_cmd`); Run B added `--auth-type openai --model fixture-model --openai-base-url <unreachable loopback> --telemetry=false` and env `OPENAI_API_KEY=fixture-not-a-key`.
|
|
77
|
+
|
|
78
|
+
Run A, no auth:
|
|
79
|
+
|
|
80
|
+
- `initialize` -> `agentInfo { name: "qwen-code", title: "Qwen Code", version: "0.26.1" }`, `authMethods` `openai` only.
|
|
81
|
+
- `session/new` -> error `-32000` `"Authentication required: Use Qwen Code CLI to authenticate first."` with `data.authMethods`. No `session/update` arrived in the following 6 s.
|
|
82
|
+
|
|
83
|
+
Run B, fixture auth, with a fixture user skill `probe-fixture` in the isolated home:
|
|
84
|
+
|
|
85
|
+
- `session/new` succeeded (`models`, `modes`, `_meta.generatedUi`). Then one `session/update` with `sessionUpdate: "available_commands_update"`.
|
|
86
|
+
- Update fields: `sessionUpdate`, `availableCommands`, `_meta` (`availableSkills`: names; `availableSkillDetails`: name and description per skill).
|
|
87
|
+
- Per command: `name`, `description`, `input` (`{ hint }`, sometimes empty, absent on some builtins), `_meta { source, sourceLabel, supportedModes, subcommands, modelInvocable, argumentHint?, altNames? }`.
|
|
88
|
+
- 53 entries: 35 `source: "builtin-command"` (for example `status`, `config`, `export`), 17 `bundled-skill` (for example `review`, `simplify`, `batch`), 1 `skill-dir-command` (`probe-fixture`). `supportedModes` includes `acp` on all 53. No input schema and no side-effect class.
|
|
89
|
+
- Gotcha: `modelInvocable` is not a side-effect hint. It is false for every builtin and for a few skills.
|
|
90
|
+
|
|
91
|
+
`/name` execution:
|
|
92
|
+
|
|
93
|
+
- Run B sent `/help`: JSON-RPC error `-32603` "Internal error", `data.details` "Slash command not supported in ACP integration: The command \"/help\" is not supported in this mode." (`help` is not in the advertised list.)
|
|
94
|
+
- Run D (same fixture, fresh process) sent `/status` (advertised, `supportedModes` includes `acp`): one `agent_message_chunk` (`_meta.source: "slash_command"`) with version/model/auth/session text, then `stopReason: "end_turn"`. No model turn.
|
|
95
|
+
|
|
96
|
+
Verdict: `available_commands_update` SUPPORTED (live, fixture auth; refused with `-32000` without it). Builtin `/name` execution SUPPORTED (live). A command outside the ACP set fails natively with `-32603` (live). Skill `/name input` execution UNVERIFIED: it is a model turn and needs an account.
|
|
97
|
+
|
|
98
|
+
## Leg 2: Codex 0.166.0 app-server
|
|
99
|
+
|
|
100
|
+
Schema: `codex app-server generate-json-schema --out <dir>` (and `--experimental`), under the isolated wrapper. The stable bundle lists 106 client request methods, the experimental one 179.
|
|
101
|
+
|
|
102
|
+
`skills/list`:
|
|
103
|
+
|
|
104
|
+
- Present in the stable schema. Params `{ cwds?: string[], forceReload?: boolean }`. Response `{ data: [{ cwd, errors[], skills[] }] }`. Each skill (`SkillMetadata`) has `name`, `description`, `path`, `scope` (`user|repo|system|admin`), `enabled`, optional `pluginId`, `interface`, `shortDescription`, `dependencies`. No input schema, no side-effect class.
|
|
105
|
+
- Live: `codex app-server` over stdio (the hub runs it with `--listen ws://127.0.0.1:<port>`; same protocol). Sent `initialize { clientInfo }`, then the `initialized` notification, then `skills/list { cwds: [scratch cwd], forceReload: true }`. No thread was started and no auth was needed.
|
|
106
|
+
- Result: 1 entry, `errors` empty, 6 skills: the fixture `probe-fixture` (`scope: user`, path under the isolated `CODEX_HOME/skills`) and 5 `system` skills the CLI unpacks into the isolated home (for example `imagegen`, `skill-creator`, `review-agent`).
|
|
107
|
+
- One unsolicited notification arrived: `remoteControl/status/changed` (`status: disabled`).
|
|
108
|
+
- Verdict: SUPPORTED (live).
|
|
109
|
+
|
|
110
|
+
`turn/start` input item `{ type: "skill", name, path }`:
|
|
111
|
+
|
|
112
|
+
- `TurnStartParams.input` is `UserInput[]`. `UserInput` is a `oneOf` with `text`, `image`, `localImage`, `audio`, `localAudio`, `skill` and `mention`. `skill` has properties `type`, `name`, `path`, all three required, and is in the stable schema. (`mention` has the same shape.)
|
|
113
|
+
- Verdict: SUPPORTED by the 0.166.0 schema. Whether a turn started with that item actually loads the skill is UNVERIFIED: it is a model turn and needs an account.
|
|
114
|
+
|
|
115
|
+
`mcpServer/tool/call`:
|
|
116
|
+
|
|
117
|
+
- Present in the stable schema. Params `{ threadId, server, tool, arguments?, _meta? }` (`threadId`, `server`, `tool` required). Response `{ content[], isError?, structuredContent?, _meta? }`. The schema says nothing about approvals.
|
|
118
|
+
- Source at `rust-v0.166.0` (`app-server/src/request_processors/mcp_processor.rs` `call_mcp_server_tool`, `core/src/codex_thread.rs` `call_mcp_tool`):
|
|
119
|
+
- The handler loads the thread and checks only `ensure_direct_input_allowed` (refuses direct input to a multi-agent v2 subagent thread).
|
|
120
|
+
- It then calls the MCP runtime's `latest_call_tool` directly. No tool-call approval request (`item/*/requestApproval`) is on that path, so the thread's approval policy does not gate the call.
|
|
121
|
+
- The thread's approval policy does shape elicitations that the MCP server itself raises during the call (`tests/suite/v2/mcp_tool.rs`: `mcpServer/elicitation/request` round-trips under `unlessTrusted`; full-access threads decline form elicitation without the client capability).
|
|
122
|
+
- Not called live: it needs a thread and a configured MCP server.
|
|
123
|
+
- Verdict: the method EXISTS. "Subject to thread approvals": NO, by a source reading at the tag, not run live (UNVERIFIED live). The design excludes it either way. `command/exec` ("Execute a standalone command (argv vector) under the server's sandbox") also remains in the stable schema.
|
|
124
|
+
|
|
125
|
+
## Summary
|
|
126
|
+
|
|
127
|
+
| Source (D1) | Verdict | Basis |
|
|
128
|
+
| --- | --- | --- |
|
|
129
|
+
| Kimi 2.3.2 `available_commands_update` | SUPPORTED | live, fixture-configured session |
|
|
130
|
+
| Kimi builtin `/name` | SUPPORTED | live (`/help`) |
|
|
131
|
+
| Kimi skill `/name input` | UNVERIFIED | model turn needs an account |
|
|
132
|
+
| Qwen 0.26.1 `available_commands_update` | SUPPORTED | live, fixture auth |
|
|
133
|
+
| Qwen builtin `/name` | SUPPORTED | live (`/status`); `/help` refused `-32603` |
|
|
134
|
+
| Qwen skill `/name input` | UNVERIFIED | model turn needs an account |
|
|
135
|
+
| Codex 0.166.0 `skills/list` | SUPPORTED | live, no thread, no auth |
|
|
136
|
+
| Codex `turn/start` `{type:"skill",name,path}` | SUPPORTED (schema) | generated schema; live turn UNVERIFIED |
|
|
137
|
+
| Codex `mcpServer/tool/call` | exists; no approval gate (source) | schema + tag source; not live |
|
|
138
|
+
|
|
139
|
+
Findings that touch the frozen design:
|
|
140
|
+
|
|
141
|
+
- Neither native listing carries an input schema or a side-effect class. Kimi gives `input.hint` on one builtin, Qwen gives `input.hint` plus `_meta`. This supports O1: the class comes from the person.
|
|
142
|
+
- Native names include `:` (Kimi `skill:x`) and `.` (Kimi `sub-skill.review`). Both fit the D1 name regex `/^[A-Za-z0-9_.:-]{1,64}$/`. The capability id `command:skill:x` is then valid but double-prefixed.
|
|
143
|
+
- Builtins are mixed into the same lists as skills: Kimi `compact`; Qwen `clear`, `config`, `export`, `update`, `remember`, `forget`, `auth`. Some of these change session or host state. Kimi marks no source on its entries; Qwen has `_meta.source`. A C1 parser has to choose which entries to list.
|
|
144
|
+
- Kimi answers an unknown `/x` with a normal `end_turn` and an "Unknown ACP command" chunk (source), not a JSON-RPC error. Qwen answers a command outside its ACP set with `-32603`. So D3's "native rejection -> failed" holds for Qwen but needs text matching for Kimi.
|
|
145
|
+
- Both ACP agents refuse `session/new` without auth (`-32000`), so the listing exists only for an authenticated peer. Neither emits `available_commands_update` before a session exists.
|
|
146
|
+
|
|
147
|
+
## Not verified
|
|
148
|
+
|
|
149
|
+
- Executing a skill through `/name input` on Kimi or Qwen, and a Codex `turn/start` with a `skill` item: each starts a model turn and needs an authenticated account. Not run without one.
|
|
150
|
+
- Kimi and Qwen listings under a real login (a logged-in home may add user, project or plugin skills and MCP-derived commands). Only clean isolated homes plus one fixture skill were seen.
|
|
151
|
+
- `mcpServer/tool/call` live behavior: approval-free is a reading of the tag source, not a run.
|
|
152
|
+
- Kimi's unknown-command handling (source only; no unknown command was sent).
|
|
153
|
+
- The card's versions (Kimi 2.1.x, Qwen 0.25.0, Codex 0.154.0 pin). Only the installed versions above were probed.
|
|
154
|
+
- Outbound connection attempts were blocked by the sandbox profile, but not counted (the earlier Qwen receipts counted them with a Node preload guard).
|
|
155
|
+
- Linux and Intel macOS builds.
|
|
156
|
+
|
|
157
|
+
## Evidence fingerprints (scratch, not committed)
|
|
158
|
+
|
|
159
|
+
| Item | SHA-256 |
|
|
160
|
+
| --- | --- |
|
|
161
|
+
| `scripts/acp_probe.py` | `879ee4da9e42043ff5aa633b05aa5aef4115c2cf3c6f42dd645833d7bba196fc` |
|
|
162
|
+
| `scripts/codex_probe.py` | `021a8196c7d3a879a49d6703d1f369c1376b8f56150d2c6acec0043825888926` |
|
|
163
|
+
| `scripts/iso.sh` | `4b1bb766bcbe64d492e0d6f3f9bbf70fc2197f29cd1fc7680f240515b4ec148c` |
|
|
164
|
+
| `scripts/nonet.sb` | `ad9d4fdb76db3a41beb3fd5ad6557ef57e1b051663850048e51357ed46812edf` |
|
|
165
|
+
| `scripts/hashes.sh` | `3e100d6906a75ea23fe43e8f49bc0af1bef5ded87ec82d84231a3d419080aa37` |
|
|
166
|
+
| `out/kimi-plain.json` | `3a4c73d303f1ec190f6190482da50971be3652c6d8b71e765edc0b59ecd6a871` |
|
|
167
|
+
| `out/kimi-fixture.json` | `c29d4173c4cc53bb49ff2d50f6a584b217c828560569e2fa0d4dd5b9d588a548` |
|
|
168
|
+
| `out/kimi-fixture-skill.json` | `d18962889da6888eebf2c22af8e360d2b797e6be84c58fb8d2b451aa47d12140` |
|
|
169
|
+
| `out/qwen-plain.json` | `1c343778484440fec310ea15b197f06da7fd96308837e256eb8b2f77bb811ea9` |
|
|
170
|
+
| `out/qwen-fixture.json` | `3ebb27fede3f98930164a9b20d65267aa752ed4038ac77ff55e38b4ac52924a3` |
|
|
171
|
+
| `out/qwen-fixture-status.json` | `743e272ddbfe9002fc3c7e627d9a5e6eda31a0f2829c00ce5c9df9621af23943` |
|
|
172
|
+
| `out/codex-skills.json` | `70e2d6e4e4c59ff257720aa1c0f5a3e18fc4a7a761652513fa4c17d622034079` |
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# H3 bus and delivery H0 audit
|
|
2
|
+
|
|
3
|
+
Inventory reconciliation for #489 H3, based on H0 and main 26a8a835d3c01838eee4ecf374b87c7666676612. H0 locations below are frozen inventory locations, not current source lines.
|
|
4
|
+
|
|
5
|
+
Reconciliation: 68 detailed markdown rows, 59 unique rows, and 59 classification JSON identities. Nine duplicate markdown display rows are counted once. Unique classifications: 21 operational, 19 safety floor, 14 contract, 5 test seam.
|
|
6
|
+
|
|
7
|
+
Implemented scope: five operational controls through the H1 fixed descriptor mechanism; preserve existing hard ceilings and all queue/lifecycle/security behavior. The keys and bounds below are approved for this group.
|
|
8
|
+
|
|
9
|
+
| Frozen H0 location | Name | Value | H0 class | Disposition | Code-read reason / proposed control |
|
|
10
|
+
| --- | --- | --- | --- | --- | --- |
|
|
11
|
+
| src/hub/bus.ts:101:7 | `SEEN_CAP` | `2048` | operational | keep replay/storage contract | SEEN_CAP=2048 is both the retained dedupe/reply_to window and delivery-journal validateBus seen-array ceiling. A lower policy forgets replay/reply context earlier; a higher one violates existing snapshot acceptance. Leave the compatibility-sensitive bound fixed. |
|
|
12
|
+
| src/hub/bus.ts:102:7 | `MAX_ATTEMPTS` | `3` | operational | convert | MAX_ATTEMPTS=3 is the definitive safe-failure poison-envelope retry policy. Read the current configured value once per failed() evaluation; retain existing attempt counters, quota-paused exemption, presence restoration and undeliverable handling. Proposed bus.max_attempts integer1..100/default3, live at next safe failure; journal attempt validation remains fixed1..100. |
|
|
13
|
+
| src/hub/bus.ts:105:7 | `DIGEST_MAX` | `10` | operational | convert within existing ceiling | DIGEST_MAX=10 limits originals in a new push delivery. Proposed bus.digest_max integer1..10/default10, live at next take(); preserve important-first ordering, poison-alone and remote-singleton rules. Do not increase the documented10-original ceiling. |
|
|
14
|
+
| src/hub/bus.ts:108:7 | `PULL_BUDGET_BYTES` | `64 * 1024` | operational | convert within existing ceiling | PULL_BUDGET_BYTES=65536 bounds aggregate rendered text in a new pull. Proposed bus.pull_budget_bytes integer1..65536/default65536, live at next takeBudget(); preserve oldest-first, first-item-always-goes and poison-alone behavior. Do not increase the existing64KiB ceiling. |
|
|
15
|
+
| src/hub/bus.ts:109:7 | `NOTES_KEPT` | `10` | operational | convert within existing ceiling | NOTES_KEPT=10 is the shared-note preface tail, not durable memory deletion. Proposed bus.notes_kept integer1..10/default10, live on next note() or restorePreface() merge. Never rewrite existing prefaces or discard queued envelopes merely on reload. |
|
|
16
|
+
| src/hub/bus.ts:365:17 | `delay` | `1` | operational | defer recovery polling group | Initial1ms polling delay belongs to fenceRecovery(timeoutMs), the coordinator quiescence wait. It is not delivery retry delay; defer with recovery-wait settings so its shared timeout/hold semantics remain one change. |
|
|
17
|
+
| src/hub/bus.ts:372:24 | `Math.min` | `delay * 2` | operational | keep derived arithmetic | delay*2 is the exponential-backoff recurrence inside the bounded recovery fence, not an independent duration default. Do not add a setting for a derived expression. |
|
|
18
|
+
| src/hub/bus.ts:372:35 | `Math.min` | `50` | operational | defer recovery polling group | 50ms caps polling sleeps inside fenceRecovery. Defer with the1ms initial poll and injectable overall fence timeout; keep queues/in-flight work and prior recovery hold unchanged. |
|
|
19
|
+
| src/hub/bus.ts:892:31 | `this.withdrawn.size > 256` | `256` | operational | keep cancellation safety bound | The256-entry withdrawn tombstone window is consulted after awaited condensation/preparation and during retry queue restoration. Configuring it downward can forget cancellation evidence and revive withdrawn originals; leave this control fence fixed. |
|
|
20
|
+
| src/hub/delivery-journal.ts:22:3 | `TERMINAL_CAP` | `2048` | operational | convert within existing ceiling | TERMINAL_CAP=2048 is a target for pruning eligible completed/discarded/failed history. Proposed bus.terminal_history_limit integer1..2048/default2048, live at next normal terminal-settlement prune. Do not prune on reload, touch pending/uncertain rows, remove previous_id protection or change durable consumed-retry proof. Protected rows can keep the actual count above the target. |
|
|
21
|
+
| src/hub/limits.ts:15:63 | `sender_per_min` | `0` | operational | already configured | No-project sender_per_min=0 deliberately disables sender limiting. Existing LimitsConfig and config.limits own it; keep this separate from the configured-project default12. |
|
|
22
|
+
| src/hub/limits.ts:15:80 | `pair_per_min` | `0` | operational | already configured | No-project pair_per_min=0 deliberately disables recipient limiting. Existing LimitsConfig and config.limits own it; keep this separate from the configured-project default6. |
|
|
23
|
+
| src/hub/limits.ts:15:123 | `repeat_window_s` | `0` | operational | already configured | No-project repeat_window_s=0 deliberately disables repeat suppression. Existing LimitsConfig and config.limits own it; preserve configured-project default120s separately. |
|
|
24
|
+
| src/hub/limits.ts:17:63 | `sender_per_min` | `12` | operational | already configured | PROJECT_LIMITS.sender_per_min=12 is already overridable by limits.sender_per_min and read on each admission. Preserve no-project default0 and currently shared live cfg object; no second numeric control. |
|
|
25
|
+
| src/hub/limits.ts:17:81 | `pair_per_min` | `6` | operational | already configured | PROJECT_LIMITS.pair_per_min=6 is already overridable by limits.pair_per_min and read per admission. Preserve the no-project default0 and recipient/group bucket semantics. |
|
|
26
|
+
| src/hub/limits.ts:17:104 | `important_per_hour` | `6` | operational | already configured | PROJECT_LIMITS.important_per_hour=6 is already overridable by limits.important_per_hour. Preserve important-only charging, atomic group/peer scopes and no-project default0. |
|
|
27
|
+
| src/hub/limits.ts:17:124 | `repeat_window_s` | `120` | operational | already configured | PROJECT_LIMITS.repeat_window_s=120 is already overridable by limits.repeat_window_s. Preserve no-project default0 and the current dedupe key including parent and sorted audience. |
|
|
28
|
+
| src/hub/limits.ts:47:46 | `now - last < this.cfg.repeat_window_s * 1000` | `this.cfg.repeat_window_s * 1000` | operational | keep derived arithmetic | repeat_window_s*1000 converts the configured seconds into milliseconds for repeat admission. It already follows the operator value; no independent setting. |
|
|
29
|
+
| src/hub/limits.ts:51:30 | `this.recent.size > 1000` | `1000` | operational | keep implementation scan trigger | recent.size>1000 triggers deletion of EXPIRED entries only. It is not a retention cap and does not evict fresh duplicate evidence. A new cache-cap setting would misdescribe/change semantics; leave the maintenance trigger fixed. |
|
|
30
|
+
| src/hub/limits.ts:51:87 | `now - at >= this.cfg.repeat_window_s * 1000` | `this.cfg.repeat_window_s * 1000` | operational | keep derived arithmetic | repeat_window_s*1000 is the same configured-window expiry comparison used for cleanup. Keep the arithmetic coupled to limits.repeat_window_s. |
|
|
31
|
+
| src/hub/peers.ts:54:14 | `DEFAULT_WATCHDOG_MS` | `300000` | operational | already configured | DEFAULT_WATCHDOG_MS=300000 is already daemon watchdog_ms and constructor-injectable. Reload reaches BasePeer.configureWatchdog and takes effect on the next busy turn, never rearming the running watchdog. |
|
|
32
|
+
| src/hub/bus.ts:78:51 | `retryMs` | `1000` | test seam | existing test seam | DEFAULT_BUS.retryMs=1000 is already a constructor option used by arm() after a failure. H0 marks it test seam rather than operational; leave the injectable API, and do not introduce a second retry-delay control in this operational-only conversion. |
|
|
33
|
+
| src/hub/bus.ts:78:67 | `batchMax` | `3` | test seam | already configured/test seam | batchMax=3 is BusOptions plus daemon batch_max. Bus.configureScheduling already applies future scheduling only; no new default conversion needed. |
|
|
34
|
+
| src/hub/bus.ts:78:79 | `batchMs` | `15_000` | test seam | already configured/test seam | batchMs=15000 is BusOptions plus daemon batch_ms. Preserve the oldest original ts-based deadline and no reload re-arm. |
|
|
35
|
+
| src/hub/bus.ts:78:97 | `queueCap` | `200` | test seam | already configured/test seam | queueCap=200 is BusOptions plus daemon queue_cap. Preserve later admission only; reload never trims existing queues. |
|
|
36
|
+
| src/hub/bus.ts:185:55 | `batchMax < 1` | `1` | contract | keep contract | batchMax minimum1 is the positive delivery-count contract checked by configureScheduling; settings metadata must fit inside it. |
|
|
37
|
+
| src/hub/bus.ts:185:71 | `batchMax > 2_147_483_647` | `2_147_483_647` | contract | keep contract | batchMax upper2147483647 is the existing numeric scheduling contract; do not replace it with an operator-controlled bound. |
|
|
38
|
+
| src/hub/bus.ts:186:63 | `batchMs > 2_147_483_647` | `2_147_483_647` | contract | keep contract | batchMs upper2147483647 is the JavaScript timer-domain ceiling; retained as a fixed validator. |
|
|
39
|
+
| src/hub/bus.ts:187:55 | `queueCap < 1` | `1` | contract | keep contract | queueCap minimum1 forbids nonsensical zero-cap scheduling; retained as a fixed validator. |
|
|
40
|
+
| src/hub/bus.ts:187:71 | `queueCap > 2_147_483_647` | `2_147_483_647` | contract | keep contract | queueCap upper2147483647 is the existing Bus scheduling numeric contract; retained as a fixed validator. |
|
|
41
|
+
| src/hub/bus.ts:361:35 | `timeoutMs` | `5_000` | test seam | existing test seam | fenceRecovery timeoutMs=5000 is already an injectable overall quiescence deadline. Do not add per-call or environment overrides; leave H3 delivery configuration separate. |
|
|
42
|
+
| src/hub/bus.ts:616:98 | `backlog.length > 64` | `64` | safety floor | keep safety floor | backlog length64 bounds untrusted/persisted task-id metadata decoded from one envelope before queue observation; do not expose it as a work policy. |
|
|
43
|
+
| src/hub/bus.ts:1222:67 | `reason.replace(/\s+/g, ).slice` | `300` | safety floor | keep safety floor | Failure reason slice300 is a sanitized public diagnostic-size ceiling. Keep fixed independently of retry settings. |
|
|
44
|
+
| src/hub/deferred-hub.ts:4:14 | `MAX_DEFERRED_HUB` | `2048` | safety floor | keep safety floor | MAX_DEFERRED_HUB2048 is the bounded recovery outbox admission/restore contract. A full outbox refuses new publication without dropping accepted notices; larger support requires the documented paged durable outbox. |
|
|
45
|
+
| src/hub/deferred-hub.ts:21:21 | `text` | `256` | safety floor | keep safety floor | id text256 bounds a restored deferred envelope identifier before trust. |
|
|
46
|
+
| src/hub/deferred-hub.ts:21:46 | `text` | `256` | safety floor | keep safety floor | trace text256 bounds the restored trace identifier before trust. |
|
|
47
|
+
| src/hub/deferred-hub.ts:22:57 | `env.body.length > 1_000_000` | `1_000_000` | safety floor | keep safety floor | body1000000 is the deferred envelope untrusted text ceiling and must remain compatible with the journal envelope validator. |
|
|
48
|
+
| src/hub/deferred-hub.ts:27:50 | `env.to.length > 256` | `256` | safety floor | keep safety floor | Recipient count256 bounds restored deferred fan-out metadata; not an operator audience policy. |
|
|
49
|
+
| src/hub/deferred-hub.ts:27:90 | `text` | `256` | safety floor | keep safety floor | Per-recipient text256 bounds restored peer identifiers independently of count. |
|
|
50
|
+
| src/hub/deferred-hub.ts:35:88 | `refs.paths.length > 256` | `256` | safety floor | keep safety floor | refs.paths count256 bounds restored path metadata before downstream policy checks. |
|
|
51
|
+
| src/hub/delivery-hints.ts:13:31 | `result.rows.length >= 32` | `32` | safety floor | keep safety floor | Producer hint rows32 is the bounded body-free advisory projection; count/truncated still report omitted rows. |
|
|
52
|
+
| src/hub/delivery-hints.ts:23:112 | `held.rows.length > 32` | `32` | safety floor | keep safety floor | Consumer hint rows32 validates untrusted hint payload and matches the producer ceiling. |
|
|
53
|
+
| src/hub/delivery-hints.ts:23:240 | `Buffer.byteLength(JSON.stringify(held), utf8) > 4096` | `4096` | safety floor | keep safety floor | Consumer hint JSON4096 bytes is the closed metadata budget; do not tie it to user-configured retention. |
|
|
54
|
+
| src/hub/delivery-hints.ts:24:130 | `row.id.length > 256` | `256` | safety floor | keep safety floor | Held delivery id256 bounds untrusted identifier text in recipient-visible hints. |
|
|
55
|
+
| src/hub/delivery-hints.ts:24:305 | `sender.length > 256` | `256` | safety floor | keep safety floor | Held sender256 bounds untrusted sender text in recipient-visible hints. |
|
|
56
|
+
| src/hub/delivery-journal.ts:20:14 | `MAX_ENVELOPE_BODY` | `1000000` | contract | keep contract | MAX_ENVELOPE_BODY1000000 is a wire/storage acceptance ceiling also used by retry-warning decoration and deferred validation. Keep byte/path/protocol compatibility unchanged. |
|
|
57
|
+
| src/hub/delivery-journal.ts:21:7 | `SCHEMA_VERSION` | `1` | contract | keep contract | SCHEMA_VERSION1 identifies the journal storage/import format, never a setting. |
|
|
58
|
+
| src/hub/delivery-journal.ts:23:3 | `MAX_ROWS` | `100000` | safety floor | keep safety floor | MAX_ROWS100000 bounds imported lists/serialized history and protects restore resources. Terminal-history target cannot raise it. |
|
|
59
|
+
| src/hub/delivery-journal.ts:24:3 | `MAX_JSON` | `20 * 1024 * 1024` | contract | keep contract | MAX_JSON20MiB is the whole serialized journal acceptance contract. Keep unchanged across retention conversion. |
|
|
60
|
+
| src/hub/delivery-journal.ts:75:51 | `max` | `4096` | safety floor | keep safety floor | Generic journal text maximum4096 bounds untrusted persisted/imported string fields before use. |
|
|
61
|
+
| src/hub/delivery-journal.ts:76:51 | `value.length < 1` | `1` | contract | keep contract | text minimum length1 is the nonempty identifier/string shape contract. |
|
|
62
|
+
| src/hub/delivery-journal.ts:83:9 | `min` | `0` | contract | keep contract | integer default minimum0 encodes nonnegative counters/timestamps; per-field overrides remain fixed. |
|
|
63
|
+
| src/hub/delivery-journal.ts:144:36 | `Object.keys(queues).length > 4096` | `4096` | safety floor | keep safety floor | Queue peer-map count4096 bounds imported bus state, not configured capacity per peer. |
|
|
64
|
+
| src/hub/delivery-journal.ts:147:43 | `list` | `2048` | safety floor | keep safety floor | Queue list2048 bounds imported envelopes for one peer; preserve compatibility even if normal live queue_cap differs. |
|
|
65
|
+
| src/hub/delivery-journal.ts:608:53 | `Math.max` | `1` | contract | keep contract | attempt Math.max1 records a positive attempt number in normalized delivery history; it is not a retry-budget default. |
|
|
66
|
+
| src/hub/envelope.ts:23:14 | `MAX_HOP` | `3` | contract | keep contract | MAX_HOP3 is the cross-peer loop-prevention/wire hop cap. No configurable retry budget may alter it. |
|
|
67
|
+
| src/hub/envelope.ts:45:52 | `hop` | `0` | contract | keep contract | Initial hop0 starts a new trace; not a duration or retry policy. |
|
|
68
|
+
| src/hub/envelope.ts:121:98 | `Array.from(note from ${from} [${kind}]: ${text.replace(/\s+/g, ).trim()}).slice` | `300` | safety floor | keep safety floor | Public note-line300 codepoints is the sanitized rendering ceiling. NOTES_KEPT can only affect count, never this per-note bound. |
|
|
69
|
+
| src/hub/peers.ts:78:49 | `ms > 2_147_483_647` | `2_147_483_647` | contract | keep contract | Watchdog maximum2147483647 is the JavaScript timer-domain ceiling, not the configurable watchdog interval itself. |
|
|
70
|
+
|
|
71
|
+
## Runtime boundaries and verification
|
|
72
|
+
|
|
73
|
+
- The five values follow the existing accepted configuration and H1 publication path. Each is read at its documented next operation; reload itself does not replay work, re-arm deadlines, trim queues, mutate attempts or rewrite prefaces.
|
|
74
|
+
- Journal retention is read in the existing `pruneTerminal` path. The `previous_id` protection and separate consumed-retry proof are unchanged, so protected parents and the current mutation receipt can keep history above the configured target.
|
|
75
|
+
- Existing limits retain separate no-project-off and configured-project defaults. This conversion adds no limits UI rows or duplicate controls, and leaves `configureScheduling` and `configureWatchdog` timing unchanged.
|
|
76
|
+
- No safety floor, wire/storage constant, imported-state bound, sanitizer limit, unknown/PII gate, receipt rule or remote queue contract changes.
|
|
77
|
+
- Tests cover independent legacy pins, schema/row/apply parity, next-operation configuration reads, poison-alone and paused-quota retries, oversized first-pull progress, and history protection. Their execution result belongs to the exact-head PR receipt; live console/dashboard editing and native delivery performance remain unverified.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Jcode native hub-tool receipt (#332 AC4)
|
|
2
|
+
|
|
3
|
+
Readback date: 2026-10-30. Historical host records only; no new task, message or model call was sent for this receipt. Task titles, message bodies, arguments and native payloads are omitted.
|
|
4
|
+
|
|
5
|
+
## Correlated identifiers
|
|
6
|
+
|
|
7
|
+
All three operations belong to host turn `jcode#mvlpussw.165`, bounded by `events.jsonl` line 291728 (`turn_start`, 2026-10-24T05:05:58.480Z) and line 291975 (`turn_end`, 2026-10-24T05:12:21.788Z).
|
|
8
|
+
|
|
9
|
+
| Operation | UTC | Host event identity | Matching hub.log record |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| `hub_task_accept` | 2026-10-24T05:06:25.607Z | line 291765; task `406`; event `accepted`; by/owner `jcode`; state `in_progress` | line 26001, 2026-10-24T05:06:25.666Z; task `406`; accepted by `jcode` |
|
|
12
|
+
| `hub_send` | 2026-10-24T05:06:25.805Z | line 291766; envelope `00e7e800-1373-49fc-bc37-6c75307ee354`; from `jcode`; to `kimi`, `codex` | line 26002, same UTC; `msg jcode` |
|
|
13
|
+
| `hub_task_done` | 2026-10-24T05:12:14.206Z | line 291964; task `406`; event `done`; by/owner `jcode`; state `in_review`; reviewer `codex-review` | line 26026, 2026-10-24T05:12:14.259Z; task `406` notification |
|
|
14
|
+
| `hub_send` | 2026-10-24T05:12:21.096Z | line 291973; envelope `e5832f38-4c7e-4e54-bce2-c09cd795e8c5`; from `jcode`; to `hub` | line 26031, same UTC; `msg jcode` |
|
|
15
|
+
|
|
16
|
+
Sources are the project's append-only `.agenthub/state/events.jsonl` and `.agenthub/state/hub.log`. The task records have `pii: false`. Line numbers identify the readback prefix; timestamp, task/turn/envelope IDs provide the correlation if logs are later rotated. No raw log excerpt is published.
|
|
17
|
+
|
|
18
|
+
## Scope
|
|
19
|
+
|
|
20
|
+
This is a receipt of the historical native peer's accepted host effects, not a new provider/model probe. The logical tool names correspond to the host task/send entry points; individual MCP RPC frame IDs and the historical native binary version are not retained in these records and are not inferred from the later installed version.
|
|
21
|
+
|
|
22
|
+
`test/jcode-peer.test.ts` separately covers the person-owned MCP writer and override/link/foreign-entry refusals, the configured MCP SDK bridge reaching this project's tools as `jcode`, owned launch/version/stop behavior, and refusal of a load without identity proof. Those are fixtures; they do not replace this historical receipt or establish a fresh native/account turn.
|
|
23
|
+
|
|
24
|
+
Refs #332. AC6 identity re-probe is recorded separately.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Jcode 0.99.1 session/load identity re-probe (#332 AC6)
|
|
2
|
+
|
|
3
|
+
Probe UTC: `2026-10-30T05:14:34.859Z`. Host: macOS arm64, probe parent Bun 1.4.2. This is a model-free native id-echo prerequisite check, not a restored conversation or account/model receipt.
|
|
4
|
+
|
|
5
|
+
Probe adapter source: `3af9255d355a29bc1d63eaa5b7535f1c48018cd9`; isolated worktree dependency `@staix/agent-mem` 0.13.0. Scratch probe script SHA-256: `27ba447c4fed211fa01234d069a44b4db96e2de31402ab562c7ffe98487cf8e3`.
|
|
6
|
+
|
|
7
|
+
## Native version and boundary
|
|
8
|
+
|
|
9
|
+
- Selected installed binary: `~/.jcode/builds/versions/0.99.1/jcode`; SHA-256 `eccb33c08a21764317b0e0bf217e60c745b90f51c7bf6d2ff90b548b9fe7383e`.
|
|
10
|
+
- Native version JSON and ACP `agentInfo` both identify `jcode` `0.99.1`.
|
|
11
|
+
- The current adapter calls `assessVersion("jcode", version)`; this run returned `ok: true`, state `verified`. `COMPAT.jcode` accepts releases from `0.98.0` up to, excluding, `1.0.0`; `0.99.1` is explicitly verified.
|
|
12
|
+
- The product adapter still sets `requireLoadSessionEcho: true`. No source, range, trust or recovery setting changed.
|
|
13
|
+
|
|
14
|
+
## Isolation and lifecycle
|
|
15
|
+
|
|
16
|
+
- Fresh, distinct `HOME` and `JCODE_HOME`, temp directory and project repository were created below scratch probe id `j428-tNBKn0`. No auth or other real config contents were copied.
|
|
17
|
+
- The isolated native home and all three project MCP files (`.jcode/mcp.json`, `.mcp.json`, `.claude/mcp.json`) held empty `mcpServers` maps. Child environment was an explicit allowlist; it carried no hub token, peer/launch identity or inherited agent markers.
|
|
18
|
+
- `JCODE_NO_TELEMETRY=1`, `DO_NOT_TRACK=1` and `JCODE_DISABLE_CLAUDE_MCP=1` were supplied. No claim is made that the last flag selects MCP servers or that network attempts were measured.
|
|
19
|
+
- Both native command arrays came from the adapter's `jcodeCommand`: private `.sock` path, `--cwd`, `--no-update`, `--no-selfdev`; serve also used `--temporary-server`, `--owner-pid` and the server name, ACP used `--mcp-tools eager`. Readiness used `JCODE_READY_FD=3` and a verified private socket.
|
|
20
|
+
- Sequence: native version, owned serve readiness, first ACP initialize/new, stop only that ACP group, second ACP initialize/load, then teardown. No `session/prompt`, provider request or native permission grant was sent.
|
|
21
|
+
- Owned process ids: `63478, 63479, 63480, 63492`. The repository's `trackGroup`/`stopOwnedProcess` stopped only these owned groups. Final process-table readback confirmed no member of those groups and no command naming the probe root remained. No global Jcode stop command was used.
|
|
22
|
+
|
|
23
|
+
## Protocol identifiers
|
|
24
|
+
|
|
25
|
+
| Step | Recorded result |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| First initialize | requested protocol 1; `agentInfo` jcode 0.99.1; `agentCapabilities.loadSession: true` |
|
|
28
|
+
| session/new | `sessionId: session_retriever_1793337275047_fe44650598b973ee`; result keys `configOptions`, `models`, `sessionId` |
|
|
29
|
+
| Second initialize | completed on a new ACP client against the same private serve |
|
|
30
|
+
| session/load | requested exactly `session_retriever_1793337275047_fe44650598b973ee`; successful result keys `configOptions`, `models` only |
|
|
31
|
+
| Identity echo | `sessionId` absent; exact equality false |
|
|
32
|
+
|
|
33
|
+
No raw native response, model catalog, stderr, task text or prompt body is published. The native saved-session file was absent after this zero-prompt run. The successful load therefore demonstrates only the reply shape for a freshly created native session; it does not prove on-disk conversation restoration, server-restart recovery or TUI resume.
|
|
34
|
+
|
|
35
|
+
## Real configuration comparison
|
|
36
|
+
|
|
37
|
+
The four real `~/.jcode` files were SHA-256 compared before the first native process and after teardown. All were regular, bounded files; all four comparisons were unchanged. The hash values remain in private scratch evidence and are not published. No file contents are published.
|
|
38
|
+
|
|
39
|
+
| File | Before/after comparison |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `auth.json` | unchanged |
|
|
42
|
+
| `auth-refresh-state.json` | unchanged |
|
|
43
|
+
| `config.toml` | unchanged |
|
|
44
|
+
| `mcp.json` | unchanged |
|
|
45
|
+
|
|
46
|
+
## Outcome
|
|
47
|
+
|
|
48
|
+
**AC6 remains blocked on native 0.99.1 id-echo proof.** A successful `session/load` acknowledgement without the selected native id cannot authorize verified restore. The adapter's existing refusal and withheld automatic recovery remain unchanged; the historical conversation and emitted full recovery path are not claimed verified. No enable-restore follow-up is proposed from a non-echoing response.
|
|
49
|
+
|
|
50
|
+
This confirms the missing-echo boundary recorded in [the earlier 0.99.1 receipt](2026-10-26-jcode-0.99.1.md) with a fresh isolated run. A future native release must independently echo the actual selected id before the verified-restore follow-up is considered.
|
|
51
|
+
|
|
52
|
+
Refs #332.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# H4 recovery and upgrade waits: H0 ledger
|
|
2
|
+
|
|
3
|
+
Reconciliation for #489 H4 (task 445), against the H0 inventory `2026-10-24-hardcoded-values.md`. The inventory lists 141 rows for the area "recovery/upgrade waits" (117 unique after the inventory's duplicate display rows). Locations are frozen H0 locations, not current source lines. The rows are taken from the inventory as it stands and each disposition was read against the code at main 3af9255d; the generator is not committed.
|
|
4
|
+
|
|
5
|
+
Classification of the unique rows by H0: 58 operational, 23 safety floor, 26 contract, 10 test seam.
|
|
6
|
+
|
|
7
|
+
Dispositions: **6 rows converted** into five settings (111 left out, each with its reason below). 0 rows are unclassified.
|
|
8
|
+
|
|
9
|
+
The five settings (all `next use`, read from the project's config at the start of each wait by `src/cli/recovery-waits.ts`):
|
|
10
|
+
|
|
11
|
+
| Setting | Bounds | Default | Constant it replaces |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `recovery.reconnect_wait_s` | 600 to 3600 s | 600 | `RECONNECT_WAIT_MS` |
|
|
14
|
+
| `recovery.unmanaged_reconnect_wait_s` | 90 to 900 s | 90 | `UNMANAGED_RECONNECT_WAIT_MS` |
|
|
15
|
+
| `recovery.control_timeout_s` | 30 to 300 s | 30 | `RECOVERY_CONTROL_TIMEOUT_MS` |
|
|
16
|
+
| `recovery.shutdown_wait_s` | 30 to 300 s | 30 | the 30 s wait after a commit in `runRecovery` |
|
|
17
|
+
| `recovery.terminal_idle_wait_s` | 30 to 600 s | 120 | the two 120 s `waitForIdle` calls |
|
|
18
|
+
|
|
19
|
+
Every minimum is today's constant except the terminal idle wait: a person-visible wait may be raised and never shortened below what ships. A shorter terminal idle wait only ends a wait in manual-required, which retains the terminal.
|
|
20
|
+
|
|
21
|
+
Handed over from H3 and not in this area's inventory rows: the recovery fence poll in `src/hub/bus.ts` (`fenceRecovery`: a 1 ms initial poll, doubling to a 50 ms cap, bounded by a 5 s deadline). H3's ledger rows `bus.ts:365:17` and `bus.ts:372:35` deferred it to this task. **Left out of H4**, with the reason: the 5 s deadline is already an injectable parameter of `fenceRecovery(timeoutMs = 5_000)` and a fence that times out leaves queues, in-flight deliveries and any hold the caller did not set exactly as they were, so a longer value only delays a refusal the caller retries; the 1 ms and 50 ms poll steps are an implementation detail of that bounded wait, not a wait a person tunes. It stays a constant (H3's row `bus.ts:361:35` records the same `5_000` as a test seam). Both daemon call sites (`recovery prepare` and `recovery restore`) pass no argument. This is a disposition, not a conversion: no setting was added for it.
|
|
22
|
+
|
|
23
|
+
| Frozen H0 location | Name | Value | H0 class | Disposition | Reason |
|
|
24
|
+
| --- | --- | --- | --- | --- | --- |
|
|
25
|
+
| src/cli/recovery-guidance.ts:89:173 | `[...new Set(recorded.filter((peer): peer is string => typeof` | `64` | contract | keep: contract | A format, protocol or arithmetic constant. |
|
|
26
|
+
| src/cli/recovery-package.ts:15:23 | `next.length > 2_000_000` | `2_000_000` | safety floor | defer (H4 follow-up): recovery-package.ts | Outside this task's paths: package-copy and child-process timeouts. |
|
|
27
|
+
| src/cli/recovery-package.ts:16:23 | `next.slice` | `-2_000_000` | safety floor | defer (H4 follow-up): recovery-package.ts | Outside this task's paths: package-copy and child-process timeouts. |
|
|
28
|
+
| src/cli/recovery-package.ts:21:100 | `options.timeoutMs ?? 60_000` | `60_000` | operational | defer (H4 follow-up): recovery-package.ts | Outside this task's paths: package-copy and child-process timeouts. |
|
|
29
|
+
| src/cli/recovery-package.ts:22:61 | `setTimeout` | `(options.timeoutMs ?? 60_000) ` | operational | defer (H4 follow-up): recovery-package.ts | Outside this task's paths: package-copy and child-process timeouts. |
|
|
30
|
+
| src/cli/recovery-package.ts:22:83 | `options.timeoutMs ?? 60_000` | `60_000` | operational | defer (H4 follow-up): recovery-package.ts | Outside this task's paths: package-copy and child-process timeouts. |
|
|
31
|
+
| src/cli/recovery-package.ts:110:128 | `timeoutMs` | `30_000` | operational | defer (H4 follow-up): recovery-package.ts | Outside this task's paths: package-copy and child-process timeouts. |
|
|
32
|
+
| src/cli/recovery-package.ts:121:99 | `timeoutMs` | `30_000` | operational | defer (H4 follow-up): recovery-package.ts | Outside this task's paths: package-copy and child-process timeouts. |
|
|
33
|
+
| src/cli/recovery-package.ts:153:115 | `timeoutMs` | `180_000` | operational | defer (H4 follow-up): recovery-package.ts | Outside this task's paths: package-copy and child-process timeouts. |
|
|
34
|
+
| src/cli/terminal-recovery.ts:178:7 | `MAX_WAIT_MS` | `10 * 60 * 1000` | operational | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
35
|
+
| src/cli/terminal-recovery.ts:179:14 | `MAX_COMMAND_MS` | `30000` | operational | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
36
|
+
| src/cli/terminal-recovery.ts:181:7 | `EXIT_SLICE_MS` | `5000` | operational | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
37
|
+
| src/cli/terminal-recovery.ts:183:7 | `MAP_POLL_MS` | `1000` | operational | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
38
|
+
| src/cli/terminal-recovery.ts:222:66 | `argv.slice` | `2` | contract | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
39
|
+
| src/cli/terminal-recovery.ts:239:88 | `argv.slice` | `2` | contract | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
40
|
+
| src/cli/terminal-recovery.ts:472:61 | `JSON.stringify(value).length > 32 * 1024` | `32 * 1024` | safety floor | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
41
|
+
| src/cli/terminal-recovery.ts:473:101 | `value.launchId.length > 128` | `128` | safety floor | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
42
|
+
| src/cli/terminal-recovery.ts:473:141 | `value.launcherSignature.length > 256` | `256` | safety floor | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
43
|
+
| src/cli/terminal-recovery.ts:808:113 | `timeout` | `0` | contract | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
44
|
+
| src/cli/terminal-recovery.ts:829:75 | `timeoutMs` | `600_000` | test seam | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
45
|
+
| src/cli/terminal-recovery.ts:838:35 | `deadline` | `5000` | operational | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
46
|
+
| src/cli/terminal-recovery.ts:842:23 | `Bun.sleep` | `100` | operational | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
47
|
+
| src/cli/terminal-recovery.ts:854:127 | `timeoutMs` | `600_000` | test seam | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
48
|
+
| src/cli/terminal-recovery.ts:928:32 | `Math.max` | `1` | operational | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
49
|
+
| src/cli/terminal-recovery.ts:941:77 | `timeoutMs` | `600_000` | test seam | defer (H4 follow-up): terminal-recovery.ts | Outside this task's paths. MAX_WAIT_MS is the ceiling every terminal wait is clamped to, so the idle wait setting cannot exceed it; the poll slices and the 5 s close confirmation stay with it. |
|
|
50
|
+
| src/cli/upgrade-interactive.ts:116:100 | `peer.state.padEnd` | `7` | contract | defer (H4 follow-up): upgrade-interactive.ts | Outside this task's paths: a one-minute refresh cadence of an interactive screen. |
|
|
51
|
+
| src/cli/upgrade-interactive.ts:116:139 | `KINDS[peerKind(p, peer)].padEnd` | `8` | contract | defer (H4 follow-up): upgrade-interactive.ts | Outside this task's paths: a one-minute refresh cadence of an interactive screen. |
|
|
52
|
+
| src/cli/upgrade-interactive.ts:165:83 | `clock(io) - lastWaitAt >= 60_000` | `60_000` | operational | defer (H4 follow-up): upgrade-interactive.ts | Outside this task's paths: a one-minute refresh cadence of an interactive screen. |
|
|
53
|
+
| src/cli/upgrade-interactive.ts:174:59 | `clock(io) - lastWaitAt >= 60_000` | `60_000` | operational | defer (H4 follow-up): upgrade-interactive.ts | Outside this task's paths: a one-minute refresh cadence of an interactive screen. |
|
|
54
|
+
| src/cli/upgrade-interactive.ts:259:80 | `reason.slice` | `500` | safety floor | defer (H4 follow-up): upgrade-interactive.ts | Outside this task's paths: a one-minute refresh cadence of an interactive screen. |
|
|
55
|
+
| src/cli/upgrade-interactive.ts:287:112 | `reason.slice` | `500` | safety floor | defer (H4 follow-up): upgrade-interactive.ts | Outside this task's paths: a one-minute refresh cadence of an interactive screen. |
|
|
56
|
+
| src/cli/upgrade-labels.ts:17:42 | `ms < 90_000` | `90_000` | contract | keep: presentation | A label threshold or a line index, not a wait. |
|
|
57
|
+
| src/cli/upgrade-labels.ts:17:99 | `ms < 5_400_000` | `5_400_000` | contract | keep: presentation | A label threshold or a line index, not a wait. |
|
|
58
|
+
| src/cli/upgrade-labels.ts:27:75 | `lines.push` | `0` | operational | keep: presentation | A label threshold or a line index, not a wait. |
|
|
59
|
+
| src/cli/upgrade-presentation.ts:35:28 | `Math.max` | `0` | contract | keep: contract | A format, protocol or arithmetic constant. |
|
|
60
|
+
| src/cli/upgrade-presentation.ts:36:17 | `seconds < 60` | `60` | contract | keep: contract | A format, protocol or arithmetic constant. |
|
|
61
|
+
| src/cli/upgrade-presentation.ts:38:17 | `minutes < 60` | `60` | contract | keep: contract | A format, protocol or arithmetic constant. |
|
|
62
|
+
| src/cli/upgrade-presentation.ts:39:76 | `minutes % 60` | `60` | contract | keep: contract | A format, protocol or arithmetic constant. |
|
|
63
|
+
| src/cli/upgrade-presentation.ts:39:89 | `String(minutes % 60).padStart` | `2` | contract | keep: contract | A format, protocol or arithmetic constant. |
|
|
64
|
+
| src/cli/upgrade-presentation.ts:171:40 | `points.length > 512` | `512` | safety floor | keep: safety floor | A size or count cap that protects data or the host; never loosenable here. |
|
|
65
|
+
| src/cli/upgrade-presentation.ts:171:65 | `points.slice` | `509` | safety floor | keep: safety floor | A size or count cap that protects data or the host; never loosenable here. |
|
|
66
|
+
| src/cli/upgrade-runtime.ts:26:7 | `UNMANAGED_RECONNECT_WAIT_MS` | `90000` | operational | convert: recovery.unmanaged_reconnect_wait_s (floor = 90 s) | Read from the project's own config at the start of the wait; unset is the old constant. |
|
|
67
|
+
| src/cli/upgrade-runtime.ts:28:7 | `RECONNECT_WAIT_MS` | `600000` | operational | convert: recovery.reconnect_wait_s (floor = 600 s) | Read from the project's own config at the start of the wait; unset is the old constant. |
|
|
68
|
+
| src/cli/upgrade-runtime.ts:65:72 | `timeoutMs` | `610_000` | operational | keep: orca runner timeout | One Orca command is bounded by terminal-recovery's own ten-minute ceiling (MAX_WAIT_MS) plus 10 s; raising the reconnect wait must not raise it, and lowering it below that ceiling would cut a wait the ceiling allows. |
|
|
69
|
+
| src/cli/upgrade-runtime.ts:79:7 | `RECOVERY_CONTROL_TIMEOUT_MS` | `30000` | operational | convert: recovery.control_timeout_s (floor = 30 s) | Read from the project's own config at the start of the wait; unset is the old constant. |
|
|
70
|
+
| src/cli/upgrade-runtime.ts:231:166 | `(Array.isArray(response.recovery?.blockers) ? response.recov` | `20` | safety floor | keep: safety floor | A bound on blocker text copied into a receipt. |
|
|
71
|
+
| src/cli/upgrade-runtime.ts:231:200 | `b.slice` | `200` | safety floor | keep: safety floor | A bound on blocker text copied into a receipt. |
|
|
72
|
+
| src/cli/upgrade-runtime.ts:248:69 | `timeoutMs` | `10_000` | operational | keep: installer probe | A version probe of the shared Claude plugin installer. A short fixed probe, not a wait a person tunes. |
|
|
73
|
+
| src/cli/upgrade-runtime.ts:393:106 | `timeoutMs` | `180_000` | operational | keep: global install timeout | `bun add -g` is a global effect with no project, so no project config can own it; and it is not a shorter-is-safe wait. |
|
|
74
|
+
| src/cli/upgrade-runtime.ts:412:61 | `waitForIdle` | `120_000` | operational | convert: recovery.terminal_idle_wait_s (30-600 s) | Read from the project's own config at the start of the wait; unset is the old constant. |
|
|
75
|
+
| src/cli/upgrade-runtime.ts:510:45 | `waitForIdle` | `120_000` | operational | convert: recovery.terminal_idle_wait_s (30-600 s) | Read from the project's own config at the start of the wait; unset is the old constant. |
|
|
76
|
+
| src/cli/upgrade-runtime.ts:562:32 | `Math.min` | `1000` | operational | keep: polling slice | A poll or sleep slice inside a bounded wait (the bound is the setting); not a wait. |
|
|
77
|
+
| src/cli/upgrade-runtime.ts:579:28 | `Math.min` | `1000` | operational | keep: polling slice | A poll or sleep slice inside a bounded wait (the bound is the setting); not a wait. |
|
|
78
|
+
| src/cli/upgrade-runtime.ts:583:125 | `timeoutMs` | `3000` | operational | keep: orca show timeout | One `orca terminal show` read inside the attachment poll; the poll's bound is the setting. |
|
|
79
|
+
| src/cli/upgrade-runtime.ts:698:49 | `waitForIdle` | `600_000` | operational | keep: idle wait before the close | waitForIdle(binding, 600_000) before a terminal is closed is bounded by the source's preparation lease, a fixed ten minutes (daemon.ts armRecoveryLease): a longer wait expires the lease, a shorter one cuts the floor of a person-visible wait. |
|
|
80
|
+
| src/cli/upgrade-runtime.ts:955:23 | `sleep` | `1000` | operational | keep: polling slice | A poll or sleep slice inside a bounded wait (the bound is the setting); not a wait. |
|
|
81
|
+
| src/cli/upgrade-runtime.ts:973:151 | `timeoutMs` | `180_000` | operational | keep: global install timeout | `bun add -g` is a global effect with no project, so no project config can own it; and it is not a shorter-is-safe wait. |
|
|
82
|
+
| src/cli/upgrade.ts:111:7 | `MAX_RECOVERY_DELEGATIONS` | `256` | safety floor | keep: safety floor | Delegation count cap. |
|
|
83
|
+
| src/cli/upgrade.ts:565:105 | `idleTimeoutMs` | `600_000` | test seam | keep: test seam | `runRecovery`'s idleTimeoutMs default is the 600 s source-quiet wait, bounded by the source's ten-minute lease; the parameter is a test seam. |
|
|
84
|
+
| src/cli/upgrade.ts:751:43 | `deadline` | `30_000` | operational | convert: recovery.shutdown_wait_s (floor = 30 s) | Read from the project's own config at the start of the wait; unset is the old constant. |
|
|
85
|
+
| src/hub/control-client.ts:11:14 | `PROTOCOL` | `16` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
86
|
+
| src/hub/control-client.ts:21:17 | `backoff` | `250` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
87
|
+
| src/hub/control-client.ts:26:37 | `includes` | `1006` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
88
|
+
| src/hub/control-client.ts:30:26 | `Math.min` | `1000` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
89
|
+
| src/hub/control-client.ts:30:42 | `Math.min` | `2` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
90
|
+
| src/hub/control-client.ts:73:97 | `status.controlPort > 65535` | `65535` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
91
|
+
| src/hub/control-client.ts:113:62 | `timeoutMs` | `3000` | test seam | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
92
|
+
| src/hub/control-client.ts:170:53 | `timeoutMs` | `30_000` | test seam | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
93
|
+
| src/hub/lifecycle.ts:23:68 | `timeoutMs` | `3000` | test seam | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
94
|
+
| src/hub/lifecycle.ts:97:32 | `SHUTDOWN_DEADLINE_MS` | `15_000` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
95
|
+
| src/hub/lifecycle.ts:114:37 | `attempt < 100` | `100` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
96
|
+
| src/hub/lifecycle.ts:173:35 | `deadline` | `12_000` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
97
|
+
| src/hub/lifecycle.ts:178:23 | `Bun.sleep` | `100` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
98
|
+
| src/hub/lifecycle.ts:210:33 | `deadline` | `10_000` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
99
|
+
| src/hub/lifecycle.ts:217:21 | `Bun.sleep` | `100` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
100
|
+
| src/hub/manager.ts:17:7 | `MANAGER_OWNER_DB_BUSY_TIMEOUT_MS` | `5000` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
101
|
+
| src/hub/manager.ts:30:7 | `CONTROL_TIMEOUT` | `3000` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
102
|
+
| src/hub/manager.ts:34:87 | `error.message.slice` | `300` | safety floor | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
103
|
+
| src/hub/manager.ts:72:76 | `status.port > 65535` | `65535` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
104
|
+
| src/hub/manager.ts:161:25 | `nominalMs` | `10_000` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
105
|
+
| src/hub/manager.ts:180:78 | `maxRequestBodySize` | `1024` | safety floor | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
106
|
+
| src/hub/manager.ts:207:33 | `options.orphanWatchMs ?? 10_000` | `10_000` | test seam | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
107
|
+
| src/hub/manager.ts:251:33 | `deadline` | `8000` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
108
|
+
| src/hub/manager.ts:262:54 | `Bun.sleep` | `100` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
109
|
+
| src/hub/manager.ts:274:73 | `Bun.sleep` | `25` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
110
|
+
| src/hub/manager.ts:291:21 | `Bun.sleep` | `25` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
111
|
+
| src/hub/ports.ts:6:14 | `BASE_PORT` | `4600` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
112
|
+
| src/hub/ports.ts:7:14 | `STRIDE` | `10` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
113
|
+
| src/hub/ports.ts:9:14 | `CONTROL` | `0` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
114
|
+
| src/hub/ports.ts:10:14 | `CODEX_APP` | `1` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
115
|
+
| src/hub/ports.ts:11:14 | `CODEX_PROXY` | `2` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
116
|
+
| src/hub/ports.ts:13:14 | `SWITCHYARD` | `3` | contract | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
117
|
+
| src/hub/ports.ts:27:22 | `attempt` | `0` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
118
|
+
| src/hub/ports.ts:30:76 | `attempt >= 500` | `500` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
119
|
+
| src/hub/ports.ts:31:57 | `Atomics.wait` | `4` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
120
|
+
| src/hub/ports.ts:31:62 | `Atomics.wait` | `0` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
121
|
+
| src/hub/ports.ts:31:65 | `Atomics.wait` | `0` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
122
|
+
| src/hub/ports.ts:31:68 | `Atomics.wait` | `10` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
123
|
+
| src/hub/recovery-continuity.ts:9:14 | `RECOVERY_CONTINUITY_BUSY_TIMEOUT_MS` | `3000` | operational | defer (H4 follow-up): SQLite busy timeouts | Outside this task's paths: database busy timeouts that protect receipts; a safety bound before a tunable. |
|
|
124
|
+
| src/hub/recovery-continuity.ts:10:7 | `MAX_BOOKMARK_BYTES` | `16 * 1024` | safety floor | defer (H4 follow-up): SQLite busy timeouts | Outside this task's paths: database busy timeouts that protect receipts; a safety bound before a tunable. |
|
|
125
|
+
| src/hub/recovery-error.ts:30:82 | `(stack ?? ).split(\n).filter(line => /^\s*at /.test(line)).s` | `8` | safety floor | keep: safety floor | A size or count cap that protects data or the host; never loosenable here. |
|
|
126
|
+
| src/hub/recovery-error.ts:30:128 | `sanitize(line.trim()).slice` | `400` | safety floor | keep: safety floor | A size or count cap that protects data or the host; never loosenable here. |
|
|
127
|
+
| src/hub/recovery-store.ts:8:7 | `RUNNER_DB_BUSY_TIMEOUT_MS` | `3000` | operational | defer (H4 follow-up): SQLite busy timeouts | Outside this task's paths: database busy timeouts that protect receipts; a safety bound before a tunable. |
|
|
128
|
+
| src/hub/recovery-store.ts:152:79 | `waitMs` | `5000` | test seam | defer (H4 follow-up): SQLite busy timeouts | Outside this task's paths: database busy timeouts that protect receipts; a safety bound before a tunable. |
|
|
129
|
+
| src/hub/recovery-store.ts:159:56 | `setTimeout` | `100` | operational | defer (H4 follow-up): SQLite busy timeouts | Outside this task's paths: database busy timeouts that protect receipts; a safety bound before a tunable. |
|
|
130
|
+
| src/hub/restart.ts:11:14 | `RESTART_SCHEMA_VERSION` | `1` | contract | keep: contract | A format, protocol or arithmetic constant. |
|
|
131
|
+
| src/hub/restart.ts:74:74 | `e.id.length <= 256` | `256` | contract | keep: contract | A format, protocol or arithmetic constant. |
|
|
132
|
+
| src/hub/restart.ts:74:152 | `e.trace.length <= 256` | `256` | contract | keep: contract | A format, protocol or arithmetic constant. |
|
|
133
|
+
| src/hub/snapshots.ts:36:23 | `Math.max` | `1` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
134
|
+
| src/hub/snapshots.ts:41:7 | `SNAPSHOT_TIMEOUT_MS` | `10000` | operational | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
135
|
+
| src/hub/snapshots.ts:55:21 | `++entries > 20000` | `20000` | safety floor | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
136
|
+
| src/hub/snapshots.ts:55:38 | `depth > 32` | `32` | safety floor | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
137
|
+
| src/hub/snapshots.ts:182:7 | `HEAD_LOG_TAIL_BYTES` | `4096` | safety floor | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
138
|
+
| src/hub/snapshots.ts:183:7 | `HEAD_LOG_MAX_APPEND_BYTES` | `128 * 1024` | safety floor | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
139
|
+
| src/hub/snapshots.ts:184:7 | `HEAD_LOG_MAX_MOVES` | `64` | safety floor | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
140
|
+
| src/hub/snapshots.ts:239:88 | `named.size > 4096` | `4096` | safety floor | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|
|
141
|
+
| src/hub/snapshots.ts:619:31 | `limit` | `20` | test seam | defer (H4 follow-up): hub process lifecycle | Outside this task's paths: daemon shutdown, manager, port and control-client timing. |
|