@quolu/lattice 0.52.3 → 0.53.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 (188) hide show
  1. package/LICENSE +147 -147
  2. package/README.ja.md +355 -355
  3. package/README.md +258 -258
  4. package/bin/lattice-bridge.mjs +25 -0
  5. package/bin/lattice-hub.mjs +67 -0
  6. package/bin/lattice-mcp.mjs +0 -0
  7. package/bin/lattice-scripted-adapter.mjs +0 -0
  8. package/bin/lattice-scripted-worker.mjs +0 -0
  9. package/bin/lattice-work-order-adapter.mjs +0 -0
  10. package/bin/lattice.mjs +0 -0
  11. package/docs/bridge-setup.md +132 -132
  12. package/docs/schemas/lattice.executor_packet.v1.schema.json +57 -57
  13. package/docs/schemas/lattice.executor_receipt.v1.schema.json +66 -66
  14. package/docs/schemas/lattice.phase_todo_revision.v3.schema.json +360 -360
  15. package/docs/schemas/lattice.plan_create_input.v1.schema.json +56 -56
  16. package/docs/schemas/lattice.plan_create_input.v2.schema.json +72 -72
  17. package/docs/schemas/lattice.plan_create_input.v3.schema.json +81 -81
  18. package/docs/schemas/lattice.plan_create_input.v4.schema.json +85 -85
  19. package/docs/schemas/lattice.run_request.v1.schema.json +238 -238
  20. package/docs/schemas/lattice.runtime_adapter_capabilities.v2.schema.json +55 -55
  21. package/docs/schemas/lattice.runtime_adapter_registration_input.v1.schema.json +78 -78
  22. package/docs/schemas/lattice.runtime_adapter_registration_input.v2.schema.json +86 -86
  23. package/docs/schemas/lattice.todo_extraction.v2.schema.json +298 -298
  24. package/docs/schemas/lattice.todo_extraction.v3.schema.json +146 -146
  25. package/docs/schemas/lattice.todo_revision.v2.schema.json +260 -260
  26. package/docs/schemas/lattice.todo_revision_set.v3.schema.json +363 -363
  27. package/package.json +103 -103
  28. package/sensor/LICENSE +21 -21
  29. package/sensor/NOTICE +19 -19
  30. package/sensor/dist/bin/lattice-sensor.js +9 -9
  31. package/sensor/dist/db/index.js +24 -24
  32. package/sensor/dist/db/migrations.js +41 -41
  33. package/sensor/dist/db/queries.js +164 -164
  34. package/sensor/dist/db/schema.sql +205 -205
  35. package/sensor/dist/directory.js +5 -5
  36. package/sensor/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  37. package/sensor/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  38. package/sensor/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  39. package/sensor/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  40. package/sensor/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  41. package/sensor/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  42. package/sensor/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
  43. package/sensor/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
  44. package/sensor/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
  45. package/sensor/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  46. package/sensor/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  47. package/sensor/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
  48. package/sensor/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
  49. package/sensor/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
  50. package/sensor/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  51. package/sensor/dist/mcp/liveness-watchdog.js +53 -53
  52. package/sensor/dist/mcp/server-instructions.js +95 -95
  53. package/sensor/package.json +56 -56
  54. package/src/artifact-contracts-v2.mjs +325 -325
  55. package/src/artifact-contracts.mjs +895 -895
  56. package/src/boundary-compiler.mjs +712 -712
  57. package/src/boundary-observation-compiler-v2.mjs +344 -344
  58. package/src/bounded-seam.mjs +230 -230
  59. package/src/bridge-address.mjs +107 -107
  60. package/src/bridge-cli.mjs +303 -297
  61. package/src/bridge-config.mjs +382 -346
  62. package/src/bridge-daemon.mjs +378 -378
  63. package/src/bridge-hub-heartbeat.mjs +170 -0
  64. package/src/bridge-hub-protocol.mjs +198 -0
  65. package/src/bridge-hub-server.mjs +544 -0
  66. package/src/bridge-launch-agent.mjs +323 -323
  67. package/src/bridge-registrar.mjs +102 -102
  68. package/src/bridge-server.mjs +376 -376
  69. package/src/cli-help.mjs +308 -308
  70. package/src/cli-stdio.mjs +40 -40
  71. package/src/control-compiler.mjs +532 -532
  72. package/src/dag-chain.mjs +261 -261
  73. package/src/factory-diagnostics.mjs +188 -188
  74. package/src/git-process.mjs +72 -0
  75. package/src/hash-chain.mjs +76 -76
  76. package/src/hooks-cli.mjs +1057 -1057
  77. package/src/isolation-runner.mjs +409 -409
  78. package/src/node-version-guard.mjs +44 -44
  79. package/src/project-cli.mjs +3 -3
  80. package/src/project-identity.mjs +130 -130
  81. package/src/rc1-black-box-oracle.mjs +906 -906
  82. package/src/rc1-comparison.mjs +154 -154
  83. package/src/rc1-evidence-bundle.mjs +456 -456
  84. package/src/rc1-v4-campaign.mjs +708 -708
  85. package/src/rc1-v4-transform.mjs +467 -467
  86. package/src/rc1-v5-artifact-set.mjs +855 -855
  87. package/src/rc1-v5-behavior-evidence.mjs +594 -594
  88. package/src/rc1-v5-campaign.mjs +797 -797
  89. package/src/rc1-v5-transform.mjs +421 -421
  90. package/src/rc1-v6-artifact-set.mjs +807 -807
  91. package/src/rc1-v6-behavior-evidence.mjs +273 -273
  92. package/src/rc1-v6-campaign.mjs +623 -623
  93. package/src/rc1-v6-causal-binding.mjs +473 -473
  94. package/src/rc1-v6-measurement.mjs +313 -313
  95. package/src/rc2-artifact-set.mjs +1584 -1584
  96. package/src/rc2-campaign.mjs +1506 -1506
  97. package/src/rc2-delivery-policy-front-end.mjs +1079 -1079
  98. package/src/rc2-delivery-policy-oracle.mjs +134 -134
  99. package/src/rc2-delivery-policy-transform.mjs +1127 -1127
  100. package/src/rc2-rc1-transfer-front-end.mjs +511 -511
  101. package/src/rc3-actual-dogfood.mjs +652 -652
  102. package/src/rc3-dogfood-scaffold.mjs +315 -315
  103. package/src/rc3-scripted-campaign.mjs +1383 -1383
  104. package/src/rc4-stage1-dogfood.mjs +673 -673
  105. package/src/runtime-adapter-registry.mjs +524 -524
  106. package/src/runtime-cli.mjs +4588 -4588
  107. package/src/runtime-contracts.mjs +824 -824
  108. package/src/runtime-control-store.mjs +604 -604
  109. package/src/runtime-controller-protocol.mjs +587 -587
  110. package/src/runtime-decision-verifier.mjs +701 -701
  111. package/src/runtime-diff-observer.mjs +361 -361
  112. package/src/runtime-direct-os-observer.mjs +301 -301
  113. package/src/runtime-driver-state.mjs +166 -166
  114. package/src/runtime-engine.mjs +779 -779
  115. package/src/runtime-errors.mjs +356 -356
  116. package/src/runtime-event-store.mjs +189 -189
  117. package/src/runtime-front-end.mjs +925 -925
  118. package/src/runtime-gate-store.mjs +481 -481
  119. package/src/runtime-hold-recompile.mjs +916 -916
  120. package/src/runtime-io-sentinel.mjs +391 -391
  121. package/src/runtime-lifecycle-lock.mjs +294 -294
  122. package/src/runtime-managed-supervisor.mjs +1490 -1490
  123. package/src/runtime-multi-epoch-store.mjs +838 -838
  124. package/src/runtime-projection.mjs +269 -269
  125. package/src/runtime-pull-intake.mjs +1192 -1192
  126. package/src/runtime-scripted-adapter-controller.mjs +1160 -1160
  127. package/src/runtime-scripted-executor.mjs +163 -163
  128. package/src/runtime-scripted-worktree.mjs +104 -104
  129. package/src/runtime-seam-resolve.mjs +428 -428
  130. package/src/runtime-seam-treatment.mjs +173 -173
  131. package/src/runtime-socket-owner.mjs +125 -125
  132. package/src/runtime-work-order-contracts.mjs +91 -91
  133. package/src/runtime-work-order-controller.mjs +1171 -1171
  134. package/src/runtime-worktree-executor.mjs +199 -199
  135. package/src/schedulability-compiler-v2.mjs +303 -303
  136. package/src/schedulability-verifier-v2.mjs +317 -317
  137. package/src/seam-apply.mjs +549 -549
  138. package/src/seam-commit-shared.mjs +22 -22
  139. package/src/seam-commit-transform.mjs +81 -81
  140. package/src/seam-commit.mjs +18 -18
  141. package/src/seam-cost.mjs +322 -322
  142. package/src/seam-derivation.mjs +188 -188
  143. package/src/seam-gate.mjs +146 -146
  144. package/src/seam-proposal-contracts.mjs +446 -446
  145. package/src/seam-proposal-queries.mjs +521 -521
  146. package/src/seam-proposal.mjs +2011 -2011
  147. package/src/seam-ref.mjs +33 -33
  148. package/src/seam-rewrite.mjs +286 -286
  149. package/src/seam-transform.mjs +554 -554
  150. package/src/seam-verification.mjs +260 -260
  151. package/src/sensor-adapter.mjs +432 -432
  152. package/src/sensor-cli.mjs +139 -139
  153. package/src/sensor-diff.mjs +661 -661
  154. package/src/sensor-node-runtime.mjs +53 -53
  155. package/src/sensor-runtime.mjs +52 -52
  156. package/src/timestamp-contract.mjs +8 -8
  157. package/src/todo-audit-pending.mjs +91 -91
  158. package/src/todo-chain.mjs +178 -178
  159. package/src/todo-cli.mjs +8 -8
  160. package/src/todo-contracts.mjs +728 -728
  161. package/src/todo-dashboard-registry.mjs +573 -573
  162. package/src/todo-dispatch-shape.mjs +190 -190
  163. package/src/todo-gantt-html-independence.mjs +239 -239
  164. package/src/todo-gantt-html-shared.mjs +226 -226
  165. package/src/todo-gantt-html-style.mjs +131 -131
  166. package/src/todo-gantt-html.mjs +248 -248
  167. package/src/todo-gantt-layout.mjs +974 -974
  168. package/src/todo-gantt-live.mjs +361 -361
  169. package/src/todo-gantt-nested.mjs +263 -263
  170. package/src/todo-gantt-presentation.mjs +217 -217
  171. package/src/todo-gantt-scope.mjs +123 -123
  172. package/src/todo-gantt-svg.mjs +353 -353
  173. package/src/todo-independence-contracts.mjs +595 -595
  174. package/src/todo-independence-guidance.mjs +322 -322
  175. package/src/todo-independence.mjs +640 -640
  176. package/src/todo-markdown-renderer.mjs +260 -260
  177. package/src/todo-migration.mjs +448 -448
  178. package/src/todo-narrative-anchor.mjs +130 -130
  179. package/src/todo-note-store.mjs +629 -629
  180. package/src/todo-parallel-candidates.mjs +114 -114
  181. package/src/todo-revision.mjs +995 -995
  182. package/src/todo-split.mjs +472 -472
  183. package/src/todo-status.mjs +690 -690
  184. package/src/todo-store-git-transaction.mjs +418 -418
  185. package/src/todo-store.mjs +42 -21
  186. package/src/treatment-compiler.mjs +728 -728
  187. package/src/treatment-runner.mjs +656 -656
  188. package/src/witness-scaffold.mjs +180 -180
