@felixdotgo/aidlc-kit 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/DEVELOPMENT.md +13 -26
  2. package/README.md +35 -39
  3. package/dist/assets/.agents/aidlc/orchestrator.md +1 -1
  4. package/dist/assets/.agents/aidlc/schemas/state.schema.json +2 -0
  5. package/dist/assets/.agents/aidlc/scripts/lib/assignment-store.mjs +94 -48
  6. package/dist/assets/.agents/aidlc/scripts/lib/context-runtime.mjs +5 -4
  7. package/dist/assets/.agents/aidlc/scripts/lib/loop-authority.mjs +21 -5
  8. package/dist/assets/.agents/aidlc/scripts/lib/loop-daemon.mjs +52 -78
  9. package/dist/assets/.agents/aidlc/scripts/lib/loop-drivers.mjs +88 -14
  10. package/dist/assets/.agents/aidlc/scripts/lib/loop-env.mjs +279 -0
  11. package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-cli.mjs +20 -5
  12. package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-remote.mjs +10 -1
  13. package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-supervisor.mjs +2 -1
  14. package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet.mjs +3 -2
  15. package/dist/assets/.agents/aidlc/scripts/lib/loop-git.mjs +9 -3
  16. package/dist/assets/.agents/aidlc/scripts/lib/loop-holder.mjs +376 -0
  17. package/dist/assets/.agents/aidlc/scripts/lib/loop-intake.mjs +11 -3
  18. package/dist/assets/.agents/aidlc/scripts/lib/loop-lease.mjs +67 -61
  19. package/dist/assets/.agents/aidlc/scripts/lib/loop-leases.mjs +268 -0
  20. package/dist/assets/.agents/aidlc/scripts/lib/loop-local-workers.mjs +78 -17
  21. package/dist/assets/.agents/aidlc/scripts/lib/loop-runtime.mjs +42 -10
  22. package/dist/assets/.agents/aidlc/scripts/lib/loop-stream.mjs +66 -9
  23. package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-local.mjs +16 -56
  24. package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-run-local.mjs +12 -6
  25. package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-docker.mjs +14 -2
  26. package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-log.mjs +158 -0
  27. package/dist/assets/.agents/aidlc/scripts/lib/repo-head.mjs +22 -0
  28. package/dist/assets/.agents/aidlc/scripts/lib/store.mjs +11 -0
  29. package/dist/assets/.agents/aidlc/scripts/lib/task-runtime-migrate.mjs +75 -0
  30. package/dist/assets/.agents/aidlc/scripts/lib/task-runtime.mjs +97 -0
  31. package/dist/assets/.agents/aidlc/scripts/loop-entry.mjs +87 -4
  32. package/dist/assets/.agents/aidlc/scripts/loop.cmd +101 -0
  33. package/dist/assets/.agents/aidlc/scripts/loop.sh +71 -0
  34. package/dist/assets/.agents/aidlc/scripts/remote-state.mjs +10 -4
  35. package/dist/assets/.agents/aidlc/scripts/state.mjs +16 -8
  36. package/dist/assets/ui/changes.js +83 -0
  37. package/dist/assets/ui/common.js +664 -0
  38. package/dist/assets/ui/dashboard.css +281 -59
  39. package/dist/assets/ui/dashboard.js +77 -0
  40. package/dist/assets/ui/detail.js +159 -0
  41. package/dist/assets/ui/live-log.js +332 -0
  42. package/dist/services/aidlc-coordination/package.json +1 -1
  43. package/dist/services/aidlc-coordination/src/lifecycle-core.mjs +11 -0
  44. package/dist/src/cli/argv.js +10 -4
  45. package/dist/src/cli/commands.js +52 -22
  46. package/dist/src/cli/loop-launcher.d.ts +47 -0
  47. package/dist/src/cli/loop-launcher.js +322 -0
  48. package/dist/src/cli.js +3 -0
  49. package/dist/src/installer.js +4 -2
  50. package/dist/src/model/records.d.ts +4 -0
  51. package/dist/src/state/validate.js +5 -0
  52. package/dist/src/task-ui.d.ts +31 -52
  53. package/dist/src/task-ui.js +25 -1562
  54. package/dist/src/ui/assets.d.ts +14 -0
  55. package/dist/src/ui/assets.js +45 -0
  56. package/dist/src/ui/changes.d.ts +83 -0
  57. package/dist/src/ui/changes.js +498 -0
  58. package/dist/src/ui/containers.d.ts +71 -0
  59. package/dist/src/ui/containers.js +214 -0
  60. package/dist/src/ui/daemon.d.ts +75 -0
  61. package/dist/src/ui/daemon.js +232 -0
  62. package/dist/src/ui/data.d.ts +42 -0
  63. package/dist/src/ui/data.js +89 -0
  64. package/dist/src/ui/docs.d.ts +13 -0
  65. package/dist/src/ui/docs.js +39 -0
  66. package/dist/src/ui/files.d.ts +3 -0
  67. package/dist/src/ui/files.js +20 -0
  68. package/dist/src/ui/http.d.ts +14 -0
  69. package/dist/src/ui/http.js +80 -0
  70. package/dist/src/ui/live.d.ts +5 -0
  71. package/dist/src/ui/live.js +43 -0
  72. package/dist/src/ui/markdown.d.ts +2 -0
  73. package/dist/src/ui/markdown.js +127 -0
  74. package/dist/src/ui/options.d.ts +48 -0
  75. package/dist/src/ui/options.js +81 -0
  76. package/dist/src/ui/security.d.ts +34 -0
  77. package/dist/src/ui/security.js +38 -0
  78. package/dist/src/ui/server.d.ts +39 -0
  79. package/dist/src/ui/server.js +347 -0
  80. package/dist/src/ui/sse.d.ts +14 -0
  81. package/dist/src/ui/sse.js +281 -0
  82. package/dist/src/ui/views/board.d.ts +7 -0
  83. package/dist/src/ui/views/board.js +131 -0
  84. package/dist/src/ui/views/changes.d.ts +19 -0
  85. package/dist/src/ui/views/changes.js +154 -0
  86. package/dist/src/ui/views/components.d.ts +56 -0
  87. package/dist/src/ui/views/components.js +113 -0
  88. package/dist/src/ui/views/docs.d.ts +15 -0
  89. package/dist/src/ui/views/docs.js +64 -0
  90. package/dist/src/ui/views/layout.d.ts +44 -0
  91. package/dist/src/ui/views/layout.js +233 -0
  92. package/dist/src/ui/views/task.d.ts +25 -0
  93. package/dist/src/ui/views/task.js +320 -0
  94. package/dist/src/upgrade.js +5 -2
  95. package/dist/src/workflow.d.ts +4 -0
  96. package/dist/src/workflow.js +33 -1
  97. package/docs/README.md +48 -33
  98. package/docs/architecture.md +101 -38
  99. package/docs/command-reference.md +269 -93
  100. package/docs/configuration.md +62 -42
  101. package/docs/coordination-service.md +85 -36
  102. package/docs/design-decisions.md +35 -31
  103. package/docs/development.md +111 -61
  104. package/docs/loop-local-run.md +135 -402
  105. package/docs/loop-runbook.md +84 -105
  106. package/docs/operating-workflow.md +55 -42
  107. package/docs/testing-and-release.md +70 -51
  108. package/docs/troubleshooting.md +165 -69
  109. package/package.json +1 -1
@@ -1,8 +1,6 @@
1
1
  # Testing and release
2
2
 
3
- Loop changes should run the focused client assignment, graph, Git, remote-state, and `loop-*.test` fixtures, then lifecycle gate/conformance tests and package smoke. Verify in-conversation gate stop, later client resume, concurrent worker claims, lease expiry, exact-session recovery, Git scope checks, remote reviewer approval, and run bounds before aggregate `npm test` and `npm run lint`. Fleet persistence needs PostgreSQL integration coverage as well as in-memory/SQLite fixtures.
4
-
5
- Use the smallest relevant verification while developing, then complete the repository checks before a release review.
3
+ Verifying changes, then preparing and publishing releases.
6
4
 
7
5
  ## Standard verification
8
6
 
@@ -12,28 +10,35 @@ npm run lint
12
10
  npm test
