@logicseek/hello-cc 1.0.0 → 1.0.1

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 (35) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/README.md +32 -0
  3. package/README.zh-CN.md +31 -0
  4. package/docs/guide.md +58 -0
  5. package/docs/guide.zh-CN.md +55 -0
  6. package/lib/cli/app.mjs +2 -0
  7. package/lib/cli/commands/coordination.mjs +3 -1
  8. package/lib/cli/commands/gc.mjs +182 -32
  9. package/lib/cli/commands/misc.mjs +15 -0
  10. package/lib/cli/commands/peer.mjs +21 -5
  11. package/lib/process/identity.mjs +30 -0
  12. package/lib/runtime/buffer-directory-lease.mjs +2 -1
  13. package/lib/runtime/client.mjs +3 -0
  14. package/lib/shared/file-lock.mjs +11 -4
  15. package/lib/shared/socket-lock-worker.mjs +73 -24
  16. package/lib/terminal/tmux.mjs +53 -23
  17. package/lib/web/buffer-gc-runtime.mjs +2 -2
  18. package/lib/web/project-contexts.mjs +6 -1
  19. package/lib/web/runtime-main.mjs +3 -0
  20. package/lib/web/startup.mjs +4 -2
  21. package/package.json +2 -2
  22. package/scripts/regression.mjs +95 -98
  23. package/docs/architecture-split-review.md +0 -217
  24. package/docs/current-state-review-2026-08.md +0 -341
  25. package/docs/defect-review-2026-07.md +0 -382
  26. package/docs/layout-split-stack-audit.md +0 -298
  27. package/docs/superpowers/plans/2026-08-03-runtime-safety-plan.md +0 -294
  28. package/docs/superpowers/plans/2026-08-03-v1-data-identity-plan.md +0 -400
  29. package/docs/superpowers/plans/2026-08-03-v1-release-verification-plan.md +0 -284
  30. package/docs/superpowers/plans/2026-08-03-web-api-hardening-plan.md +0 -303
  31. package/docs/superpowers/plans/2026-08-04-runtime-buffer-gc-two-phase.md +0 -71
  32. package/docs/superpowers/specs/2026-08-03-runtime-safety-design.md +0 -117
  33. package/docs/superpowers/specs/2026-08-03-v1-data-identity-design.md +0 -120
  34. package/docs/superpowers/specs/2026-08-03-v1-release-verification-design.md +0 -117
  35. package/docs/superpowers/specs/2026-08-03-web-api-hardening-design.md +0 -104