package/README.md CHANGED
@@ -1,258 +1,258 @@
1
- <p align="center">
2
- <img src=".github/og.png" alt="Lattice — several viable routes emerging through an apparently blocked mountain valley" width="100%">
3
- <br>
4
- <sub><em>This image represents several viable paths emerging from terrain that first appeared blocked, as autonomous executors begin moving in coordination.</em></sub>
5
- </p>
6
-
7
- # Lattice
8
-
9
- [![npm](https://img.shields.io/npm/v/@quolu/lattice?color=cb3837&logo=npm)](https://www.npmjs.com/package/@quolu/lattice)
10
- [![CI](https://github.com/kitepon-rgb/Lattice/actions/workflows/ci.yml/badge.svg)](https://github.com/kitepon-rgb/Lattice/actions/workflows/ci.yml)
11
- [![license](https://img.shields.io/badge/license-PolyForm%20Noncommercial%201.0.0-blue)](LICENSE)
12
- [![node](https://img.shields.io/node/v/@quolu/lattice?color=339933&logo=node.js&logoColor=white)](https://nodejs.org/)
13
- [![patent](https://img.shields.io/badge/patent-pending%20JP%202026--178950-6366f1)](#patent)
14
-
15
- **English** · [日本語](README.ja.md)
16
-
17
- > **Stop serializing work that only looks like it conflicts.**
18
- > Lattice is a schedulability compiler for multi-agent development. It observes the real
19
- > boundaries of your codebase, proves which tasks can run in parallel, and — when two tasks
20
- > genuinely collide — **refactors the seam between them and recompiles the plan** so they can
21
- > run in parallel after all.
22
-
23
- Built and maintained by [Quo](https://x.com/QLyun35332) at [kitepon.dev](https://kitepon.dev/en).
24
-
25
- ## Why
26
-
27
- Give three coding agents three tasks and the usual outcome is one of two failures:
28
-
29
- - **You serialize too much.** "These both touch `renderer.ts`, so run them one at a time."
30
- Often they touch *different symbols* in that file and could have run together.
31
- - **You serialize too little.** Nothing declared a dependency, so you run them in parallel and
32
- discover the collision after both have written conflicting code.
33
-
34
- Both failures come from the same gap: *nobody actually measured the boundary.* Dependency
35
- arrows in a task list are a claim about intent, not evidence about code.
36
-
37
- Lattice closes that gap with a different move. It does not just **detect** the conflict — it
38
- **removes** it. When two tasks contend for one file, Lattice derives a cut, applies it in an
39
- isolated worktree, verifies the transform against five acceptance conditions, and recompiles the
40
- plan against the transformed source. The conflict edge disappears because the shared surface
41
- stopped being shared.
42
-
43
- ## What it actually does
44
-
45
- ```
46
- declare boundaries → compile independence → conflict?
47
- ├─ no → run in parallel
48
- └─ yes → propose a seam
49
- → transform in an isolated worktree
50
- → verify (5 conditions)
51
- → land + recompile → run in parallel
52
- ```
53
-
54
- **A real example, from this repository.** Two tasks both needed to change
55
- `src/seam-commit.mjs`. Lattice compiled the declarations, reported `conflict_count: 1` with
56
- `severability: code_seam`, proposed a cut, and applied it in an isolated worktree. After all
57
- five acceptance conditions passed, the file was split into one owned surface per task plus a
58
- shared and a residual surface. Recompiling reported `conflict_count: 0` and placed both tasks in
59
- the same parallel group.
60
-
61
- Nobody hand-refactored that file. The product cut it so the work could parallelize.
62
-
63
- ### Task memory travels with the task
64
-
65
- Every newly authored ToDo carries an initial Markdown design memo. Empty text and a file reference are
66
- not accepted; an agent with no plan must explicitly write `NO_PLAN`. Lattice asks:
67
- “あなたがこのToDoに対して、何も考えていないならば、設計メモに `NO_PLAN` と書いてください”.
68
- A normal `lattice todo show` and every successful `lattice todo start` return that memo automatically.
69
-
70
- After work begins, an agent can append decisions, rejected approaches, findings, cautions, and open
71
- questions. These remain a separate, append-only `note_context`, with origin, correction state, chain
72
- head, overflow, and the full-history command.
73
-
74
- ```bash
75
- lattice todo note --plan <key> --task <id> --message "Use the existing parser; do not add a fallback"
76
- lattice todo show --plan <key> --task <id> --json
77
- ```
78
-
79
- The selected ToDo's detail pane shows the initial design memo and the append-only note bodies, plus the
80
- status of each prerequisite and dependent ToDo (pending, in progress, done, blocked) and whether the ToDo
81
- can run in parallel. Note bodies are carried by every rendered surface, including HTML served outside the
82
- repository. Static per-project HTML is not generated; `lattice todo gantt serve` and the shared dashboard
83
- read the store dynamically.
84
-
85
- ### The five acceptance conditions
86
-
87
- A transform is adopted only when **all five** hold. One missing condition rejects it:
88
-
89
- | Condition | Meaning |
90
- |---|---|
91
- | `behavior_equivalent` | The original path's public export surface is preserved, and no moved code references a symbol that stayed behind without a binding (severed-reference net) |
92
- | `focused_tests_passed` | The affected tests actually pass against the transformed source |
93
- | `sensor_fresh` | The structure index was rebuilt and covers the new surfaces |
94
- | `overlap_reduced` | The target conflict is gone **and** plan-wide conflict pairs did not increase |
95
- | `parallelism_improved` | The number of execution waves went down |
96
-
97
- ### Runtime, not just planning
98
-
99
- Complete separation is not obtainable at planning time — dynamic dispatch, runtime-resolved
100
- paths, and external state always leave residue. That is the design, not a deficiency: Lattice
101
- carries a second stage at runtime.
102
-
103
- While work executes, Lattice observes **what was actually changed**, not what was declared. When
104
- it sees a task writing outside its declared scope, or into another running task's scope, it
105
- raises a runtime conflict — and can either hold one side while the other commits, or transform
106
- the seam and resume both. Both treatments are exercised end-to-end against a live store in the
107
- integration suite.
108
-
109
- Two projection surfaces support that decision without scoring anyone. `lattice run seam profile`
110
- (and `todo seam-profile` at plan time) reports the countable anatomy of a cut — cross references,
111
- shared module state with read/write distinction, shared imports, cycles — with declared blind
112
- spots, and never persists into any digested artifact. And every machine-transform rejection is
113
- classified by a **certainty gate**: the machine only transforms what it can do with certainty,
114
- and each refusal says whether fixing the declaration suffices or the seam should be handed to
115
- the operating AI.
116
-
117
- ## Install
118
-
119
- ```bash
120
- npm install -g @quolu/lattice
121
- ```
122
-
123
- Requires **Node.js 22.13 or newer, except 25.x** (`engines: >=22.13 <25 || >=26`; Node 25's V8
124
- turboshaft WASM JIT breaks the bundled sensor, so it is blocked with a banner). The structure sensor ships inside the package — there is nothing
125
- else to install, and Lattice never falls back to a sensor on your `PATH`.
126
-
127
- ## Quick start
128
-
129
- Every project begins with typed discovery. Never guess from directory layout:
130
-
131
- ```bash
132
- lattice status --json
133
- ```
134
-
135
- `state` is one of `uninitialized | ready | active_run | invalid`, and `next_action` gives the
136
- canonical next command. Then index the codebase and declare boundaries:
137
-
138
- ```bash
139
- lattice sensor init . --json
140
- ```
141
-
142
- Write a draft declaring what each task owns, then let the tool supply the parts you cannot
143
- hand-write — fresh observations, provenance wiring, canonical bytes:
144
-
145
- ```bash
146
- lattice todo independence witness scaffold --plan <key> --input draft.json
147
- lattice todo independence compile --plan <key> --input .lattice/todo/witness/<key>.json
148
- lattice todo independence --plan <key> --json
149
- ```
150
-
151
- If the verdict reports a conflict with `severability: code_seam`, ask for a cut and apply it:
152
-
153
- ```bash
154
- lattice todo seam-proposal compile --plan <key>
155
- lattice todo seam-proposal apply --plan <key> # isolated worktree, five conditions
156
- lattice todo seam-proposal land --plan <key> --names names.json
157
- ```
158
-
159
- Full CLI surface: `lattice --help`, then
160
- `lattice <plan|run|event|todo|sensor|factory-diagnostics|runtime-errors|bridge|hooks> --help`.
161
-
162
- ## Design principles
163
-
164
- **The operating AI is part of the apparatus.** Lattice is driven by an AI agent, and that agent
165
- is not outside the system — it is a component of it. So Lattice supplies only what the AI
166
- *cannot* produce for itself: structure observation, contracts, verification, records, and
167
- version boundaries. Estimation, judgment, and naming remain the AI's job. You will not find an
168
- LLM call inside this product; adding one would duplicate a capability already present at the
169
- point of use.
170
-
171
- **Unknown is never rounded to "no conflict."** If a boundary was not verified, the verdict says
172
- `missing`, not "independent." The absence of a dependency edge is not evidence of independence.
173
-
174
- **Fail closed, and say why.** Every rejection carries a typed reason and a next action. A
175
- transform that cannot be verified is not adopted. A finding that cannot be independently
176
- re-derived is not recorded.
177
-
178
- **Heavy audit is on by default.** A plan without explicit phases still carries an implicit
179
- terminal audit: every task being done means `gate_ready` — *awaiting audit* — not finished. The
180
- live dependency diagram refuses to fold such a plan away, because folding is how the product
181
- says "closed", and nothing gets there without an evidence-bound `phase accept`. Creation is never
182
- rejected over it; the requirement is reported instead. And the audit gate never touches dispatch:
183
- phases order reviews, the ToDo DAG orders work
184
- ([ADR 0147](docs/adr/0147-audit-is-on-by-default.md)).
185
-
186
- **History closes unaudited, never audited.** Work that finished long ago cannot be audited — the
187
- code under review has already moved. Demanding an audit there produces either a false finding
188
- (pointing at a later, intentional change) or a rubber stamp. So there is a third terminal state,
189
- `closed_unaudited`: recorded with a reason, folded away like finished work, and **structurally
190
- incapable of passing as `accepted`** — phase-accept dependencies unlock on `accepted` alone. The
191
- bulk entry point never runs by itself, and the machine never infers "old enough to skip"; a human
192
- decides what gets audited and what becomes history
193
- ([ADR 0148](docs/adr/0148-history-closes-unaudited-not-audited.md)).
194
-
195
- ## Patent
196
-
197
- The design in this repository is the subject of a Japanese patent application:
198
-
199
- | | |
200
- |---|---|
201
- | Application number | 特願2026-178950 (JP 2026-178950) |
202
- | Filing date | 2026-07-27 |
203
- | Title | 情報処理装置、ソフトウェア開発制御方法及びプログラム<br>(Information processing apparatus, software development control method, and program) |
204
- | Claims | 12 |
205
-
206
- Noncommercial use is permitted under the [License](#license) below.
207
- **A separate commercial license is required for commercial use.**
208
-
209
- ## Ownership boundary
210
-
211
- This repository owns the plan/ToDo/run store, the bundled sensor, schemas, migrations,
212
- releases, and diagnostics. [dotagents](https://github.com/kitepon-rgb/dotagents) is the
213
- internal toolchain behind kitepon.dev and owns cross-product installation and host integration.
214
-
215
- - Product philosophy: [PLAN.md](PLAN.md)
216
- - Public contract: [docs/00_product-contract.md](docs/00_product-contract.md)
217
- - Immutable decisions: [docs/adr/](docs/adr/)
218
- - Document map: [docs/README.md](docs/README.md)
219
-
220
- ## Development
221
-
222
- ```bash
223
- npm test # product test gate
224
- npm run check # syntax + control-character gate
225
- npm run ci # full gate
226
- ```
227
-
228
- The full gate includes checks that are unusual and deliberate:
229
-
230
- - **`check:cli-surface`** — every shipped command must have help text *and* be exercised through
231
- a CLI entry point by a test. Shipping a command nobody ever ran is treated as a defect.
232
- - **`check:open-questions`** — every unresolved question in an ADR must carry an explicit firing
233
- condition, so "deferred" is never indistinguishable from "forgotten."
234
- - **`check:reachability`** — every module must be reachable from a product entry point, or be
235
- declared a research artifact with a reason.
236
-
237
- Detailed operational notes (dashboard, bridge, actor environment, store transactions) are in
238
- [README.ja.md](README.ja.md) and [docs/](docs/).
239
-
240
- ## License
241
-
242
- **[PolyForm Noncommercial License 1.0.0](LICENSE)** — free for noncommercial use.
243
-
244
- - **Free:** personal projects, study and research, hobby and amateur work, charities,
245
- educational institutions, public research organizations, and government institutions.
246
- - **Permission required:** commercial use. That includes use inside a company's paid work or products,
247
- regardless of whether Lattice itself is redistributed.
248
-
249
- **For commercial use**, a separate commercial license is required.
250
- Enquiries can be made by email at [kitepon@gmail.com](mailto:kitepon@gmail.com). Whether a
251
- license is granted, and on what terms, is decided case by case.
252
-
253
- The bundled structure sensor in [`sensor/`](sensor/) is third-party work absorbed into this
254
- repository and remains under the **MIT License**. Its upstream origin and attribution are
255
- recorded in [`sensor/NOTICE`](sensor/NOTICE); the license text is
256
- [`sensor/LICENSE`](sensor/LICENSE). The terms above do not modify it.
257
-
258
- © 2026 quolu (kitepon-rgb)
1
+ <p align="center">
2
+ <img src=".github/og.png" alt="Lattice — several viable routes emerging through an apparently blocked mountain valley" width="100%">
3
+ <br>
4
+ <sub><em>This image represents several viable paths emerging from terrain that first appeared blocked, as autonomous executors begin moving in coordination.</em></sub>
5
+ </p>
6
+
7
+ # Lattice
8
+
9
+ [![npm](https://img.shields.io/npm/v/@quolu/lattice?color=cb3837&logo=npm)](https://www.npmjs.com/package/@quolu/lattice)
10
+ [![CI](https://github.com/kitepon-rgb/Lattice/actions/workflows/ci.yml/badge.svg)](https://github.com/kitepon-rgb/Lattice/actions/workflows/ci.yml)
11
+ [![license](https://img.shields.io/badge/license-PolyForm%20Noncommercial%201.0.0-blue)](LICENSE)
12
+ [![node](https://img.shields.io/node/v/@quolu/lattice?color=339933&logo=node.js&logoColor=white)](https://nodejs.org/)
13
+ [![patent](https://img.shields.io/badge/patent-pending%20JP%202026--178950-6366f1)](#patent)
14
+
15
+ **English** · [日本語](README.ja.md)
16
+
17
+ > **Stop serializing work that only looks like it conflicts.**
18
+ > Lattice is a schedulability compiler for multi-agent development. It observes the real
19
+ > boundaries of your codebase, proves which tasks can run in parallel, and — when two tasks
20
+ > genuinely collide — **refactors the seam between them and recompiles the plan** so they can
21
+ > run in parallel after all.
22
+
23
+ Built and maintained by [Quo](https://x.com/QLyun35332) at [kitepon.dev](https://kitepon.dev/en).
24
+
25
+ ## Why
26
+
27
+ Give three coding agents three tasks and the usual outcome is one of two failures:
28
+
29
+ - **You serialize too much.** "These both touch `renderer.ts`, so run them one at a time."
30
+ Often they touch *different symbols* in that file and could have run together.
31
+ - **You serialize too little.** Nothing declared a dependency, so you run them in parallel and
32
+ discover the collision after both have written conflicting code.
33
+
34
+ Both failures come from the same gap: *nobody actually measured the boundary.* Dependency
35
+ arrows in a task list are a claim about intent, not evidence about code.
36
+
37
+ Lattice closes that gap with a different move. It does not just **detect** the conflict — it
38
+ **removes** it. When two tasks contend for one file, Lattice derives a cut, applies it in an
39
+ isolated worktree, verifies the transform against five acceptance conditions, and recompiles the
40
+ plan against the transformed source. The conflict edge disappears because the shared surface
41
+ stopped being shared.
42
+
43
+ ## What it actually does
44
+
45
+ ```
46
+ declare boundaries → compile independence → conflict?
47
+ ├─ no → run in parallel
48
+ └─ yes → propose a seam
49
+ → transform in an isolated worktree
50
+ → verify (5 conditions)
51
+ → land + recompile → run in parallel
52
+ ```
53
+
54
+ **A real example, from this repository.** Two tasks both needed to change
55
+ `src/seam-commit.mjs`. Lattice compiled the declarations, reported `conflict_count: 1` with
56
+ `severability: code_seam`, proposed a cut, and applied it in an isolated worktree. After all
57
+ five acceptance conditions passed, the file was split into one owned surface per task plus a
58
+ shared and a residual surface. Recompiling reported `conflict_count: 0` and placed both tasks in
59
+ the same parallel group.
60
+
61
+ Nobody hand-refactored that file. The product cut it so the work could parallelize.
62
+
63
+ ### Task memory travels with the task
64
+
65
+ Every newly authored ToDo carries an initial Markdown design memo. Empty text and a file reference are
66
+ not accepted; an agent with no plan must explicitly write `NO_PLAN`. Lattice asks:
67
+ “あなたがこのToDoに対して、何も考えていないならば、設計メモに `NO_PLAN` と書いてください”.
68
+ A normal `lattice todo show` and every successful `lattice todo start` return that memo automatically.
69
+
70
+ After work begins, an agent can append decisions, rejected approaches, findings, cautions, and open
71
+ questions. These remain a separate, append-only `note_context`, with origin, correction state, chain
72
+ head, overflow, and the full-history command.
73
+
74
+ ```bash
75
+ lattice todo note --plan <key> --task <id> --message "Use the existing parser; do not add a fallback"
76
+ lattice todo show --plan <key> --task <id> --json
77
+ ```
78
+
79
+ The selected ToDo's detail pane shows the initial design memo and the append-only note bodies, plus the
80
+ status of each prerequisite and dependent ToDo (pending, in progress, done, blocked) and whether the ToDo
81
+ can run in parallel. Note bodies are carried by every rendered surface, including HTML served outside the
82
+ repository. Static per-project HTML is not generated; `lattice todo gantt serve` and the shared dashboard
83
+ read the store dynamically.
84
+
85
+ ### The five acceptance conditions
86
+
87
+ A transform is adopted only when **all five** hold. One missing condition rejects it:
88
+
89
+ | Condition | Meaning |
90
+ |---|---|
91
+ | `behavior_equivalent` | The original path's public export surface is preserved, and no moved code references a symbol that stayed behind without a binding (severed-reference net) |
92
+ | `focused_tests_passed` | The affected tests actually pass against the transformed source |
93
+ | `sensor_fresh` | The structure index was rebuilt and covers the new surfaces |
94
+ | `overlap_reduced` | The target conflict is gone **and** plan-wide conflict pairs did not increase |
95
+ | `parallelism_improved` | The number of execution waves went down |
96
+
97
+ ### Runtime, not just planning
98
+
99
+ Complete separation is not obtainable at planning time — dynamic dispatch, runtime-resolved
100
+ paths, and external state always leave residue. That is the design, not a deficiency: Lattice
101
+ carries a second stage at runtime.
102
+
103
+ While work executes, Lattice observes **what was actually changed**, not what was declared. When
104
+ it sees a task writing outside its declared scope, or into another running task's scope, it
105
+ raises a runtime conflict — and can either hold one side while the other commits, or transform
106
+ the seam and resume both. Both treatments are exercised end-to-end against a live store in the
107
+ integration suite.
108
+
109
+ Two projection surfaces support that decision without scoring anyone. `lattice run seam profile`
110
+ (and `todo seam-profile` at plan time) reports the countable anatomy of a cut — cross references,
111
+ shared module state with read/write distinction, shared imports, cycles — with declared blind
112
+ spots, and never persists into any digested artifact. And every machine-transform rejection is
113
+ classified by a **certainty gate**: the machine only transforms what it can do with certainty,
114
+ and each refusal says whether fixing the declaration suffices or the seam should be handed to
115
+ the operating AI.
116
+
117
+ ## Install
118
+
119
+ ```bash
120
+ npm install -g @quolu/lattice
121
+ ```
122
+
123
+ Requires **Node.js 22.13 or newer, except 25.x** (`engines: >=22.13 <25 || >=26`; Node 25's V8
124
+ turboshaft WASM JIT breaks the bundled sensor, so it is blocked with a banner). The structure sensor ships inside the package — there is nothing
125
+ else to install, and Lattice never falls back to a sensor on your `PATH`.
126
+
127
+ ## Quick start
128
+
129
+ Every project begins with typed discovery. Never guess from directory layout:
130
+
131
+ ```bash
132
+ lattice status --json
133
+ ```
134
+
135
+ `state` is one of `uninitialized | ready | active_run | invalid`, and `next_action` gives the
136
+ canonical next command. Then index the codebase and declare boundaries:
137
+
138
+ ```bash
139
+ lattice sensor init . --json
140
+ ```
141
+
142
+ Write a draft declaring what each task owns, then let the tool supply the parts you cannot
143
+ hand-write — fresh observations, provenance wiring, canonical bytes:
144
+
145
+ ```bash
146
+ lattice todo independence witness scaffold --plan <key> --input draft.json
147
+ lattice todo independence compile --plan <key> --input .lattice/todo/witness/<key>.json
148
+ lattice todo independence --plan <key> --json
149
+ ```
150
+
151
+ If the verdict reports a conflict with `severability: code_seam`, ask for a cut and apply it:
152
+
153
+ ```bash
154
+ lattice todo seam-proposal compile --plan <key>
155
+ lattice todo seam-proposal apply --plan <key> # isolated worktree, five conditions
156
+ lattice todo seam-proposal land --plan <key> --names names.json
157
+ ```
158
+
159
+ Full CLI surface: `lattice --help`, then
160
+ `lattice <plan|run|event|todo|sensor|factory-diagnostics|runtime-errors|bridge|hooks> --help`.
161
+
162
+ ## Design principles
163
+
164
+ **The operating AI is part of the apparatus.** Lattice is driven by an AI agent, and that agent
165
+ is not outside the system — it is a component of it. So Lattice supplies only what the AI
166
+ *cannot* produce for itself: structure observation, contracts, verification, records, and
167
+ version boundaries. Estimation, judgment, and naming remain the AI's job. You will not find an
168
+ LLM call inside this product; adding one would duplicate a capability already present at the
169
+ point of use.
170
+
171
+ **Unknown is never rounded to "no conflict."** If a boundary was not verified, the verdict says
172
+ `missing`, not "independent." The absence of a dependency edge is not evidence of independence.
173
+
174
+ **Fail closed, and say why.** Every rejection carries a typed reason and a next action. A
175
+ transform that cannot be verified is not adopted. A finding that cannot be independently
176
+ re-derived is not recorded.
177
+
178
+ **Heavy audit is on by default.** A plan without explicit phases still carries an implicit
179
+ terminal audit: every task being done means `gate_ready` — *awaiting audit* — not finished. The
180
+ live dependency diagram refuses to fold such a plan away, because folding is how the product
181
+ says "closed", and nothing gets there without an evidence-bound `phase accept`. Creation is never
182
+ rejected over it; the requirement is reported instead. And the audit gate never touches dispatch:
183
+ phases order reviews, the ToDo DAG orders work
184
+ ([ADR 0147](docs/adr/0147-audit-is-on-by-default.md)).
185
+
186
+ **History closes unaudited, never audited.** Work that finished long ago cannot be audited — the
187
+ code under review has already moved. Demanding an audit there produces either a false finding
188
+ (pointing at a later, intentional change) or a rubber stamp. So there is a third terminal state,
189
+ `closed_unaudited`: recorded with a reason, folded away like finished work, and **structurally
190
+ incapable of passing as `accepted`** — phase-accept dependencies unlock on `accepted` alone. The
191
+ bulk entry point never runs by itself, and the machine never infers "old enough to skip"; a human
192
+ decides what gets audited and what becomes history
193
+ ([ADR 0148](docs/adr/0148-history-closes-unaudited-not-audited.md)).
194
+
195
+ ## Patent
196
+
197
+ The design in this repository is the subject of a Japanese patent application:
198
+
199
+ | | |
200
+ |---|---|
201
+ | Application number | 特願2026-178950 (JP 2026-178950) |
202
+ | Filing date | 2026-07-27 |
203
+ | Title | 情報処理装置、ソフトウェア開発制御方法及びプログラム<br>(Information processing apparatus, software development control method, and program) |
204
+ | Claims | 12 |
205
+
206
+ Noncommercial use is permitted under the [License](#license) below.
207
+ **A separate commercial license is required for commercial use.**
208
+
209
+ ## Ownership boundary
210
+
211
+ This repository owns the plan/ToDo/run store, the bundled sensor, schemas, migrations,
212
+ releases, and diagnostics. [dotagents](https://github.com/kitepon-rgb/dotagents) is the
213
+ internal toolchain behind kitepon.dev and owns cross-product installation and host integration.
214
+
215
+ - Product philosophy: [PLAN.md](PLAN.md)
216
+ - Public contract: [docs/00_product-contract.md](docs/00_product-contract.md)
217
+ - Immutable decisions: [docs/adr/](docs/adr/)
218
+ - Document map: [docs/README.md](docs/README.md)
219
+
220
+ ## Development
221
+
222
+ ```bash
223
+ npm test # product test gate
224
+ npm run check # syntax + control-character gate
225
+ npm run ci # full gate
226
+ ```
227
+
228
+ The full gate includes checks that are unusual and deliberate:
229
+
230
+ - **`check:cli-surface`** — every shipped command must have help text *and* be exercised through
231
+ a CLI entry point by a test. Shipping a command nobody ever ran is treated as a defect.
232
+ - **`check:open-questions`** — every unresolved question in an ADR must carry an explicit firing
233
+ condition, so "deferred" is never indistinguishable from "forgotten."
234
+ - **`check:reachability`** — every module must be reachable from a product entry point, or be
235
+ declared a research artifact with a reason.
236
+
237
+ Detailed operational notes (dashboard, bridge, actor environment, store transactions) are in
238
+ [README.ja.md](README.ja.md) and [docs/](docs/).
239
+
240
+ ## License
241
+
242
+ **[PolyForm Noncommercial License 1.0.0](LICENSE)** — free for noncommercial use.
243
+
244
+ - **Free:** personal projects, study and research, hobby and amateur work, charities,
245
+ educational institutions, public research organizations, and government institutions.
246
+ - **Permission required:** commercial use. That includes use inside a company's paid work or products,
247
+ regardless of whether Lattice itself is redistributed.
248
+
249
+ **For commercial use**, a separate commercial license is required.
250
+ Enquiries can be made by email at [kitepon@gmail.com](mailto:kitepon@gmail.com). Whether a
251
+ license is granted, and on what terms, is decided case by case.
252
+
253
+ The bundled structure sensor in [`sensor/`](sensor/) is third-party work absorbed into this
254
+ repository and remains under the **MIT License**. Its upstream origin and attribution are
255
+ recorded in [`sensor/NOTICE`](sensor/NOTICE); the license text is
256
+ [`sensor/LICENSE`](sensor/LICENSE). The terms above do not modify it.
257
+
258
+ © 2026 quolu (kitepon-rgb)
@@ -5,9 +5,11 @@ import {
5
5
  readBridgeStopRequest, removeBridgeDaemonActiveMarker, removeBridgeDaemonDescriptor,
6
6
  writeBridgeDaemonDescriptor, writeBridgeStopReceipt,
7
7
  } from '../src/bridge-daemon.mjs';
8
+ import { createBridgeHubHeartbeatController } from '../src/bridge-hub-heartbeat.mjs';
8
9
  import { bridgeRuntimeController } from '../src/bridge-server.mjs';
9
10
 
10
11
  const env = process.env;
12
+ const hubHeartbeat = createBridgeHubHeartbeatController({ env });
11
13
  const instanceToken = env.LATTICE_BRIDGE_INSTANCE_TOKEN;
12
14
  if (typeof instanceToken !== 'string' || !/^[0-9a-f]{64}$/u.test(instanceToken)) {
13
15
  process.stderr.write(`${JSON.stringify({ schema: 'lattice.bridge_daemon_error.v1',
@@ -20,6 +22,7 @@ let closing = false;
20
22
  let descriptorFingerprint = null;
21
23
  let checking = false;
22
24
  let failClosedError = null;
25
+ let hubHeartbeatError = null;
23
26
  const close = async () => {
24
27
  if (closing) return;
25
28
  closing = true;
@@ -71,6 +74,28 @@ timer = setInterval(async () => {
71
74
  await writeBridgeDaemonDescriptor({ config, env });
72
75
  descriptorFingerprint = config.updated_at;
73
76
  }
77
+ // Hub heartbeat failures are reported but never fail-close local traffic:
78
+ // an unreachable hub is a routing problem for the hub's aggregate view,
79
+ // not a reason to stop serving this terminal's own dashboard directly.
80
+ // Network/hub-rejection failures already come back as typed results, not
81
+ // throws (sendBridgeHubHeartbeat's contract) — only a local error (e.g.
82
+ // the terminal identity file) reaches this catch.
83
+ try {
84
+ const heartbeat = await hubHeartbeat.tick({ config });
85
+ hubHeartbeatError = null;
86
+ if (heartbeat?.state === 'unreachable' || heartbeat?.state === 'rejected') {
87
+ const fingerprint = JSON.stringify(heartbeat);
88
+ if (fingerprint !== hubHeartbeatError) process.stderr.write(`${fingerprint}\n`);
89
+ hubHeartbeatError = fingerprint;
90
+ }
91
+ } catch (error) {
92
+ const failure = { schema: 'lattice.bridge_daemon_error.v1',
93
+ code: error?.code ?? 'BRIDGE_HUB_HEARTBEAT_FAILED',
94
+ message: error?.message ?? 'bridge hub heartbeat failed' };
95
+ const fingerprint = JSON.stringify(failure);
96
+ if (fingerprint !== hubHeartbeatError) process.stderr.write(`${fingerprint}\n`);
97
+ hubHeartbeatError = fingerprint;
98
+ }
74
99
  } catch (error) {
75
100
  const failure = { schema: 'lattice.bridge_daemon_error.v1',
76
101
  code: error?.code ?? 'BRIDGE_RECONCILE_FAILED',
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * bridge-hub server daemon entry point (bh5). Meant to run under systemd on a
4
+ * fixed, non-DHCP server — unlike `lattice-bridge.mjs`, there is no address
5
+ * reconciliation loop, health-attestation dance, or LaunchAgent coordination:
6
+ * systemd is the single process supervisor, and the hub's own host does not
7
+ * move. Configuration is environment-only (opt-in-via-environment, matching
8
+ * `bridge-registrar.mjs`'s posture) rather than a persisted CLI-managed
9
+ * config file, since this daemon has exactly one deployment target.
10
+ */
11
+
12
+ import { isIP } from 'node:net';
13
+ import { startBridgeHubServer } from '../src/bridge-hub-server.mjs';
14
+
15
+ const env = process.env;
16
+
17
+ function fail(code, message) {
18
+ process.stderr.write(`${JSON.stringify({ schema: 'lattice.hub_daemon_error.v1', code, message })}\n`);
19
+ process.exit(1);
20
+ }
21
+
22
+ // Defaults to loopback (bh2's original behavior) for local/dev use. Production
23
+ // deployment sets this explicitly — see src/bridge-hub-server.mjs's
24
+ // `listenAddress` doc comment for why a Docker-networked Caddy needs this to
25
+ // be the host's docker-bridge gateway address rather than 127.0.0.1.
26
+ const listenAddress = env.LATTICE_HUB_LISTEN ?? '127.0.0.1';
27
+ if (isIP(listenAddress) === 0) fail('LATTICE_HUB_LISTEN_INVALID', 'LATTICE_HUB_LISTEN must be an IP literal');
28
+
29
+ // No default port: an ephemeral (port 0) hub would give Caddy a moving
30
+ // upstream target every restart, defeating the point of a fixed endpoint.
31
+ const portValue = env.LATTICE_HUB_PORT;
32
+ if (typeof portValue !== 'string' || portValue.length === 0) {
33
+ fail('LATTICE_HUB_PORT_REQUIRED', 'LATTICE_HUB_PORT must be set to a fixed port (Caddy needs a stable upstream)');
34
+ }
35
+ const port = Number(portValue);
36
+ if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) {
37
+ fail('LATTICE_HUB_PORT_INVALID', 'LATTICE_HUB_PORT must be an integer in 1..65535');
38
+ }
39
+
40
+ const allowedHostsValue = env.LATTICE_HUB_ALLOWED_HOSTS ?? '';
41
+ const allowedHosts = new Set(allowedHostsValue.split(',').map((host) => host.trim()).filter((host) => host.length > 0));
42
+ if (allowedHosts.size === 0) {
43
+ fail('LATTICE_HUB_ALLOWED_HOSTS_REQUIRED',
44
+ 'LATTICE_HUB_ALLOWED_HOSTS must list at least one allowed Host (comma-separated), e.g. lattice.kitepon.dev');
45
+ }
46
+
47
+ let hub;
48
+ try {
49
+ hub = await startBridgeHubServer({ port, allowedHosts, listenAddress, env });
50
+ } catch (error) {
51
+ fail(error?.code ?? 'BRIDGE_HUB_START_FAILED', error?.message ?? 'bridge hub server failed to start');
52
+ }
53
+
54
+ process.stdout.write(`${JSON.stringify({
55
+ schema: 'lattice.hub_daemon_started.v1', host: hub.host, port: hub.port,
56
+ allowed_hosts: [...allowedHosts].sort((left, right) => left.localeCompare(right, 'en')),
57
+ })}\n`);
58
+
59
+ let closing = false;
60
+ const close = async () => {
61
+ if (closing) return;
62
+ closing = true;
63
+ await hub.close();
64
+ };
65
+ // systemd sends SIGTERM on stop/restart; ExecStop is unnecessary with this handler.
66
+ process.once('SIGINT', () => close().finally(() => process.exit(0)));
67
+ process.once('SIGTERM', () => close().finally(() => process.exit(0)));
File without changes
File without changes
File without changes
File without changes
package/bin/lattice.mjs CHANGED
File without changes