13
11
  ```
14
12
 
15
- `npm test` rebuilds the package before running compiled unit tests. The tests cover CLI and installer behaviour, state and gate transitions, migration safety, managed content, profiles/context, evaluator logic, and installed-runtime parity.
16
-
17
- If a test depends on child processes and a sandbox returns `EPERM`, rerun it in an appropriate local environment before deciding that the product failed.
13
+ `npm test` rebuilds first. If a child-process test fails with `EPERM` in a sandbox, rerun locally before calling it a product failure.
18
14
 
19
15
  ## Lifecycle core sync
20
16
 
21
- The TypeScript core (`src/state.ts`) and the dependency-free installed/runtime core (`assets/aidlc/scripts/lib/store.mjs`, mirrored to `services/aidlc-coordination/src/lifecycle-core.mjs`) must stay byte-identical. After editing `assets/aidlc/scripts/lib/store.mjs`, run `npm run sync-core` to copy it into the coordination service, then commit both files together. The byte-identity conformance test (`test/unit/lifecycle-core-conformance.test.ts`) enforces this link.
17
+ - After editing `assets/aidlc/scripts/lib/store.mjs`, run `npm run sync-core` and commit it with `services/aidlc-coordination/src/lifecycle-core.mjs`.
18
+ - `test/unit/lifecycle-core-conformance.test.ts` enforces byte identity and parity with `src/state.ts`.
22
19
 
23
20
  ## Focused tests
24
21
 
25
- Build first, then invoke a compiled test file directly:
26
-
27
22
  ```sh
28
23
  npm run build
29
24
  node --test dist/test/unit/installer.test.js
30
25
  ```
31
26
 
32
- Choose the test closest to the changed boundary. For example, use installer tests for package inventory or documentation assertions, upgrade tests for migration semantics, and lifecycle-runtime tests when touching installed scripts. Continuation changes must also run `continuation-guard`, multi-item lifecycle runtime, context, and local/MCP lifecycle conformance coverage.
27
+ Pick the nearest test: installer (package inventory, docs assertions), upgrade (migration semantics), lifecycle-runtime (installed scripts). Continuation changes also run `continuation-guard`, multi-item lifecycle runtime, context, and local/MCP lifecycle conformance.
33
28
 
34
29
  ## Loop, Docker, and PostgreSQL verification
35
30
 
36
- Loop orchestration tests are part of `npm test`. The ones that exercise real container isolation gate on fixture images plus environment flags; build the fixtures once with a local Docker daemon:
31
+ > [!WARNING]
32
+ > Experimental, pre-1.0. See [Status and stability](./loop-runbook.md#status-and-stability).
33
+
34
+ Loop changes:
35
+
36
+ - Run the client assignment, graph, Git, remote-state, and `loop-*.test` fixtures, then lifecycle gate/conformance tests and the [package smoke test](#package-smoke-test).
37
+ - Verify in-conversation gate stop, client resume, concurrent worker claims, lease expiry, exact-session recovery, Git scope checks, remote reviewer approval, and run bounds.
38
+ - Cover fleet persistence with the PostgreSQL suite below, not only SQLite.
39
+ - Finish with `npm test` and `npm run lint`.
40
+
41
+ Container-isolation tests skip without fixture images and flags, so plain `npm test` is not isolation verification. Build the fixtures once:
37
42
 
38
43
  ```sh
39
44
  docker build -q -t aidlc-worker-isolation-test:local test/fixtures/docker/worker-isolation
@@ -48,16 +53,16 @@ AIDLC_WORKER_DOCKER_IMAGE=aidlc-worker-fleet-e2e-test:local \
48
53
  npm test
49
54
  ```
50
55
 
51
- - `AIDLC_TEST_DOCKER=1` builds and runs the adversarial lead-boundary container: the isolated lead must not write source or see lifecycle state, the Docker socket, host HOME, or reviewer credentials.
52
- - `AIDLC_TEST_WORKER_IMAGE` and `AIDLC_TEST_DOCKER_IMAGE` run the isolated Docker worker through the local batch dispatcher and the fleet Git handoff.
53
- - `AIDLC_TEST_MULTITURN_IMAGE` runs the multi-turn session HOME fixture against the turn limit.
54
- - `AIDLC_WORKER_DOCKER_IMAGE` is required on Linux for the real fleet end-to-end test (coordinator dispatch, isolated worker, Git integration, canonical completion, and G2 publication). Without it that test fails closed instead of skipping.
56
+ | Variable | Enables |
57
+ | --- | --- |
58
+ | `AIDLC_TEST_DOCKER=1` | Adversarial lead-boundary container: isolated lead must not write source or see lifecycle state, Docker socket, host HOME, or reviewer credentials. |
59
+ | `AIDLC_TEST_WORKER_IMAGE`, `AIDLC_TEST_DOCKER_IMAGE` | Isolated Docker worker via the local batch dispatcher and fleet Git handoff. |
60
+ | `AIDLC_TEST_MULTITURN_IMAGE` | Multi-turn session HOME fixture against the turn limit. |
61
+ | `AIDLC_WORKER_DOCKER_IMAGE` | Real fleet e2e on Linux (coordinator dispatch, isolated worker, Git integration, canonical completion, G2 publication). The CLI e2e test skips without it; the loop-daemon e2e test fails closed. |
55
62
 
56
- Each fixture image contains only a fake provider CLI that emits the Codex JSONL protocol; no real Codex, Claude Code, or OpenCode credentials or accounts are used, and the fake refuses to run when it can see `.git`, lifecycle state, or the Docker socket.
63
+ Fixture images hold only a fake provider CLI speaking the Codex JSONL protocol (no real credentials); it refuses to run if it can see `.git`, lifecycle state, or the Docker socket.
57
64
 
58
- Without these variables the Docker-gated tests skip, so a plain `npm test` is not loop-isolation verification.
59
-
60
- PostgreSQL fleet coverage runs against a real database and is not part of `npm test`:
65
+ PostgreSQL fleet coverage is outside `npm test` and skips without `TEST_POSTGRES_URL` (SQLite still runs). Run it whenever `services/aidlc-coordination/` changes:
61
66
 
62
67
  ```sh
63
68
  docker run -d --rm --name aidlc-pg-test -e POSTGRES_PASSWORD=test -p 127.0.0.1:5433:5432 postgres:16-alpine
@@ -67,12 +72,9 @@ TEST_POSTGRES_URL=postgres://postgres:test@127.0.0.1:5433/postgres \
67
72
  docker stop aidlc-pg-test
68
73
  ```
69
74
 
70
- Without `TEST_POSTGRES_URL` the PostgreSQL tests skip with SQLite coverage still running; run the coordination service suites separately whenever `services/aidlc-coordination/` changes.
71
-
72
-
73
75
  ## Package smoke test
74
76
 
75
- Release verification must exercise the tarball rather than the source tree. From the repository root, build and pack locally, extract the archive, then run the extracted CLI against a clean temporary consumer project.
77
+ Release verification exercises the tarball, not the source tree.
76
78
 
77
79
  ```sh
78
80
  AIDLC_PACK_DIR="$(mktemp -d /tmp/aidlc-pack.XXXXXX)"
@@ -81,20 +83,19 @@ AIDLC_TEST_PROJECT="$(mktemp -d /tmp/aidlc-project.XXXXXX)"
81
83
 
82
84
  npm run build
83
85
  npm pack --pack-destination "$AIDLC_PACK_DIR"
84
- tar -xzf "$AIDLC_PACK_DIR/felixdotgo-aidlc-kit-0.2.0.tgz" -C "$AIDLC_EXTRACT_DIR"
86
+ tar -xzf "$AIDLC_PACK_DIR/felixdotgo-aidlc-kit-0.3.0.tgz" -C "$AIDLC_EXTRACT_DIR"
85
87
  node "$AIDLC_EXTRACT_DIR/package/dist/src/cli.js" init "$AIDLC_TEST_PROJECT" --agent codex --dry-run
86
88
  node "$AIDLC_EXTRACT_DIR/package/dist/src/cli.js" init "$AIDLC_TEST_PROJECT" --agent codex --yes
87
89
  node "$AIDLC_EXTRACT_DIR/package/dist/src/cli.js" status "$AIDLC_TEST_PROJECT"