@@ -1,298 +0,0 @@
1
- # Layout Split Stack Audit
2
-
3
- Date: 2026-06-14
4
-
5
- Audit branch: `audit/layout-split-stack-20260614`
6
-
7
- Reviewed range: `origin/master..HEAD`
8
-
9
- - Base: `4969100` (`origin/master`, published as `@logicseek/hello-cc@0.1.5`)
10
- - Audited head: `4283234`
11
- - Commit count: 40
12
-
13
- This document audits the local architecture split stack before any push or npm
14
- publish. It is intentionally on a dedicated audit branch/worktree so the active
15
- `master` implementation stack is not rewritten during review.
16
-
17
- ## Review Standard
18
-
19
- Each commit is classified against `docs/architecture.md`:
20
-
21
- - `keep`: the commit directly moves code toward a documented product boundary.
22
- - `keep-with-cleanup`: the direction is right, but package surface, shim policy,
23
- or module placement still needs a cleanup decision before release.
24
- - `squash/rebuild`: the code is useful, but the commit exists mostly as an
25
- intermediate flat extraction and should be folded into a product-boundary
26
- commit if a clean release branch is rebuilt.
27
- - `decision-needed`: the final location or public surface is not settled.
28
- - `docs-only`: documentation or process record.
29
-
30
- The important distinction is code shape versus history shape. A commit can be
31
- useful for reaching the current code state while still being a poor standalone
32
- release-history commit.
33
-
34
- ## Team Review Split
35
-
36
- Parent task: `#232`
37
-
38
- - `#234 lead-audit`: maintain this matrix and merge review feedback.
39
- - `#236 review-core-db`: core, coordination, db, peers, session semantics.
40
- - `#235 review-runtime-web`: runtime, web, terminal, integrations, release,
41
- shared helper placement.
42
- - `#237 review-package-surface`: top-level `lib/*.mjs` compatibility shims,
43
- npm package surface, and release-note risk.
44
-
45
- ## Summary
46
-
47
- The current `HEAD` is not a random bad refactor. The final code shape has mostly
48
- been corrected toward the target architecture:
49
-
50
- - coordination logic under `lib/core/coordination`
51
- - peer/session semantics under `lib/core/peers` and `lib/core/sessions`
52
- - schema and stores under `lib/db`
53
- - runtime state/client/project helpers under `lib/runtime`
54
- - tmux under `lib/terminal`
55
- - Web runtime helpers under `lib/web`
56
- - provider/hooks/shims under `lib/integrations`
57
- - small utilities under `lib/shared`
58
- - text rendering/help under `lib/ui`
59
- - release helpers under `lib/release`
60
-
61
- The problem is the history shape. The first 25 local commits were mostly
62
- "extract a helper from `bin/hcc.mjs` into a top-level `lib/*.mjs` file". That
63
- was useful as a safety step, but it does not match the architecture design by
64
- itself. Later commits then moved many of those flat files into real product
65
- boundaries.
66
-
67
- Therefore:
68
-
69
- 1. If the project keeps the current `master` history, do not keep making broad
70
- split commits. Finish only package-surface cleanup, run full validation, bump
71
- the version, and publish/sync with a clear changelog.
72
- 2. If the project wants clean history for this major refactor, create a rebuild
73
- branch from `origin/master` and replay the final shape as fewer architectural
74
- commits. Do not rewrite the active `master` while peers use it.
75
-
76
- ## Phase Classification
77
-
78
- ### Phase 1: Early Flat Extractions
79
-
80
- These commits reduced `bin/hcc.mjs`, but mostly created top-level helper modules
81
- before the design document existed. They should be treated as
82
- `squash/rebuild` if a clean branch is made.
83
-
84
- | Commit | Area | Classification | Reason |
85
- | --- | --- | --- | --- |
86
- | `1bb1967` | providers + tmux | `squash/rebuild` | Mixed two product boundaries in one top-level extraction; should become integrations/provider and terminal/tmux commits. |
87
- | `e155d5a` | locks | `squash/rebuild` | Useful code, but final home is `lib/core/coordination/locks.mjs`, not top-level `lib/locks.mjs`. |
88
- | `9ab464d` | team planning | `squash/rebuild` | Same pattern; final home is `lib/core/coordination/teams.mjs`. |
89
- | `807fa96` | peer identity | `squash/rebuild` | Useful extraction, but identity is split between integration discovery and core peer semantics later. |
90
- | `494d38f` | peer format | `squash/rebuild` | Good low-level helper, but should land with peer-boundary cleanup rather than a standalone flat helper commit. |
91
- | `e2b745d` | project registry | `squash/rebuild` | Final boundary is runtime/project registry. |
92
- | `e4c4497` | project context | `squash/rebuild` | Final boundary is runtime/project context. |
93
- | `dec3e2e` | handoff | `decision-needed` | `lib/handoff.mjs` remains top-level; decide core coordination semantics versus CLI command helper. |
94
- | `61b02a2` | timeline | `squash/rebuild` | Final boundary is core coordination timeline. |
95
- | `62ede11` | runtime state | `squash/rebuild` | Final boundary is `lib/runtime/state.mjs`. |
96
- | `7d885f1` | task liveness | `squash/rebuild` | Final boundary is core peer liveness. |
97
- | `3f0cc7e` | session launch | `decision-needed` | Current compatibility file bridges core session launch and terminal/tmux helpers; keep an eye on dependency direction. |
98
- | `b07e9b5` | automation | `squash/rebuild` | Final boundary is core coordination automation. |
99
- | `428bbf3` | state render | `squash/rebuild` | Final boundary is UI state rendering. |
100
- | `8a6120f` | tmux pane | `squash/rebuild` | Should be folded into terminal/tmux movement. |
101
- | `3ec062b` | help text | `squash/rebuild` | Final boundary is UI help. |
102
- | `7e8068c` | uninstall help | `squash/rebuild` | Should be folded into UI help extraction. |
103
- | `9ed79b6` | message store | `squash/rebuild` | Final boundary is core coordination messages. |
104
- | `07ddcc9` | runtime client | `squash/rebuild` | Final boundary is `lib/runtime/client.mjs`. |
105
- | `c06e55d` | web runtime server helpers | `squash/rebuild` | Useful step, but final boundary is `lib/web/runtime.mjs`; route/session/server split still pending. |
106
- | `fe36930` | task store | `squash/rebuild` | Final boundary is core coordination tasks. |
107
- | `3bd0782` | task CLI parsing | `keep-with-cleanup` | This is a CLI-specific helper and can remain near CLI until `lib/cli/*` exists. |
108
- | `61538fc` | peer bindings | `squash/rebuild` | Final split crosses core peer bindings and db peer store. |
109
- | `787857f` | CLI runtime | `keep-with-cleanup` | Still not the final `lib/cli/context.mjs` layout, but it is a valid CLI/runtime entrypoint reduction. |
110
- | `00ac7ba` | coordination state | `squash/rebuild` | Useful factory boundary, but should be evaluated with core coordination dependencies. |
111
-
112
- ### Phase 2: Architecture Documentation And First Boundary Correction
113
-
114
- | Commit | Area | Classification | Reason |
115
- | --- | --- | --- | --- |
116
- | `94d63c0` | architecture docs | `docs-only` | Correctly establishes the target layout. |
117
- | `76d5181` | web peer actions | `squash/rebuild` | Good product boundary direction, but final import path is corrected later under `lib/web/peer-actions.mjs`. |
118
- | `265284a` | broad architecture alignment | `keep-with-cleanup` | Correct direction, but too broad for ideal history; should become several product-boundary commits on a rebuild branch. Also review whether SQL/transaction-heavy task code belongs in `lib/core/coordination/tasks.mjs` or should split pure task policy from a db store. |
119
-
120
- ### Phase 3: Product-Boundary Cleanup Commits
121
-
122
- These commits are much closer to the target design. They are the model for the
123
- rebuild branch if one is created.
124
-
125
- | Commit | Area | Classification | Reason |
126
- | --- | --- | --- | --- |
127
- | `294eb2e` | peer layout boundaries | `keep` | Moves peer semantics toward `core/peers`, `db/stores`, and integrations boundaries. |
128
- | `a3eabd8` | tmux adapter | `keep` | Clear terminal adapter boundary. |
129
- | `fb9c35a` | shared JSON file helpers | `keep-with-cleanup` | Shared utility is appropriate; keep `lib/json-file.mjs` compat because it was already published in `0.1.5`. |
130
- | `77c098d` | provider commands | `keep` | Correct integrations boundary. |
131
- | `6bbe4a0` | project context | `keep` | Correct runtime boundary. |
132
- | `be7c882` | session launch helpers | `decision-needed` | Direction is mostly correct, but compat surface exports both core session and terminal/tmux helpers. Review dependency direction before release. |
133
- | `ffc42a7` | setup hook installers | `keep` | Correct integrations/hooks boundary. |
134
- | `1bd110f` | setup shims | `keep` | Correct integrations/shims boundary. |
135
- | `c191c72` | shim script generator | `keep` | Correct integrations/shims/script boundary. |
136
- | `11fd4f6` | CLI errors | `keep` | Correct small shared utility boundary with compatibility re-export. |
137
-
138
- ### Phase 4: Review And Policy Docs
139
-
140
- | Commit | Area | Classification | Reason |
141
- | --- | --- | --- | --- |
142
- | `19c0856` | split review | `docs-only` | Captures the historical concern and branch strategy. |
143
- | `4283234` | package surface policy | `docs-only` | Captures npm `0.1.5` fact, version-bump requirement, and A/B/C shim policy. |
144
-
145
- ## Initial Recommendations
146
-
147
- ### Use A New Branch
148
-
149
- Yes. This is a major refactor stack and should not be pushed or published
150
- directly just because `master` is currently green. Use this audit branch for
151
- review. If the team chooses clean history, create a separate rebuild branch from
152
- `origin/master`, not from current `master`.
153
-
154
- Suggested rebuild branch:
155
-
156
- ```bash
157
- git worktree add ../hello-cc-layout-rebuild -b rebuild/layout-split-20260614 origin/master
158
- ```
159
-
160
- Suggested rebuilt commit order:
161
-
162
- 1. Architecture docs.
163
- 2. Core coordination modules: locks, teams, messages, tasks, timeline,
164
- automation, liveness-related coordination state.
165
- 3. Core peer/session modules and db peer store.
166
- 4. Runtime modules: paths, state, client, project registry, project context.
167
- 5. Terminal adapter: tmux.
168
- 6. Web modules: runtime, HTTP, peer actions, UI template.
169
- 7. Integrations: providers, hooks, shims, shim script, peer identity.
170
- 8. Shared/release/ui helpers.
171
- 9. Compatibility shim policy and package-surface release notes.
172
-
173
- ### Do Not Revert The Final Shape Blindly
174
-
175
- The final code shape is mostly aligned with the architecture document. The
176
- problem is the noisy path taken to get there. A rebuild should preserve the
177
- validated final behavior while changing the history granularity.
178
-
179
- ### Core/DB Review Findings
180
-
181
- The core/db review from `#236` and the parallel read-only subagent agree on the
182
- main shape:
183
-
184
- - Keep the final direction of `lib/core/coordination/*`, `lib/core/peers/*`,
185
- `lib/core/sessions/launch.mjs`, `lib/db/schema.mjs`,
186
- `lib/db/stores/peers.mjs`, and `lib/shared/errors.mjs`.
187
- - Rebuild the early top-level coordination/peer/session helper commits into
188
- product-boundary commits if clean history is chosen.
189
- - Do not treat `lib/handoff.mjs`, `lib/session-launch.mjs`, or
190
- `lib/coordination-state.mjs` as settled final architecture.
191
-
192
- Concrete cleanup items from that review:
193
-
194
- - `lib/core/coordination/tasks.mjs` is currently SQL/transaction-heavy. Split
195
- pure task lifecycle/takeover/team policy from DB store operations, or move the
196
- store-style SQL operations under `lib/db/stores/tasks.mjs`.
197
- - `lib/core/coordination/automation.mjs` and
198
- `lib/core/coordination/timeline.mjs` depend on top-level `lib/format.mjs` for
199
- `shellQuoteArg` / `compactText`. Move dependency-light text helpers to
200
- `lib/shared/text.mjs` or keep rendering concerns in the UI/CLI layer.
201
- - `lib/handoff.mjs` mixes CLI input normalization with runtime Git changed-file
202
- discovery. Split handoff product semantics from CLI/runtime file inspection.
203
- - `lib/session-launch.mjs` re-exports both core session helpers and
204
- terminal/tmux helpers. That is acceptable only as a compatibility entrypoint;
205
- do not let it become the conceptual module boundary.
206
- - `lib/coordination-state.mjs` is useful as an interim assembler, but it mixes
207
- DB queries, timeline, automation, hook context, status summary, and message
208
- ack batching. Later split it into core state services plus CLI/Web adapters.
209
-
210
- ### Runtime/Web/Integrations Review Findings
211
-
212
- The runtime/web/terminal/integrations review from `#235` and the parallel
213
- read-only subagent agree on the main shape:
214
-
215
- - Keep the final direction of `lib/terminal/tmux.mjs`.
216
- - Keep the final direction of `lib/integrations/providers.mjs`,
217
- `lib/integrations/hooks.mjs`, `lib/integrations/shims.mjs`, and
218
- `lib/integrations/shims/script.mjs`.
219
- - Keep the final direction of `lib/release/*`, `lib/shared/errors.mjs`, and
220
- `lib/shared/json-file.mjs`.
221
- - Keep the runtime and Web movement as directionally correct:
222
- `lib/runtime/{paths,state,client,projects,project-context}.mjs` and
223
- `lib/web/{http,runtime,ui-template,peer-actions}.mjs`.
224
-
225
- Concrete cleanup items from that review:
226
-
227
- - `lib/runtime/client.mjs` and `lib/runtime/state.mjs` import `runtimeApiUrl`
228
- from `lib/web/runtime.mjs`. That creates a runtime -> web reverse dependency.
229
- Move the URL helper into `lib/runtime`, `lib/shared`, or inject it from the
230
- caller before claiming strict dependency direction.
231
- - `lib/web/runtime.mjs` and `lib/web/peer-actions.mjs` import CLI parsing
232
- helpers from `lib/cli-args.mjs`. Move shared option parsing such as
233
- `intOpt`/`required` to a dependency-light shared helper, or inject parsing at
234
- the route boundary.
235
- - `lib/web/peer-actions.mjs` imports `normalizeStateResources` from
236
- `lib/ui/state-render.mjs`. Move non-render normalization out of the UI layer,
237
- or keep the dependency at a CLI/Web adapter edge.
238
- - `cmdWeb()` in `bin/hcc.mjs` still owns server lifecycle, session manager,
239
- WebSocket terminal transport, tmux/PTY orchestration, external-buffer
240
- adoption, and shutdown cleanup. Future work should split this by subsystem;
241
- do not continue random helper extraction from it.
242
-
243
- No immediate runtime blocker was found. `#235` also reran `npm test` and got
244
- `FULL_REGRESSION_OK`.
245
-
246
- ### Decide Shim Policy Before Release
247
-
248
- Because `@logicseek/hello-cc@0.1.5` is already published from `4969100`, the
249
- next package version must be new. Before that publish:
250
-
251
- - Group A: already-published or CLI-facing top-level `lib/*.mjs` paths stay.
252
- - Group B: migration compatibility paths stay one release if needed and are
253
- documented as compatibility-only deep-import paths.
254
- - Group C: unpublished top-level shims with no internal use or compatibility
255
- value should be removed before release.
256
-
257
- Initial package-surface inventory:
258
-
259
- | Group | Paths | Current decision |
260
- | --- | --- | --- |
261
- | A: published in `0.1.5` | `lib/cli-args.mjs`, `lib/db-schema.mjs`, `lib/discover.mjs`, `lib/errors.mjs`, `lib/format.mjs`, `lib/guidance.mjs`, `lib/json-file.mjs`, `lib/package-meta.mjs`, `lib/release-notes.mjs`, `lib/runtime-paths.mjs`, `lib/setup.mjs`, `lib/shell-path.mjs`, `lib/shim-script.mjs`, `lib/web-http.mjs`, `lib/web-runtime.mjs`, `lib/web-ui-template.mjs` | Keep for the next release, even if some are now compatibility re-exports. Removing them would be a package-surface break. |
262
- | A: current internal top-level runtime refs | `lib/cli-runtime.mjs`, `lib/coordination-state.mjs`, `lib/handoff.mjs`, `lib/project-context.mjs`, `lib/task-cli.mjs`, `lib/tmux.mjs` | Keep until a focused cleanup moves current internal imports to the target directories. Do not delete these as pure compatibility shims today. |
263
- | B/C candidates: new re-export-only paths with no current runtime ref | `lib/automation.mjs`, `lib/help.mjs`, `lib/locks.mjs`, `lib/messages.mjs`, `lib/peer-bindings.mjs`, `lib/peer-format.mjs`, `lib/peer-identity.mjs`, `lib/project-registry.mjs`, `lib/provider-commands.mjs`, `lib/runtime-client.mjs`, `lib/runtime-state.mjs`, `lib/session-launch.mjs`, `lib/state-render.mjs`, `lib/task-liveness.mjs`, `lib/task-store.mjs`, `lib/team-planning.mjs`, `lib/timeline.mjs`, `lib/web-peer-actions.mjs` | Treat as C only if the project decides they have no migration compatibility value. Otherwise keep for one release as B and document them as compatibility-only deep imports. |
264
- | C: remove before publish | None confirmed yet | Do not delete by guess. A candidate becomes C only after checking it was not in `0.1.5`, is not imported internally, and has no release compatibility value. |
265
-
266
- ### Watch Items
267
-
268
- - `lib/handoff.mjs`: decide core coordination versus CLI command helper.
269
- - `lib/session-launch.mjs`: review mixed core session and terminal/tmux
270
- compatibility exports.
271
- - `lib/core/coordination/tasks.mjs`: split pure task policy from DB store style
272
- SQL/transactions.
273
- - `lib/core/coordination/{automation,timeline}.mjs`: remove dependency on
274
- top-level `lib/format.mjs`.
275
- - `lib/coordination-state.mjs`: keep as interim assembler, but split before
276
- claiming final architecture.
277
- - `lib/runtime/{client,state}.mjs`: remove reverse dependency on
278
- `lib/web/runtime.mjs`.
279
- - `lib/web/{runtime,peer-actions}.mjs`: remove direct dependency on CLI parsing
280
- helpers.
281
- - `lib/web/peer-actions.mjs`: remove direct dependency on UI state-render
282
- helpers for non-render normalization.
283
- - `scripts/regression.mjs`: current test coverage is valuable, but its size
284
- should be split after the architecture stack is stable.
285
- - `bin/hcc.mjs`: still contains large command and Web orchestration areas; do
286
- not continue extracting from it until this audit decides branch strategy.
287
-
288
- ## Current Status
289
-
290
- Peer feedback from `#235`, `#236`, and `#237` has been merged into this audit.
291
- The audit conclusion is:
292
-
293
- - The final code shape is mostly reasonable.
294
- - The early commit history is not clean architecture history.
295
- - Use a new rebuild branch from `origin/master` if clean history matters.
296
- - Keep the current `master` stack only if the project accepts noisy local
297
- history and completes the release cleanup items above before publish.
298
- - Do not resume release task `#233` until this audit decision is accepted.
@@ -1,294 +0,0 @@
1
- # Runtime Safety, Clock, GC, and Registry Implementation Plan
2
-
3
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
-
5
- **Goal:** Make clock, takeover, garbage collection, and project-registry decisions safe under sleep, PID reuse, runtime failure, and concurrent writers.
6
-
7
- **Architecture:** A clock-safety module owns persistent observation and grace. A buffer-GC planner is shared by CLI and runtime, while an authenticated runtime endpoint serializes deletion with active sessions. Registry updates use an owner-identified lock directory.
8
-
9
- **Tech Stack:** Node.js 24 ESM, `node:test`, `node:sqlite`, filesystem atomics, HTTP runtime API, tmux integration.
10
-
11
- ---
12
-
13
- ## File Map
14
-
15
- - Create `lib/core/coordination/clock-safety.mjs` and `test/clock-safety.test.mjs`.
16
- - Modify `lib/shared/clock-grace.mjs` to make grace extension atomic and observable.
17
- - Create `lib/runtime/buffer-gc.mjs` and `test/buffer-gc.test.mjs`.
18
- - Create `lib/shared/file-lock.mjs` and `test/file-lock.test.mjs`.
19
- - Modify `bin/hcc.mjs` for clock observation, runtime GC endpoint, safe CLI GC, and history flags.
20
- - Modify `lib/runtime/projects.mjs` for lock-protected registry merging.
21
- - Modify `lib/runtime/client.mjs` for the internal buffer-GC request.
22
- - Modify `lib/coordination-state.mjs`, task/lock paths, and `scripts/regression.mjs` for integration behavior.
23
-
24
- ### Task 1: Make grace extension atomic and classify observation decisions
25
-
26
- **Files:**
27
- - Create: `lib/core/coordination/clock-safety.mjs`
28
- - Create: `test/clock-safety.test.mjs`
29
- - Modify: `lib/shared/clock-grace.mjs:1-46`
30
-
31
- - [ ] **Step 1: Write failing pure-decision tests**
32
-
33
- ```js
34
- import test from 'node:test';
35
- import assert from 'node:assert/strict';
36
- import { decideClockSafety } from '../lib/core/coordination/clock-safety.mjs';
37
-
38
- test('live evidence crosses expiry without grace and requests renewal', () => {
39
- assert.deepEqual(decideClockSafety({ previous: 100, current: 1000, operation: 'ownership', candidates: [{ boundary: 500, evidence: 'live' }] }), {
40
- enterGrace: false,
41
- renewOwners: true,
42
- reason: 'verified-live'
43
- });
44
- });
45
-
46
- test('unknown evidence crossing expiry enters grace', () => {
47
- assert.equal(decideClockSafety({ previous: 100, current: 1000, operation: 'ownership', candidates: [{ boundary: 500, evidence: 'unknown' }] }).enterGrace, true);
48
- });
49
-
50
- test('GC crossing an age cutoff enters grace without owner candidates', () => {
51
- assert.equal(decideClockSafety({ previous: 100, current: 1000, operation: 'gc', gcCutoffs: [500] }).enterGrace, true);
52
- });
53
-
54
- test('verified dead evidence does not delay ownership', () => {
55
- assert.equal(decideClockSafety({ previous: 100, current: 1000, operation: 'ownership', candidates: [{ boundary: 500, evidence: 'dead' }] }).enterGrace, false);
56
- });
57
- ```
58
-
59
- - [ ] **Step 2: Run to verify RED**
60
-
61
- Run: `node --test test/clock-safety.test.mjs`
62
-
63
- Expected: FAIL because the decision module is missing.
64
-
65
- - [ ] **Step 3: Implement the pure decision and atomic SQL extension**
66
-
67
- `decideClockSafety` must return deterministic `{ enterGrace, renewOwners, reason }` from the supplied observation. Backward movement beyond five seconds always enters grace for unknown and GC age decisions. Long forward gaps enter grace only when they cross the relevant boundary.
68
-
69
- Replace grace overwrite SQL with:
70
-
71
- ```sql
72
- INSERT INTO meta(key, value) VALUES ('clock_grace_until', ?)
73
- ON CONFLICT(key) DO UPDATE SET value = CAST(
74
- MAX(CAST(meta.value AS INTEGER), CAST(excluded.value AS INTEGER)) AS TEXT
75
- )
76
- ```
77
-
78
- `writeClockGraceUntil` returns the persisted deadline and throws on write failure; it must not swallow exceptions.
79
-
80
- - [ ] **Step 4: Verify GREEN**
81
-
82
- Run: `node --test test/clock-safety.test.mjs`.
83
-
84
- Add a real in-memory SQLite test with two shorter/longer writes and assert the final value is the maximum. Run again and require PASS.
85
-
86
- - [ ] **Step 5: Commit**
87
-
88
- ```bash
89
- git add lib/core/coordination/clock-safety.mjs lib/shared/clock-grace.mjs test/clock-safety.test.mjs
90
- git commit -m "fix: make clock grace monotonic"
91
- ```
92
-
93
- ### Task 2: Observe clock safety before destructive ownership decisions
94
-
95
- **Files:**
96
- - Modify: `bin/hcc.mjs:413-471,728-751,1053-1120,1752-1810,2926-3005,5709-5725,6426-6538`
97
- - Modify: `lib/core/coordination/clock-safety.mjs`
98
- - Modify: `lib/coordination-state.mjs:37-105,191-220`
99
- - Modify: `lib/core/coordination/tasks.mjs:73-90`
100
- - Modify: `scripts/regression.mjs:2616-2820`
101
-
102
- - [ ] **Step 1: Add the CLI-only failing integration fixture**
103
-
104
- Create an isolated project with no local or global runtime pointer. Register a peer using the regression process PID and stored fingerprint, acquire a lock, move only wall-clock DB timestamps one day into the past, remove `clock_grace_until`, and attempt acquisition from another peer.
105
-
106
- Write the final expected assertion from the start:
107
-
108
- ```js
109
- if (attempt.status === 0 || !attempt.stderr.includes('LOCK_HELD')) {
110
- fail(`live owner was not protected after a CLI-only clock gap:\n${attempt.stderr}`);
111
- }
112
- ```
113
-
114
- From the same initial test, require an unchanged owner, renewed `expires_at`, and
115
- no blanket grace for the verified live owner. Add unknown-evidence and
116
- verified-dead variants before running RED.
117
-
118
- - [ ] **Step 2: Run to verify RED**
119
-
120
- Run: `npm run test:regression`.
121
-
122
- Expected: live-owner fixture demonstrates takeover/replacement under the current code.
123
-
124
- - [ ] **Step 3: Add the observation transaction**
125
-
126
- Export `observeClockSafety(db, { operation, candidates, gcCutoffs, nowSec })`. In one immediate transaction, read `clock_last_observed_at`, call `decideClockSafety`, extend grace to `nowSec + 120` only when `enterGrace` is true, and write the new watermark. Persist the maximum of the existing and proposed deadline. Return the decision and persisted grace. Verified-live evidence renews immediately without grace, verified-dead evidence proceeds without grace, and only unknown evidence receives the 120-second delay.
127
-
128
- Call it before lock acquire, task takeover, heartbeat/hook recovery, reaper, and GC. Do not call it from pure status/list/doctor paths. When it reports verified live owners, renew retained locks from `ttl_sec`. When grace persistence throws, abort the destructive command with `CLOCK_SAFETY_UNAVAILABLE`.
129
-
130
- The Web poller passes its wall/monotonic jump signal into the same observer and no longer maintains a separate grace algorithm.
131
-
132
- - [ ] **Step 4: Verify GREEN and nearby behavior**
133
-
134
- Run: `node --test test/clock-safety.test.mjs`.
135
-
136
- Run: `npm run test:regression`.
137
-
138
- Expected: live evidence renews immediately, dead evidence expires, unknown evidence enters grace, status/doctor remain read-only.
139
-
140
- - [ ] **Step 5: Commit**
141
-
142
- ```bash
143
- git add bin/hcc.mjs lib/core/coordination/clock-safety.mjs lib/coordination-state.mjs lib/core/coordination/tasks.mjs scripts/regression.mjs
144
- git commit -m "fix: protect CLI-only ownership after clock gaps"
145
- ```
146
-
147
- ### Task 3: Extract a buffer-GC planner and runtime arbitration endpoint
148
-
149
- **Files:**
150
- - Create: `lib/runtime/buffer-gc.mjs`
151
- - Create: `test/buffer-gc.test.mjs`
152
- - Modify: `bin/hcc.mjs:3005-3063,6426-6538,4675-5050`
153
- - Modify: `lib/runtime/client.mjs:7-35`
154
- - Modify: `scripts/regression.mjs:1841-1880,2866-3300,7019-7070`
155
-
156
- - [ ] **Step 1: Write failing planner tests with real files**
157
-
158
- In a temporary `bufs` directory create old protected, old dead, old unknown, and new files. Call:
159
-
160
- ```js
161
- const result = pruneBufferFiles({
162
- directories: [bufsDir],
163
- cutoffMs,
164
- protectedPaths: new Set([protectedFile]),
165
- unknownPaths: new Set([unknownFile]),
166
- dryRun: false
167
- });
168
- ```
169
-
170
- Assert protected/unknown/new remain, dead old is deleted, and counts are `{ deleted: 1, protected: 1, deferred: 1 }`.
171
-
172
- - [ ] **Step 2: Run to verify RED**
173
-
174
- Run: `node --test test/buffer-gc.test.mjs`.
175
-
176
- Expected: missing-module failure.
177
-
178
- - [ ] **Step 3: Implement the planner and endpoint**
179
-
180
- Implement `pruneBufferFiles` with absolute resolved paths, `lstat` regular-file/FIFO checks, one supplied cutoff, and identical dry-run/apply planning. It must not follow symlinks.
181
-
182
- Add authenticated `POST /api/runtime/gc-buffers`. The handler snapshots actual `outFile`, `inFile`, `resizeFile`, `pipeFile`, and external meta paths from every running session, groups them by actual directory, and calls the synchronous planner before returning counts.
183
-
184
- Manual CLI GC fixes `cutoffMs` before the request. If a runtime pointer exists and the endpoint returns unreachable/404/426, mark eligible buffers deferred and do not fall back to blind local deletion. With no runtime pointer, build live/unknown protection from external metadata fingerprints and verified tmux panes.
185
-
186
- - [ ] **Step 4: Verify RED-GREEN at the real boundary**
187
-
188
- Run planner tests. Then add runtime integration cases for active external files, active tmux FIFO, sibling-project actual directories, unreachable runtime, legacy metadata, and orphan old files.
189
-
190
- Run: `npm run test:regression`.
191
-
192
- Expected: active/unknown files remain, only proven old orphans are removed, and runtime failure reports deferred counts.
193
-
194
- - [ ] **Step 5: Commit**
195
-
196
- ```bash
197
- git add lib/runtime/buffer-gc.mjs test/buffer-gc.test.mjs lib/runtime/client.mjs bin/hcc.mjs scripts/regression.mjs
198
- git commit -m "fix: arbitrate buffer cleanup through runtime"
199
- ```
200
-
201
- ### Task 4: Make GC retention explicit and clock-safe
202
-
203
- **Files:**
204
- - Modify: `bin/hcc.mjs:6420-6557`
205
- - Modify: `lib/ui/help.mjs:40-50,285-305`
206
- - Modify: `scripts/regression.mjs:3689-3776,7019-7070`
207
-
208
- - [ ] **Step 1: Add failing CLI cases**
209
-
210
- Add fixtures proving:
211
-
212
- ```text
213
- hcc gc --older-than -1 --yes -> BAD_ARGS, no row/file changes
214
- hcc gc --older-than 0 --yes -> technical cleanup only
215
- hcc gc --older-than 0 --history -> dry-run only
216
- hcc gc --older-than 0 --history --yes -> eligible history removed
217
- clock grace + any form -> every age-based category deferred
218
- ```
219
-
220
- Keep an open-task handoff and assert it survives even with `--history --yes`.
221
-
222
- - [ ] **Step 2: Run to verify RED**
223
-
224
- Run: `npm run test:regression`.
225
-
226
- Expected: negative retention mutates/plans broadly, and ordinary `--yes` currently removes history.
227
-
228
- - [ ] **Step 3: Implement the command contract**
229
-
230
- Reject `olderThanDays < 0` before `connect()`. Parse a `history` boolean. Split the planner into technical and history SQL. During grace, produce deferred counts for all age-based categories and execute no age-based delete. Always preserve handoffs linked to tasks outside `done`/`abandoned`.
231
-
232
- Keep WAL checkpoint only after an applied safe plan. Update text and JSON output with `deleted`, `protected`, and `deferred` category counts.
233
-
234
- - [ ] **Step 4: Verify GREEN**
235
-
236
- Run: `npm run test:regression`.
237
-
238
- Run: `node ./bin/hcc.mjs gc --help`.
239
-
240
- Expected: every CLI contract case passes and help documents `--history`.
241
-
242
- - [ ] **Step 5: Commit**
243
-
244
- ```bash
245
- git add bin/hcc.mjs lib/ui/help.mjs scripts/regression.mjs
246
- git commit -m "fix: make GC retention explicit and safe"
247
- ```
248
-
249
- ### Task 5: Serialize project-registry writers
250
-
251
- **Files:**
252
- - Create: `lib/shared/file-lock.mjs`
253
- - Create: `test/file-lock.test.mjs`
254
- - Modify: `lib/runtime/projects.mjs:1-86`
255
- - Modify: `scripts/regression.mjs:1813-1840,4500-4700`
256
-
257
- - [ ] **Step 1: Write failing real-filesystem tests**
258
-
259
- Spawn two Node child processes that wait on a barrier file, then concurrently call `registerProject` for different roots under one isolated `HOME`. Assert both records remain. Add a same-root/different-DB update inside 60 seconds and assert the DB changes immediately.
260
-
261
- Add a stale-lock fixture with a dead owner fingerprint and an unknown-owner fixture. Dead lock must be reclaimed; unknown lock must time out without deletion.
262
-
263
- - [ ] **Step 2: Run to verify RED**
264
-
265
- Run: `node --test test/file-lock.test.mjs`.
266
-
267
- Expected: missing-module failure, then the concurrent registry assertion fails before integration.
268
-
269
- - [ ] **Step 3: Implement atomic lock-directory ownership**
270
-
271
- Implement:
272
-
273
- ```js
274
- export function withFileLock(target, fn, { timeoutMs = 5000, retryMs = 25 } = {})
275
- ```
276
-
277
- Acquire `${target}.lock` with `mkdirSync`. Write owner metadata atomically with the current process fingerprint. On `EEXIST`, inspect the owner: reclaim only `dead`, retry `live`, and time out `unknown`. Always remove only the lock whose owner token still matches the current holder.
278
-
279
- Wrap the entire registry re-read, merge, throttle decision, and atomic write. Compare both canonical root and resolved DB before throttling.
280
-
281
- - [ ] **Step 4: Verify GREEN**
282
-
283
- Run: `node --test test/file-lock.test.mjs`.
284
-
285
- Run: `npm run test:regression`.
286
-
287
- Expected: concurrent writers retain both records; changed DB updates immediately; unknown locks are not stolen.
288
-
289
- - [ ] **Step 5: Commit**
290
-
291
- ```bash
292
- git add lib/shared/file-lock.mjs test/file-lock.test.mjs lib/runtime/projects.mjs scripts/regression.mjs
293
- git commit -m "fix: serialize project registry updates"
294
- ```