88
90
  node "$AIDLC_EXTRACT_DIR/package/dist/src/cli.js" doctor "$AIDLC_TEST_PROJECT" --strict
89
91
  ```
90
92
 
91
- Keep the printed temporary paths until inspection is complete. Remove them manually afterwards. Do not reuse a smoke-test project for a different package version; the installer intentionally refuses implicit upgrades.
92
-
93
- Check that the tarball contains the public CLI, bundled assets, and documentation, but not `dist/dev/`, evaluator runners, evaluator schemas, or evaluator configuration.
93
+ - Remove the temporary paths manually after inspection; never reuse a smoke project for another version (installer refuses implicit upgrades).
94
+ - The tarball must contain the public CLI, bundled assets, and docs; not `dist/dev/`, evaluator runners, schemas, or configuration.
94
95
 
95
96
  ## Development-only evaluator
96
97
 
97
- The evaluator under `dev/evaluator/` is repository and CI infrastructure. It is compiled for tests but excluded from the published package.
98
+ `dev/evaluator/` is repository/CI infrastructure: compiled for tests, not published. Runners exchange JSON; reports capture transport, transcript, normalised events, usage, and diagnostics. Real Codex, Claude Code, or OpenCode runs cost credentials and budget; ordinary verification does not need them.
98
99
 
99
100
  ```sh
100
101
  npm run build
@@ -102,59 +103,77 @@ node dist/dev/evaluator/cli.js list
102
103
  node dist/dev/evaluator/cli.js run --runner local-simulated
103
104
  ```
104
105
 
105
- Runners exchange JSON, and reports capture transport, transcript, normalised events, usage, and diagnostics. Real Codex, Claude Code, or OpenCode runs can consume credentials and model budget; they are not required for ordinary development verification.
106
-
107
- The pinned `opencode-beam` runner uses adapter `opencode` with model `opencode-go/beam-free`, version `opencode-2.2.0`, protocol version `2`, real evidence, and a 300000 ms timeout; the `economy` category is pinned to the lighter `opencode-go/beam-free#medium` variant so heavier turns stay inside that timeout. It runs `opencode run --format json --standalone --auto` once per turn, resumes with `--session`, and writes `opencode.json` containing `{"mcp": {}}` into each scenario workspace so project MCP servers do not leak into the evaluation. OpenCode resolves its project directory from the inherited `PWD`, not the spawned process working directory, so the runner and the loop driver pin `PWD` to the workspace; without that pin, commands would silently run in the invoking repository. OpenCode has no environment-credential mode, so the runner reuses the local Console authentication; the residual risk is that user plugins or agents can still load. That isolation is workspace configuration, not a security boundary.
106
+ Pinned `opencode-beam` runner: adapter `opencode`, model `opencode-go/beam-free`, version `opencode-2.2.0`, protocol version `2`, real evidence, 300000 ms timeout; `economy` category uses `opencode-go/beam-free#medium` to fit that timeout. Runs `opencode run --format json --standalone --auto` per turn, resuming with `--session`.
108
107
 
109
- The release-eligible `aidlc-official-agentic` suite is version `2.5.0`. Its `supported-adapters` scenario asks the agent to explain that the workflow supports Codex, Claude Code, and OpenCode without executing remote code or shell strings. The suite also includes `build-multi-item-continuation`, which starts with three canonical build items and requires one agent run to complete all of them, record verification/review evidence, and stop only at a ready G2. This complements unit guards by exercising the model-facing continuation contract.
108
+ - Runner and loop driver pin `PWD` to the workspace: OpenCode resolves its project from inherited `PWD`, not the spawned cwd; unpinned, commands silently run in the invoking repository.
109
+ - Each scenario turn runs with `XDG_CONFIG_HOME` pointed at an empty directory inside the workspace and without `OPENCODE_CONFIG`, so the user's global config (MCP servers, agents, plugins) never loads; the workspace also gets `opencode.json` `{"mcp": {}}`. `XDG_DATA_HOME` is untouched, so local Console auth is reused. This is configuration, not a security boundary.
110
110
 
111
- The release checker validates required evidence according to the configured adapter policy. This repository's script uses the OpenCode-only policy:
111
+ Release-eligible suite: `aidlc-official-agentic` `2.5.0`. `supported-adapters` expects the agent to state Codex, Claude Code, and OpenCode support without running remote code or shell strings; `build-multi-item-continuation` starts with three build items and requires one run to finish all, record verification/review evidence, and stop only at a ready G2.
112
112
 
113
113
  ```sh
114
114
  npm run release:check
115
115
  ```
116
116
 
117
- The script passes `--adapters opencode`, while `dev/evaluator/release.ts` keeps its `["codex","claude"]` default for compatibility so downstream users and existing policies are unaffected. It reads local evaluation evidence from `.agents/project/release-eval.json` and fails closed if required evidence or integrity thresholds are missing. Re-adding Codex or Claude to this repository's policy requires fresh real evidence for those adapters, not a policy-only edit.
117
+ Passes `--adapters opencode` (this repository's policy); `dev/evaluator/release.ts` keeps its `["codex","claude"]` default for downstream users. Reads `.agents/project/release-eval.json`; fails closed on missing evidence or integrity thresholds. Re-adding Codex or Claude needs fresh real evidence.
118
118
 
119
119
  ## Release readiness
120
120
 
121
- Before an authorised release, complete:
121
+ Before an authorised release:
122
122
 
123
123
  1. `npm test`
124
124
  2. `npm run lint`
125
125
  3. The local tarball smoke test
126
126
  4. `npm run release:check`
127
- 5. A review of the generated package contents and documentation links
127
+ 5. Review the generated package contents and documentation links
128
+
129
+ Publishing, tagging, committing, and pushing are separate human-authorised actions, not implied by a passing run.
128
130
 
129
- Publishing, tagging, committing, and pushing are separate human-authorised actions. A passing verification run is not delivery authority.
131
+ ### Version bump checklist
130
132
 
131
- ## First npm publication
133
+ Update together:
132
134
 
133
- The first release is `@felixdotgo/aidlc-kit@0.1.1`, with public access and the `latest` dist-tag. Complete the release checks and the project's human review gates before publishing.
135
+ | File | What pins the version |
136
+ | --- | --- |
137
+ | `package.json`, `package-lock.json` | Package version. |
138
+ | `README.md` | Version badge and `npx --package` commands. |
139
+ | `docs/command-reference.md`, `docs/configuration.md`, `docs/coordination-service.md`, `docs/loop-runbook.md`, `docs/loop-local-run.md` | `npx --package @felixdotgo/aidlc-kit@<version>` commands and "version `<version>`" notes. |
140
+ | `docs/development.md`, `docs/testing-and-release.md` | Local archive name `felixdotgo-aidlc-kit-<version>.tgz`. |
141
+ | `test/unit/installer.test.ts` | Expected manifest `packageVersion` and `installed version:` status output. |
142
+ | `test/unit/eval.test.ts` | `packageVersion` constant. |
134
143
 
135
- From the repository root, sign in to an npm account with permission to publish to the `@felixdotgo` scope and confirm the active account:
144
+ Confirm no old-version references remain:
136
145
 
137
146
  ```sh
138
- npm login --registry https://registry.npmjs.org
139
- npm whoami --registry https://registry.npmjs.org
140
- npm view @felixdotgo/aidlc-kit@0.1.1 version --registry https://registry.npmjs.org
147
+ grep -rn "<old-version>" README.md DEVELOPMENT.md docs test src
141
148
  ```
142
149
 
143
- An unpublished package normally returns `404` from `npm view`; that response does not establish scope ownership or publish permission. If `0.1.1` already exists, stop: npm versions cannot be overwritten. If `npm whoami` returns `401`, sign in again before publishing.
150
+ ## Publishing a release
144
151
 
145
- After inspecting the local tarball and documentation, publish from the repository root:
152
+ After [release readiness](#release-readiness) and the human review gates, publish `@felixdotgo/aidlc-kit@<version>` with public access and the `latest` dist-tag, signed in to an account that can publish to `@felixdotgo`:
146
153
 
147
154
  ```sh
148
- npm publish --access public --tag latest --registry https://registry.npmjs.org
155
+ npm login --registry https://registry.npmjs.org
156
+ npm whoami --registry https://registry.npmjs.org
157
+ npm view @felixdotgo/aidlc-kit@<version> version --registry https://registry.npmjs.org
149
158
  ```
150
159
 
151
- `prepublishOnly` runs the unit tests, lint, and evaluator release check before this command publishes. Complete any authentication or two-factor prompt from npm. The initial publication of a scoped package needs `--access public`; see the [npm scope documentation](https://docs.npmjs.com/cli/v11/using-npm/scope).
152
-
153
- Confirm the published version, dist-tag and artifact metadata:
160
+ ```sh
161
+ npm publish --access public --tag latest --registry https://registry.npmjs.org
162
+ ```
154
163
 
155
164
  ```sh
156
- npm view @felixdotgo/aidlc-kit@0.1.1 version dist.tarball dist.integrity --json --registry https://registry.npmjs.org
165
+ npm view @felixdotgo/aidlc-kit@<version> version dist.tarball dist.integrity --json --registry https://registry.npmjs.org
157
166
  npm view @felixdotgo/aidlc-kit dist-tags --json --registry https://registry.npmjs.org
158
167
  ```
159
168
 
160
- Expect version `0.1.1`, a tarball URL and integrity value, and `latest` pointing to `0.1.1`. Git tags, GitHub releases, commits, and pushes require their own delivery authorisation.
169
+ - `npm view` `404` means unpublished (not proof of scope ownership); if the version exists, stop: npm versions cannot be overwritten. `npm whoami` `401`: sign in again.
170
+ - `prepublishOnly` runs unit tests, lint, and the release check; answer npm's auth or two-factor prompt. `npm publish --dry-run` runs the same checks and packs without uploading, so it is the rehearsal to run first. A scoped package's first publish needs `--access public` ([npm scope docs](https://docs.npmjs.com/cli/v11/using-npm/scope)).
171
+ - Expect version `<version>`, tarball URL and integrity, and `latest` at `<version>`.
172
+ - Git tags, GitHub releases, commits, and pushes need separate delivery authorisation.
173
+
174
+ ## Related
175
+
176
+ - [Development guide](./development.md)
177
+ - [Architecture](./architecture.md)
178
+ - [Coordination service](./coordination-service.md)
179
+ - [Loop runbook](./loop-runbook.md)
@@ -1,125 +1,221 @@
1
1
  # Troubleshooting
2
2
 
3
- Symptom- and error-code-oriented recovery guide for the AI-DLC workflow. Read [Operating the workflow](./operating-workflow.md) for the lifecycle model and [Command reference](./command-reference.md) for flag details.
3
+ Symptom- and error-code recovery for the AI-DLC workflow and the loop: lifecycle state, gates and plans, the loop, the dashboard, fleet. Lifecycle model: [Operating the workflow](./operating-workflow.md); flags: [Command reference](./command-reference.md).
4
4
 
5
5
  ## State lock held or times out
6
6
 
7
- - Lock files live at `.agents/data/state/.aidlc-state.lock` and its companion `.agents/data/state/.aidlc-state.lock.guard`.
8
- - Defaults: acquisition times out after **5 seconds** (`timeoutMs` 5000) and treats a lock as stale only when it is **30 seconds** old (`staleMs` 30000) **and** its owning PID is no longer alive.
9
- - Contention under concurrent agents is normal; every mutation acquires the lock, including read-only `task list` and `task show`. Wait or serialize callers rather than deleting a live lock.
10
- - A dead PID lets the lock be reclaimed automatically. Do not delete a lock whose PID is still alive — that corrupts in-flight state.
11
- - Partially written or corrupt lock records are now reclaimed automatically instead of wedging mutations (recent release note). The reclamation is best-effort: if it fails, inspect the file before retrying.
12
- - When a lock is corrupt, the owning process may be unable to release it; remove only an unreadable/partial file after confirming no live process holds it.
7
+ - Lock files: `.agents/data/state/.aidlc-state.lock` and `.agents/data/state/.aidlc-state.lock.guard`.
8
+ - Defaults: acquisition times out after **5 seconds** (`timeoutMs` 5000); a lock is stale only when **30 seconds** old (`staleMs` 30000) **and** its owning PID is dead.
9
+ - Every mutation acquires the lock, including read-only `task list` and `task show`; contention is normal. Wait or serialize callers.
10
+ - A dead PID is reclaimed automatically. Never delete a lock whose PID is alive.
11
+ - Corrupt lock records are reclaimed best-effort; if that fails, remove only an unreadable/partial file after confirming no live process holds it.
13
12
 
14
13
  ## Corrupt state or assignment files
15
14
 
16
- - Corrupt local assignment files surface as `Corrupt local assignments for <task-id>`; corrupt loop/lease records surface as `Corrupt loop lease` / `Corrupt loop run record`. State JSON problems surface as `<label> is corrupted or unreadable: ...`.
17
- - Restore from `.agents/data/state/backups/upgrade-<timestamp>` created by `upgrade`/migration, or from git. These backups are the audit trail for managed writes.
18
- - `assignment-store` also guards against a corrupt assignment lock file (`Corrupt assignment lock for <task-id>`); inspect it before retrying rather than blindly deleting.
19
- - Never hand-edit canonical state to "fix" corruption; restore from backup or git and re-run `state.mjs state migrate` if schema-versioned.
15
+ - Messages: `Corrupt local assignments for <task-id>`, `Corrupt loop run record`, `Corrupt <lease|lock> file <path> (modified <age> ago)` ([leases](#loop-leases-locks-and-claims)), `<label> is corrupted or unreadable: ...` (state JSON).
16
+ - Restore from `.agents/data/state/backups/upgrade-<timestamp>` (created by `upgrade`/migration) or git; re-run `state.mjs state migrate` if schema-versioned. Never hand-edit canonical state.
20
17
 
21
18
  ## `LESSON_INDEX_STALE` warning
22
19
 
23
- - A mutation committed but the derived lesson-index rebuild failed. The mutation stays committed and the exit code stays `0`.
24
- - Run `node .agents/aidlc/scripts/state.mjs lesson rebuild` (local authority required; throws `Fleet authority is configured` if `AIDLC_FLEET_URL` is set — use `remote-state.mjs`).
20
+ - A mutation committed but the derived lesson-index rebuild failed; the mutation stays committed and the exit code stays `0`.
21
+ - Run `node .agents/aidlc/scripts/state.mjs lesson rebuild` (local authority; throws `Fleet authority is configured` if `AIDLC_FLEET_URL` is set — use `remote-state.mjs`).
25
22
 
26
23
  ## `RENDER_FAILED` warning
27
24
 
28
- - A mutation committed but the workplan render failed.
29
- - Run `node .agents/aidlc/scripts/render.mjs <task-id>` (or `--all`).
25
+ - A mutation committed but the workplan render failed. Run `node .agents/aidlc/scripts/render.mjs <task-id>` (or `--all`).
30
26
 
31
27
  ## Continuation guard exit code 2 (`CONTINUATION_REQUIRED`)
32
28
 
33
- - `task-next.mjs <task-id> --require-stop` exits `2` when `continuation.code = CONTINUATION_REQUIRED`. This is an expected pause, not a failure.
34
- - Execute `continuation.command` instead of replying. Do not treat exit code 2 as an error.
35
- - If a premature final response already slipped out, recover in the very next turn by running `task next <task-id>` and executing its returned command. Never re-approve a gate to catch up.
29
+ - `task-next.mjs <task-id> --require-stop` exits `2` with `continuation.code = CONTINUATION_REQUIRED`: an expected pause, not a failure. Execute `continuation.command` instead of replying.
30
+ - After a premature final response, run `task next <task-id>` in the very next turn and execute its command. Never re-approve a gate to catch up.
31
+
32
+ ## `Task already exists` / actionable-task guard
33
+
34
+ - `Task already exists: <id>` — resume with `task next <id>`.
35
+ - `Task create is blocked while other work is actionable: ...` — another task has `nextAction: run_phase`. Pass `--switch-from <task-id>` **only** with explicit user direction; the acknowledged task keeps its state, remains the resume target (a resume-marker diagnostic is stamped), and is never paused or mutated.
36
+ - Local-CLI enforcement only; the coordination service does not enforce it.
36
37
 
37
38
  ## Gate-check structural errors
38
39
 
39
- `gate-check.mjs` returns diagnostics; fix the underlying artifact or record, never skip the check. Codes:
40
+ `gate-check.mjs` returns diagnostics; fix the artifact or record, never skip the check. Codes:
40
41
 
41
- - `INTENT_HEADING` — intent artifact missing one of the five required headings: `## 📋 Problem`, `## 🗺️ Affected areas`, `## 💭 Assumptions`, `## ❓ Open questions`, `## 🎯 Scope`.
42
- - `DESIGN_HEADING` — design artifact missing one of the four required headings: `## 🧩 Solution per affected area`, `## 📌 Spec traceability`, `## 🔗 Cross-service contracts`, `## ⚠️ Risks / edge cases`.
43
- - `UNRESOLVED_DECISION` — a decision is still `unresolved`; resolve every decision before presenting G1.
44
- - `TASKS_OPEN` — build tasks remain open (`todo`/`in_progress`).
42
+ - `INTENT_HEADING` — intent artifact missing one of: `## 📋 Problem`, `## 🗺️ Affected areas`, `## 💭 Assumptions`, `## ❓ Open questions`, `## 🎯 Scope`.
43
+ - `DESIGN_HEADING` — design artifact missing one of: `## 🧩 Solution per affected area`, `## 📌 Spec traceability`, `## 🔗 Cross-service contracts`, `## ⚠️ Risks / edge cases`.
44
+ - `UNRESOLVED_DECISION` — a decision is still `unresolved`; resolve all before presenting G1.
45
+ - `TASKS_OPEN` — build tasks remain `todo`/`in_progress`.
45
46
  - `VERIFY_EVIDENCE` — latest post-G1 verification evidence must pass for every affected area.
46
47
  - `REVIEW_EVIDENCE` — latest post-G1 code-review evidence must pass.
47
48
  - `REPAIR_BOUND` — repair bound exhausted (3 failed verify cycles per area, or 2 failed review passes); record a durable handoff instead of presenting G2.
48
49
  - `TASK_UNKNOWN` — unknown task id.
49
50
  - `GATE_STATE` — task is at a different gate than requested.
50
- - `TASK_TERMINAL` — terminal task cannot approve a gate.
51
- - `TASK_HANDOFF` — task has an unresolved handoff.
51
+ - `TASK_TERMINAL` — a terminal task cannot approve a gate.
52
+ - `TASK_HANDOFF` — unresolved handoff.
52
53
  - `TASK_ID` — task key and id differ.
53
- - `TASK_FIELDS` — task title or affected areas missing.
54
- - `PARTITION_SCOPE` / `PARTITION_OVERLAP` — Approve plan parallel work partition; see [below](#parallel-work-partition-partition_overlap--partition_scope).
54
+ - `TASK_FIELDS` — title or affected areas missing.
55
+ - `PARTITION_SCOPE` / `PARTITION_OVERLAP` — see [below](#parallel-work-partition-partition_overlap--partition_scope).
55
56
  - `GATE_OK` — informational; no `ERROR` diagnostics (warnings may still be listed).
56
57
 
57
58
  ## Parallel work partition (`PARTITION_OVERLAP` / `PARTITION_SCOPE`)
58
59
 
59
60
  The Approve plan check (`gate-check.mjs <task-id>`) inspects build items so parallel workers never edit the same files:
60
61
 
61
- - `PARTITION_SCOPE` — an open item has no owned paths. Give it a scope: `node .agents/aidlc/scripts/state.mjs task item <task-id> <item-id> --status todo --label "<label>" --owns src/a,docs/b`.
62
- - `PARTITION_OVERLAP` — two items that can run concurrently (no direct or transitive `dependsOn` between them) own overlapping paths. Overlap is per path segment: `src` overlaps `src/a.ts`, but not `srcx`. Split the paths, merge the items, or order them with `--depends-on <item-id>`.
63
- - Severity follows the loop: `ERROR` when `loop.mode` is `local` or `fleet` (or inside a fleet-enabled coordination service), so the gate cannot be presented; `WARN` when the loop is `off`, and the gate still passes with `GATE_OK`.
64
- - The rendered workplan shows each item's scope as `owns: … · after: …`; the intent and design templates carry **Work boundaries** / **Parallel work partition** sections to plan it.
62
+ - `PARTITION_SCOPE` — an open item has no owned paths. Fix: `node .agents/aidlc/scripts/state.mjs task item <task-id> <item-id> --status todo --label "<label>" --owns src/a,docs/b`.
63
+ - `PARTITION_OVERLAP` — two items with no direct or transitive `dependsOn` own overlapping paths (per path segment: `src` overlaps `src/a.ts`, not `srcx`). Split the paths, merge the items, or order them with `--depends-on <item-id>`.
64
+ - Severity: `ERROR` when `loop.mode` is `local` or `fleet` (or in a fleet-enabled coordination service), so the gate cannot be presented; `WARN` when the loop is `off` (gate still `GATE_OK`).
65
+ - The workplan shows `owns: … · after: …` per item; the intent and design templates carry **Work boundaries** / **Parallel work partition** sections.
66
+
67
+ ## Loop stops, pauses, or never starts
68
+
69
+ > [!WARNING]
70
+ > The loop and fleet sections below cover experimental, pre-1.0 features. See [Status and stability](./loop-runbook.md#status-and-stability).
71
+
72
+ Start with `node .agents/aidlc/scripts/state.mjs task show <task-id>`: look for a `diagnostic` `Paused while active: …`; the cause is also the run's `stopReason`, for example `"agent transport failure: opencode reported an error: Model unavailable: opencode-go/flint-40b-free"`.
73
+
74
+ | Symptom / message | Cause | Fix |
75
+ | --- | --- | --- |
76
+ | `agent transport failure: …` (for example `Model unavailable: …`) | Missing, invalid, or unavailable `AIDLC_OPENCODE_MODEL` | Check `opencode models`, set `AIDLC_OPENCODE_MODEL`, restart the daemon, re-activate the task (below) |
77
+ | `turn limit reached` | The per-run `maxTurns` budget ran out before a gate | Raise `loop.limits.maxTurns` if needed, then re-activate |
78
+ | `opencode provider requires AIDLC_OPENCODE_MODEL` | Unset or not `provider/model[#variant]` | `loop.sh check` names the value and where to set it (`.agents/loop.env` or `"model"` in `opencode.json`); `loop start`/`loop up` stop on this before the daemon starts. Restart a running daemon after changing it |
79
+ | `Loop requires a configured lead and worker providers` | `loop.agents.lead` or `loop.agents.workers` missing | Complete `loop.agents` ([Enable the loop](./loop-runbook.md#enable-the-loop-from-off)) |
80
+ | `Requested mode does not match configured authority` | `--mode` differs from `loop.mode` | Drop `--mode` |
81
+ | `loop: Isolated local worker dispatcher is not integrated; loop execution is unavailable` | Stale installed `.agents/` copy (predates `createIsolatedLocalSupervisor`) | Re-sync with the human-only [`upgrade`](./command-reference.md#upgrade); source checkout: [Dogfooding](./development.md#dogfooding-this-repository) |
82
+
83
+ **The task pauses right after a gate approval and the daemon polls `actionable: []`.** The lead turn after approval failed, so the loop re-paused the task (`status: paused`, `nextAction: blocked`). Recovery from any pause:
84
+
85
+ 1. Fix the environment (for example `opencode models`, then `AIDLC_OPENCODE_MODEL`).
86
+ 2. Restart the daemon (`loop.sh down`, `loop.sh up`); a running daemon keeps the environment it started with.
87
+ 3. Re-activate: dashboard **resume**, or `node .agents/aidlc/scripts/state.mjs task status <task-id> --status active`.
88
+
89
+ OpenCode's own log: `grep -n "ModelUnavailableError\|Failed to drain Session" ~/.local/share/opencode/log/opencode.log | tail -20`. A silent lead is usually not hanging; a clarify or plan turn can take minutes ([streaming log](./loop-local-run.md#follow-the-streaming-log)).
90
+
91
+ ## Loop leases, locks and claims
92
+
93
+ Start every "stuck" or "already running" investigation with the read-only diagnostic; it lists who holds what, until when, what it blocks, and how to clear it:
94
+
95
+ ```bash
96
+ aidlc-kit loop leases [--task-id <task-id>] # or: node .agents/aidlc/scripts/loop-entry.mjs leases [task-id]
97
+ aidlc-kit loop leases --json # stable JSON (schemaVersion 1)
98
+ aidlc-kit loop leases --clear-stale # remove stale holders only
99
+ ```
100
+
101
+ | Word | Meaning | Local files under `.agents/data/` | Fleet (coordination service) |
102
+ | --- | --- | --- | --- |
103
+ | **lock** | Short mutex held only while a file is read-modified-written | `state/.aidlc-state.lock` (lifecycle state), `tasks/<task>/runtime/assignments.lock` | — |
104
+ | **lease** | A process owns something: the loop daemon, or a task's loop run | `loop/daemon.lock`, `loop/<task>.lease` | supervisor lease, lead lease (`run_claim`) |
105
+ | **claim** | A worker owns an item and its paths | `tasks/<task>/runtime/assignments.json` (assignment records; a `loop/assignments/<task>.json` left by an older version is read until migrated) | job claim (`job_*`) |
106
+
107
+ Local holder files share one format:
108
+
109
+ - Fields: `kind`, `scope`, `pid`, `host`, `command`, `activity`, `startedAt`, `heartbeatAt`, `expiresAt`. A holder is **live** while `expiresAt` is in the future **and**, on the same host, its pid is running; from another host (shared drive) `expiresAt` alone counts.
110
+ - Leases last **60 s**, renewed every **15 s**; locks last **30 s**, not renewed. A recycled pid cannot keep a lease alive.
111
+ - A holder no longer live is **stale**; the next acquire reclaims it (event `holder_reclaimed`). An unreadable holder is **corrupt**: older than its TTL it is reclaimed like a stale one, younger it fails closed with its path and age.
112
+ - The task lease `loop/<task>.lease` has an `activity`: `waiting` (gates may be approved) or `turn` (a run is executing; `state.mjs gate approve` refuses).
113
+ - Reclaims, renewals, and releases are serialized by a short-lived `<file>.guard`, abandoned when its pid is gone or it is older than 10 s.
114
+ - `--clear-stale` removes only stale lease, lock, and guard files and corrupt files older than their TTL, re-reading each under its guard. It never removes a live holder, never releases an assignment claim (it prints the `reconcile` / `release` command), and never touches the lifecycle state lock. Never delete these files by hand.
115
+
116
+ | Symptom / message | Cause | Fix |
117
+ | --- | --- | --- |
118
+ | `Loop daemon already running (pid N): lease daemon is held by pid N on <host> …` | Another `loop start` owns this project root (`daemon` lease in `.agents/data/loop/daemon.lock`) | Stop it (`loop.sh down`, or Ctrl-C in its terminal). If that process is gone, the lease is reclaimed within 60 s |
119
+ | `loop: error: opencode needs a model …` / `environment is incomplete` | No valid `AIDLC_OPENCODE_MODEL`, a malformed env file, or a missing explicit env file | `.agents/aidlc/scripts/loop.sh check`, then set the named value in `.agents/loop.env` (or `"model"` in `opencode.json`) |
120
+ | `The loop daemon exited during start-up` | The daemon exited before taking its lease | Read the printed tail of `.agents/data/loop/daemon.log`; `loop.sh logs` follows it |
121
+ | `loop.sh: the aidlc-kit CLI was not found` / `npx --no-install` fails | No package in `node_modules`, the CLI recorded in `.agents/data/loop/cli.json` by `init`/`upgrade` is gone (cleaned npx cache), and none on `PATH` | Rerun `init`/`upgrade` from the package or `.tgz` you want, or run the printed `npm install --save-dev @felixdotgo/aidlc-kit@<version>` |
122
+ | `Task <id> already has a live supervisor` / `… live loop runner (pid N): …` | Another loop process owns the task lease | `loop leases --task-id <id>` shows pid, host, and command; stop it or wait |
123
+ | `Gate approval is unavailable while loop runner owns <id>; … task lease held by pid N …, activity turn` | A loop run is executing for that task | Wait until it stops at the gate (activity `waiting`), then approve |
124
+ | `Corrupt lease file <path> (modified 5s ago); it is reclaimed automatically once older than 60s …` | An unreadable holder file | Wait for the TTL; if no loop process is running, `loop leases --clear-stale` |
125
+ | `lease ownership lost: lease task:<id> was taken over …` / `local supervisor ownership lost` | This process stopped renewing past the TTL (suspended machine, blocked event loop) and another reclaimed the lease | The run stops safely; restart `loop start` |
126
+ | `A loop from a previous aidlc-kit version is still running for <id> …` | An old `<task>.supervisor.lease` is still held after an upgrade | Stop the old daemon and any `loop start`, retry. Stop the daemon before every upgrade |
127
+ | `Timed out waiting for assignment lock: <task>: lock assignments:<task> is held by …` | Another assignment command is mid-write | Retry; a stale lock is reclaimed automatically |
128
+ | `Item already leased: <item>: claimed by assignment <id> (… worker …, paths …, claim expires …)` | A worker holds the claim | Wait for it to report or expire. If the worker is gone: `assignment.mjs release <task> <id>` (discards its unintegrated result) |
129
+ | `Item has unresolved assignment; reconcile before retry: <item>: assignment <id> …` / `Owned path overlaps active assignment: <path>: held by assignment <id> …` | An earlier claim is `reported`/`uncertain`, or holds overlapping paths | `assignment.mjs reconcile <task>` once the item is done in canonical state; otherwise `assignment.mjs release <task> <id>` |
130
+ | `assignment.mjs show` lists `"effectiveState": "expired"` | A `leased` claim passed `leaseExpiresAt`; `show` never writes | `assignment.mjs reconcile <task>` (the next mutation persists it as `uncertain`) |
131
+ | `Worker lease lost: the claim on assignment <id> … ended before the worker finished` | Claim renewal failed or the worker turn was aborted | The result is not integrated; `assignment.mjs reconcile <task>` |
132
+ | `Fleet conflict: the lead lease (run_claim) is no longer valid … (stale or expired lead claim)` | The lead's `loop start` stopped, lost its connection, or another lead took over | Restart the loop on one lead machine. `loop leases` lists the fleet supervisor lease, lead lease, and job claims when lead credentials are set |
133
+ | `Fleet conflict: another lead holds the lead lease … (lead claim is held)` | Two lead machines run the same task | Stop one. Fleet leases expire 5 minutes after the last heartbeat |
134
+
135
+ ## Loop daemon diagnostics
136
+
137
+ - `daemon_poll_error` — the daemon could not list tasks (for example the fleet service is unreachable); it keeps polling and recovers once connectivity or credentials are fixed.
138
+ - `daemon_turn_error`, or a `daemon_turn` with status `blocked`/`reconcile` — that task is retried with exponential backoff (capped at 10 minutes) while other tasks keep running. Inspect with `task show` (local) or `remote-state.mjs task next` (fleet).
139
+ - `loop resume is removed …` — use `loop start`; re-activate a paused task with the dashboard **resume** or the task status command.
65
140
 
66
141
  ## Build items deferred or `build dispatch failure: Unresolved assignment`
67
142
 
68
- - A `build_deferred` event (with `itemId` and `reason`) is not an error. The local scheduler dispatches a batch of non-overlapping ready items, at most one per configured worker, and defers the rest (`overlaps <item>`, `busy path held by an active assignment`, `unresolved assignment`, `capacity`) to a later batch. The fleet coordinator applies the same overlap rule.
69
- - The task pauses with `build dispatch failure: Unresolved assignment <id> (<state>) for <item> holds <paths>; inspect it, then run node .agents/aidlc/scripts/assignment.mjs reconcile <task-id> or … release <task-id> <assignment-id>` when a `reported` or `uncertain` assignment of an unfinished item (or a still-`leased` one, reported as `Active assignment`) blocks every ready item. The loop never releases it automatically.
70
- - Inspect it with `node .agents/aidlc/scripts/assignment.mjs show <task-id>` and the worker's branch or worktree. Run `assignment.mjs reconcile <task-id>` when the outcome is recorded, or `assignment.mjs release <task-id> <assignment-id>` only after confirming the work is abandoned. Then re-activate the task (dashboard **resume** or `state.mjs task status <task-id> --status active`).
71
- - `Build item <item> requires an owned path scope for Docker dispatch` means an item reached build without `--owns`; fix the plan (see `PARTITION_SCOPE`).
143
+ - `build_deferred` (with `itemId` and `reason`) is not an error: the scheduler dispatches non-overlapping ready items, at most one per configured worker, and defers the rest (`overlaps <item>`, `busy path held by an active assignment`, `unresolved assignment`, `capacity`). The fleet coordinator applies the same overlap rule.
144
+ - `build dispatch failure: Unresolved assignment <id> (<state>) for <item> holds <paths>; inspect it, then run node .agents/aidlc/scripts/assignment.mjs reconcile <task-id> or … release <task-id> <assignment-id>` pauses the task when a `reported`/`uncertain` assignment of an unfinished item (or a still-`leased` one, reported as `Active assignment`) blocks every ready item. The loop never releases it automatically.
145
+ - Inspect with `aidlc-kit loop leases --task-id <task-id>` or `node .agents/aidlc/scripts/assignment.mjs show <task-id>`, plus the worker's branch or worktree. `assignment.mjs reconcile <task-id>` when the outcome is recorded; `assignment.mjs release <task-id> <assignment-id>` only after confirming the work is abandoned. Then re-activate the task (dashboard **resume** or `state.mjs task status <task-id> --status active`).
146
+ - `Build item <item> requires an owned path scope for Docker dispatch` — an item reached build without `--owns`; fix the plan (`PARTITION_SCOPE`).
147
+
148
+ ## Task data still in the old place after an upgrade
149
+
150
+ Versions before the `runtime/` layout kept per-task loop files under `.agents/data/loop/` (`assignments/<task>.json`, `events/<task>.jsonl`, `<task>.json` run record) and at the task directory root (`loop-intake.json`, `requirement.md`). Every reader still falls back to those locations, so nothing breaks, but the dashboard and diagnostics are simplest once they are moved:
151
+
152
+ ```bash
153
+ aidlc-kit loop migrate-data --dry-run # list what would move
154
+ aidlc-kit loop migrate-data # move it (also runs when the daemon starts)
155
+ ```
156
+
157
+ - A file is moved only when `.agents/data/tasks/<id>/runtime/<name>` does not exist yet; an existing destination is reported `skipped` and the old file is left for inspection (`loop leases` lists such a leftover assignment file as `legacy`). Nothing is deleted or overwritten.
158
+ - Leases, locks, and guards are not moved: locks expire on their own, leases belong to `.agents/data/loop/`. `<task>.supervisor.json` and `<task>.gate-receipt.json` stay there too.
72
159
 
73
160
  ## `Git worktree must be clean before handoff or integration`
74
161
 
75
162
  - The lead checkout must have no uncommitted or untracked changes before a worker handoff or integration. Commit, stash, or remove them, then re-activate the task.
76
- - Host-local loop files under `.agents/data/loop/` (daemon lock, `daemon.log`, `ui-events.jsonl`) are ignored by this check, so a running daemon or dashboard does not trigger it.
163
+ - Host-local loop files under `.agents/data/loop/` (daemon lock, `daemon.log`, `ui-events.jsonl`, leases) and per-task runtime data under `.agents/data/tasks/<id>/runtime/` (assignments, event history, run record, intake, worker logs) are ignored; the installer's `.agents/.gitignore` excludes both as well.
77
164
 
78
- ## `Task already exists` / actionable-task guard
165
+ ## Worker image missing at build dispatch
79
166
 
80
- - `task create` fails with `Task already exists: <id>` when the id is already present; resume with `task next <id>`.
81
- - While another task has `nextAction: run_phase`, `task create` fails with `Task create is blocked while other work is actionable: ...`. Pass `--switch-from <task-id>` **only** with explicit user direction; acknowledged tasks keep their state and remain the resume target (a resume-marker diagnostic is stamped). Never pause or mutate the acknowledged task.
82
- - This guard is local-CLI enforcement; the coordination service does not enforce it.
167
+ - Local build dispatch auto-builds `aidlc-worker-<provider>:local` from the packaged Dockerfile, so this rarely surfaces.
168
+ - If the build cannot complete (no Docker daemon, no network for the CLI, removed Dockerfile), the batch fails with `Docker engine, image, or provider CLI preflight failed`. Run `aidlc-kit loop worker-image --provider <provider>` to see the build output, or set `AIDLC_WORKER_DOCKER_IMAGE` to an image you built.
169
+ - Fleet workers resolve the image on their own machine: `AIDLC_WORKER_DOCKER_IMAGE`, else `loop.workerImage[provider]`, else `aidlc-worker-<provider>:local` (auto-built). Provider: `AIDLC_FLEET_WORKER_AGENT`, else the worker's entry in `AIDLC_FLEET_WORKER_PROVIDERS`, else `AIDLC_FLEET_AGENT` (a copied lead env never overrides the worker's own mapping); without one: `AIDLC_WORKER_DOCKER_IMAGE is required when the worker provider is unknown`. Build ahead with `aidlc-kit loop worker-image --provider codex|claude|opencode` on that machine.
170
+ - Fleet e2e tests: in `test/unit/loop-fleet-e2e.test.ts` the CLI e2e skips with `Docker worker image unavailable` and the loop-daemon e2e fails when the image (default `aidlc-worker-fleet-e2e-test:local`, overridable via `AIDLC_WORKER_DOCKER_IMAGE`) is missing. Build it, or set `AIDLC_TEST_WORKER_IMAGE`/`AIDLC_WORKER_DOCKER_IMAGE`; Postgres coverage also needs `TEST_POSTGRES_URL`.
83
171
 
84
- ## Fleet authority mismatch
172
+ ## Dashboard live log or actions do nothing
85
173
 
86
- - When `AIDLC_FLEET_URL` is set, local lifecycle scripts throw `Fleet authority is configured; use remote-state.mjs instead of local lifecycle scripts`. This is by design — never silently switch authorities.
87
- - Use `node .agents/aidlc/scripts/remote-state.mjs ...` for all mutations. See [Coordination service](./coordination-service.md).
174
+ ### Approve, send feedback, or resume does nothing
88
175
 
89
- ## Docker worker image missing (fleet e2e tests)
176
+ - The **feedback** and **approve** forms exist only on the full detail page `/tasks/<id>`; the **review** button on a `blocked_on_user` card opens that page.
177
+ - **✓ Approve** opens a confirmation popup; only **Confirm approve** sends. For guidance use **Send feedback (stay at gate)**; the approval note is provenance only.
178
+ - **Send feedback** is blocked while the textarea is empty (API `400`) and returns `409` when the task is not `blocked_on_user`. After a send the task shows `active` with a **feedback pending** pill; it runs again only if a daemon is polling.
179
+ - **resume** applies only to a `paused` task; any other status returns `409` with the reason. A resumed task runs only if loop-owned and a daemon is running.
180
+ - Nothing at all (no toast, error, or update): hard-refresh (Ctrl+Shift+R) and check the browser DevTools console.
90
181
 
91
- - `test/unit/loop-fleet-e2e.test.ts` skips cleanly with `Docker worker image unavailable` when the image (default `aidlc-worker-fleet-e2e-test:local`, overridable via `AIDLC_WORKER_DOCKER_IMAGE`) is missing. No failure is recorded.
92
- - Build the worker image, or set `AIDLC_TEST_WORKER_IMAGE`/`AIDLC_WORKER_DOCKER_IMAGE`, to enable coverage. Postgres coverage additionally needs `TEST_POSTGRES_URL`.
93
-
94
- ## Worker image missing at build dispatch
182
+ ### Dashboard `403`
95
183
 
96
- - Local build dispatch auto-builds the per-provider image (`aidlc-worker-<provider>:local`) from the packaged Dockerfile when it is missing, so this error usually does not surface.
97
- - If the build cannot complete (no Docker daemon, no network to fetch the CLI, or a removed Dockerfile), the worker batch fails with `Docker engine, image, or provider CLI preflight failed`. Run `aidlc-kit loop worker-image --provider <provider>` directly to see the build output, or set `AIDLC_WORKER_DOCKER_IMAGE` to an image you built yourself.
98
- - Fleet workers resolve the image on their own machine: `AIDLC_WORKER_DOCKER_IMAGE`, else `loop.workerImage[provider]` from the project config, else `aidlc-worker-<provider>:local` (auto-built when missing). The provider comes from `AIDLC_FLEET_WORKER_AGENT`, else the worker's entry in `AIDLC_FLEET_WORKER_PROVIDERS`, else `AIDLC_FLEET_AGENT` (a copied lead env never overrides the worker's own mapping); without one, `AIDLC_WORKER_DOCKER_IMAGE is required when the worker provider is unknown`. To build ahead of time, run `aidlc-kit loop worker-image --provider codex|claude|opencode` on that machine.
184
+ - `403 … Origin …`, `403 … Sec-Fetch-Site …`, or `403 … x-aidlc-request …` — a state-changing request that does not look like the dashboard's own `fetch` (a curl without the headers, a form post from another page, an old cached script). Use the dashboard page itself after a hard refresh; scripted calls must send `Origin: http://<host:port>` and `x-aidlc-request: 1`.
185
+ - `403 Host header does not match this dashboard; open it at its bound address` — opened under another host name (for example a LAN name while bound to `127.0.0.1`). Use the printed URL; any loopback name works when bound to loopback.
186
+ - `403 Cross-origin request rejected` — a state-changing request from another origin; use the dashboard page itself.
187
+ - `403 Fleet approval needs the reviewer credential …` — restart `aidlc-kit ui` with `AIDLC_FLEET_REVIEWER_TOKEN` or `--reviewer-token-file <file>` (outside the project, mode `600`), or approve from a reviewer terminal with `remote-state.mjs gate approve <task-id> --snapshot <id> --source "<approval>"`.
188
+ - `Credential file must …` — `--reviewer-token-file` must be outside the project, a regular non-symlink file with mode `600`/`400`, containing one 16–256 character token.
99
189
 
100
- ## Loop daemon diagnostics
190
+ ### Containers panel is empty or `docker · unavailable`
101
191
 
102
- - `Loop daemon already running (pid N)` — one daemon per project (`.agents/data/loop/daemon.lock`); stop the running one first. A lock owned by a dead pid is reclaimed automatically.
103
- - `daemon_poll_error` — the daemon could not list tasks (for example the fleet service is unreachable). It keeps polling and does not stop; fix connectivity or credentials and it recovers on the next poll.
104
- - `daemon_turn_error`, or a `daemon_turn` with status `blocked`/`reconcile` — that task is retried with exponential backoff (capped at 10 minutes) while other tasks keep running. Inspect it with `task show` (local) or `remote-state.mjs task next` (fleet).
105
- - `loop resume is removed …` — use `loop start`; re-activate a paused task with the dashboard **resume** or the task status command.
192
+ - Empty with "No worker containers recorded" — the loop has not built an item of this task yet (clarify/plan run on the host, and a task driven from a terminal without the loop never starts containers). Records appear in `.agents/data/tasks/<task-id>/runtime/workers/index.json` once a worker turn starts.
193
+ - `docker · unavailable` — the dashboard could not run `docker ps` (no Docker, another context, or a slow daemon beyond 4 s); rows still show from the index, with `running` meaning "not ended yet".
194
+ - **Log** disabled with "log is on another host" — a fleet worker on another machine recorded the entry; the log file lives in that checkout.
195
+ - `Container log not found` — the assignment never wrote output or both `.log` generations were cleaned up.
106
196
 
107
- ## Dashboard `401` / `403`
197
+ ### Live log is empty or stuck on "connecting…"
108
198
 
109
- - `401 Invalid or missing approve token` — the browser has no current token. Open the login URL printed by `aidlc-kit ui` (the token changes on every restart unless you pass `--token-file`), or paste the token into **Settings**. The token is accepted only in the `x-aidlc-token` or `Authorization: Bearer` header, never as a form or body field.
110
- - `403 Host header does not match this dashboard; open it at its bound address` — the page was opened under a host name other than the bound address (for example a LAN name while bound to `127.0.0.1`). Use the printed URL; any loopback name works when bound to loopback.
111
- - `403 Cross-origin request rejected` — a state-changing request came from another origin. Use the dashboard page itself.
112
- - `403 Fleet approval needs the reviewer credential …` — a fleet dashboard without a reviewer credential cannot approve. Restart `aidlc-kit ui` with `AIDLC_FLEET_REVIEWER_TOKEN` or `--reviewer-token-file <file>` (outside the project, mode `600`), or approve from a reviewer terminal with `remote-state.mjs gate approve <task-id> --snapshot <id> --source "<approval>"`.
113
- - `Token file must …` — `--token-file`/`--reviewer-token-file` must live outside the project, be a regular non-symlink file with mode `600`/`400`, and contain one 16–256 character token.
199
+ - The log reads `.agents/data/tasks/<task-id>/runtime/events.jsonl` (or, until `loop migrate-data` has moved it, `.agents/data/loop/events/<task-id>.jsonl` from an older version), falling back to the **fixed** global `.agents/data/loop/ui-events.jsonl`. The daemon writes only when `AIDLC_LOOP_EVENT_LOG` points at that exact path (set automatically); if the shell exports another path, unset it and restart the daemon.
200
+ - The full log is on the **detail** page (`/tasks/<id>`); the side panel shows the last 20 important lines.
201
+ - A stopped daemon produces no events; the header shows whether it runs, and `.agents/data/loop/daemon.log` has start-up errors.
202
+ - Daemon-wide events (`daemon_poll`, written only when the actionable set or error state changes) are only in the global file. If **Important** shows little, switch to **All** or **Raw JSON**.
203
+ - `tail -f` the task file (or the global file): if it grows while the page does not, hard-refresh. A quiet global file is normal; idle polls are not logged.
114
204
 
115
- ## Loop / fleet experimental status
205
+ ## Fleet authority mismatch
116
206
 
117
- - Local loop mode is usable today; fleet mode and the coordination service are still under active development. The whole loop is experimental; pre-1.0 breaking changes are possible.
118
- - Selecting a mode during `init` or `upgrade` never starts or approves anything. Only `aidlc-kit loop start` runs the loop daemon, in either mode.
119
- - See the warning in [README](../README.md) and [Coordination service](./coordination-service.md).
207
+ - With `AIDLC_FLEET_URL` set, local lifecycle scripts throw `Fleet authority is configured; use remote-state.mjs instead of local lifecycle scripts`. By design: never silently switch authorities.
208
+ - Use `node .agents/aidlc/scripts/remote-state.mjs ...` for all mutations ([Coordination service](./coordination-service.md)).
120
209
 
121
210
  ## When to escalate
122
211
 
123
- - Repair bound hit (`REPAIR_BOUND`): follow the returned handoff command — record a durable handoff (`task handoff`), reopen to plan, create a successor, supersede, or close — with evidence. Do not present G2.
124
- - Security, migration, or contract changes reopen Approve plan (G1) even after a prior approval; re-run `gate-check` and present the gate again.
125
- - Fleet/loop issues affecting canonical state: stop and use `remote-state.mjs`; never mix authorities.
212
+ - `REPAIR_BOUND`: follow the returned handoff command — durable handoff (`task handoff`), reopen to plan, successor, supersede, or close — with evidence. Do not present G2.
213
+ - Security, migration, or contract changes reopen Approve plan (G1) even after approval; re-run `gate-check` and present the gate again.
214
+ - Fleet/loop issues affecting canonical state: stop and use `remote-state.mjs`; never mix authorities.
215
+
216
+ ## Related
217
+
218
+ - [Local loop walkthrough](./loop-local-run.md) — day-to-day loop operation.
219
+ - [Loop setup runbook](./loop-runbook.md) — enabling and configuring the loop.
220
+ - [AI-DLC Coordination service](./coordination-service.md) — fleet deployment and remote state.
221
+ - [Command reference](./command-reference.md) — flags, environment variables, and dashboard routes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@felixdotgo/aidlc-kit",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Install a local, agent-adapted AI-DLC workflow into a project.",
5
5
  "keywords": [
6
6
  "ai-dlc",