@quolu/lattice 0.60.7 → 0.61.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/LICENSE +147 -147
  2. package/README.ja.md +374 -387
  3. package/README.md +291 -291
  4. package/bin/lattice-mcp.mjs +0 -0
  5. package/bin/lattice-scripted-adapter.mjs +0 -0
  6. package/bin/lattice-scripted-worker.mjs +0 -0
  7. package/bin/lattice-work-order-adapter.mjs +0 -0
  8. package/bin/lattice.mjs +0 -1
  9. package/docs/bridge-setup.md +248 -239
  10. package/docs/schemas/lattice.executor_packet.v1.schema.json +57 -57
  11. package/docs/schemas/lattice.executor_receipt.v1.schema.json +66 -66
  12. package/docs/schemas/lattice.phase_todo_revision.v3.schema.json +360 -360
  13. package/docs/schemas/lattice.plan_create_input.v1.schema.json +56 -56
  14. package/docs/schemas/lattice.plan_create_input.v2.schema.json +72 -72
  15. package/docs/schemas/lattice.plan_create_input.v3.schema.json +81 -81
  16. package/docs/schemas/lattice.plan_create_input.v4.schema.json +85 -85
  17. package/docs/schemas/lattice.plan_scope_review.v1.schema.json +55 -55
  18. package/docs/schemas/lattice.run_request.v1.schema.json +238 -238
  19. package/docs/schemas/lattice.runtime_adapter_capabilities.v2.schema.json +55 -55
  20. package/docs/schemas/lattice.runtime_adapter_registration_input.v1.schema.json +78 -78
  21. package/docs/schemas/lattice.runtime_adapter_registration_input.v2.schema.json +86 -86
  22. package/docs/schemas/lattice.todo_extraction.v2.schema.json +298 -298
  23. package/docs/schemas/lattice.todo_extraction.v3.schema.json +150 -150
  24. package/docs/schemas/lattice.todo_extraction.v4.schema.json +161 -161
  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/docs/schemas/lattice.todo_structure_binding.v1.schema.json +47 -47
  28. package/docs/schemas/lattice.todo_structure_realization.v1.schema.json +55 -55
  29. package/docs/schemas/lattice.todo_structure_set.v1.schema.json +264 -264
  30. package/package.json +109 -109
  31. package/sensor/LICENSE +21 -21
  32. package/sensor/NOTICE +19 -19
  33. package/sensor/dist/bin/lattice-sensor.js +9 -9
  34. package/sensor/dist/db/index.js +24 -24
  35. package/sensor/dist/db/migrations.js +41 -41
  36. package/sensor/dist/db/queries.js +164 -164
  37. package/sensor/dist/db/schema.sql +205 -205
  38. package/sensor/dist/directory.js +5 -5
  39. package/sensor/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  40. package/sensor/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  41. package/sensor/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  42. package/sensor/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  43. package/sensor/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  44. package/sensor/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  45. package/sensor/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
  46. package/sensor/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
  47. package/sensor/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
  48. package/sensor/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  49. package/sensor/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  50. package/sensor/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
  51. package/sensor/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
  52. package/sensor/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
  53. package/sensor/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  54. package/sensor/dist/mcp/liveness-watchdog.js +53 -53
  55. package/sensor/dist/mcp/server-instructions.js +95 -95
  56. package/sensor/package.json +56 -56
  57. package/src/cli-help.mjs +5 -4
  58. package/src/project-cli.mjs +2 -5
  59. package/src/runtime-pull-intake.mjs +37 -2
  60. package/src/runtime-windows-process.mjs +44 -0
  61. package/src/todo-cli.mjs +12 -105
  62. package/src/todo-dispatch-shape.mjs +9 -39
package/src/todo-cli.mjs CHANGED
@@ -104,7 +104,6 @@ import {
104
104
  validateTodoExtraction,
105
105
  } from './todo-migration.mjs';
106
106
  import {
107
- assertTodoDispatchShapeReviewed,
108
107
  computeTodoDispatchShapeForPlan,
109
108
  } from './todo-dispatch-shape.mjs';
110
109
  import {
@@ -842,31 +841,8 @@ async function startAdvisory({ repoRoot, store, projection, planKey, taskId }) {
842
841
  };
843
842
  }
844
843
 
845
- // 直列化の理由として認めない定型句。
846
- // worker数・セッション構成・作業者の都合は「並列にできない根拠」ではない。
847
- // 根拠になるのは実際の干渉だけ(同一fileへの書込衝突・外部資源の排他・順序依存)。
848
- // 単一プロセスのagentが「自分は1人だから」と直列へ逃げる事例が実運用で出たため、
849
- // frontierの既定(all_ready_parallel_by_default)を宣言だけでなく機構で守る。
850
- const SERIAL_NON_REASONS = [
851
- /単一(?:の)?(?:セッション|エージェント|worker|ワーカー|プロセス|スレッド)/u,
852
- /(?:逐次|順次|直列|シリアル)(?:実行|処理|化|に|で)/u,
853
- /(?:一人|1人|ひとり|1名|単独)(?:で|の|しか)/u,
854
- /(?:サブ)?エージェント(?:が|は)?(?:居ない|いない|使わない|使えない)/u,
855
- /single[-\s]?(?:session|agent|worker|process|thread)/iu,
856
- /\b(?:sequential|serial)(?:ly)?\s*(?:execution|processing|run|dispatch)?\b/iu,
857
- /one[-\s]at[-\s]a[-\s]time|\bsolo\b|\bby myself\b/iu,
858
- ];
859
-
860
- /**
861
- * 直列化理由が「実際の干渉」を述べているかを検査する。
862
- * worker数・セッション構成を述べただけの理由は根拠にならないので拒否する。
863
- */
864
- function serialReasonNonInterference(reason) {
865
- return SERIAL_NON_REASONS.find((pattern) => pattern.test(reason)) ?? null;
866
- }
867
-
868
844
  async function startTask({
869
- repoRoot, env, planKey, taskId, overrideReason, parallelFrontier, serialConfirmed = false,
845
+ repoRoot, env, planKey, taskId, overrideReason, parallelFrontier,
870
846
  }) {
871
847
  const store = await readTodoStore({ repoRoot });
872
848
  // startはready判定にしかprojectionを使わず、resultを出力しない。
@@ -875,63 +851,11 @@ async function startTask({
875
851
  task.plan_key === planKey && task.task_id.toLowerCase() === taskId.toLowerCase()
876
852
  ));
877
853
  const targetReady = readyTask !== undefined;
854
+ // `--parallel-frontier`は方針の記録口で、対象がreadyでないときにだけ用法誤り。
855
+ // 複数readyのplain startや直列理由の文言審査で着手を止めない(ADR 0180)。
878
856
  if (parallelFrontier && !targetReady) {
879
857
  throw new TodoStoreError('PARALLEL_DISPATCH_INVALID', 'parallel_frontier_not_applicable');
880
858
  }
881
- const frontierContested = targetReady && projection.active_set.length === 0
882
- && projection.next_ready.length > 1;
883
- if (frontierContested && overrideReason === null && !parallelFrontier) {
884
- throw new TodoStoreError('PARALLEL_DISPATCH_REQUIRED', 'parallel_frontier_requires_declaration',
885
- undefined, {
886
- ready_count: projection.next_ready.length,
887
- ready_task_ids: projection.next_ready.map((task) => task.task_id),
888
- frontier_digest: projection.dispatch_frontier.frontier_digest,
889
- parallel_start_flag: projection.dispatch_frontier.parallel_start_flag,
890
- serial_reason_flag: '--override-reason',
891
- default_policy: projection.dispatch_frontier.policy,
892
- guidance: '既定は全ready分の同時dispatch。並列で始めるなら --parallel-frontier を使う。'
893
- + '--override-reason は「なぜ並列にできないか」を書く欄であり、'
894
- + 'worker数・セッション構成・作業者の都合は根拠にならない'
895
- + '(同一fileへの書込衝突・外部資源の排他・順序依存だけが根拠になる)。',
896
- });
897
- }
898
- if (frontierContested && overrideReason !== null) {
899
- if (serialReasonNonInterference(overrideReason) !== null) {
900
- throw new TodoStoreError('PARALLEL_DISPATCH_INVALID', 'serial_reason_is_not_an_interference',
901
- undefined, {
902
- ready_count: projection.next_ready.length,
903
- ready_task_ids: projection.next_ready.map((task) => task.task_id),
904
- rejected_reason: overrideReason,
905
- default_policy: projection.dispatch_frontier.policy,
906
- parallel_start_flag: projection.dispatch_frontier.parallel_start_flag,
907
- guidance: 'worker数・セッション構成・作業者の都合は直列化の根拠にならない。'
908
- + 'readyが複数あるなら既定は同時dispatchであり、実行主体が1つしか無いことは'
909
- + '並列にできない理由ではない(必要ならworkerを増やす)。'
910
- + '直列にするなら、並列で走らせたときに実際に起きる干渉'
911
- + '(同一fileへの書込衝突・外部資源の排他・順序依存)を書く。',
912
- });
913
- }
914
- // 直列の申告は一度突き返して並列を再検討させる。
915
- // 規則を書くだけでは読み飛ばされるため、再考をコマンドの往復で強制する。
916
- if (!serialConfirmed) {
917
- throw new TodoStoreError('PARALLEL_DISPATCH_RECONSIDER', 'consider_parallel_before_serial',
918
- undefined, {
919
- ready_count: projection.next_ready.length,
920
- ready_task_ids: projection.next_ready.map((task) => task.task_id),
921
- declared_reason: overrideReason,
922
- default_policy: projection.dispatch_frontier.policy,
923
- parallel_start_flag: projection.dispatch_frontier.parallel_start_flag,
924
- serial_confirm_flag: '--serial-confirmed',
925
- guidance: `並列を検討しなさい。ready ${projection.next_ready.length} 件は同時に着手できる`
926
- + '前提で並んでおり、既定は全件同時dispatchである。'
927
- + `まず ${projection.dispatch_frontier.parallel_start_flag} で全readyを起こし、`
928
- + 'それぞれ別のworkerへ渡すことを検討する'
929
- + '(実行主体が足りないなら増やす。増やせないことは並列にできない理由ではない)。'
930
- + '検討した上でなお直列にするなら、同じ --override-reason に'
931
- + ' --serial-confirmed を付けて再実行する。',
932
- });
933
- }
934
- }
935
859
  const member = store.members.find(({ descriptor }) => descriptor.plan_key === planKey);
936
860
  if (member === undefined) throw new TodoStoreError('STORE_INCONSISTENT', 'plan_not_active');
937
861
  const taskMatches = member.plan.tasks.filter(({ task_id: candidate }) => (
@@ -1244,13 +1168,11 @@ async function phaseBaseline({ repoRoot, env, reason, exceptPlanKeys }) {
1244
1168
  return result;
1245
1169
  }
1246
1170
 
1247
- async function migrate({ repoRoot, inputRef, serializationReviewed = false }) {
1171
+ async function migrate({ repoRoot, inputRef }) {
1248
1172
  const extraction = await readMigrationInput(repoRoot, inputRef);
1249
- // dispatch_shapeのgateはappendTodoExtraction(store書込み)より前に判定する必要がある
1250
- // (拒否時にstoreへ何も書かないため、再考後の再実行がplan_key_already_existsで
1251
- // 詰まらない)。unresolved/空集合の2つの早期gateは、compileTodoExtraction内部の
1252
- // 同名gateをここでも先に通しておくことで、既存のエラー優先順位
1253
- // (unresolved・空集合を直列度より先に報告する)を変えない。
1173
+ // unresolved/空集合の早期gateは、compileTodoExtraction内部の同名gateをここでも
1174
+ // 先に通しておくことで、既存のエラー優先順位を変えない。
1175
+ // dispatch_shapeは結果へ載せる観測であり、直列度では書込みを拒まない(ADR 0180)。
1254
1176
  const unresolvedTaskIds = extraction.tasks
1255
1177
  .filter(({ disposition }) => disposition === 'unknown_requires_evidence')
1256
1178
  .map(({ task_id: taskId }) => taskId);
@@ -1272,9 +1194,6 @@ async function migrate({ repoRoot, inputRef, serializationReviewed = false }) {
1272
1194
  hardDependencies: extraction.hard_dependencies,
1273
1195
  joins: extraction.joins,
1274
1196
  });
1275
- if (dispatchShape !== null) {
1276
- assertTodoDispatchShapeReviewed({ shape: dispatchShape, reviewed: serializationReviewed });
1277
- }
1278
1197
 
1279
1198
  const imported = await appendTodoExtraction({ repoRoot, extraction });
1280
1199
  let companion = null;
@@ -1448,7 +1367,7 @@ function extractionAuthoringViolations(extraction, now = new Date()) {
1448
1367
  return violations;
1449
1368
  }
1450
1369
 
1451
- async function migrateDryRun({ repoRoot, inputRef, serializationReviewed = false }) {
1370
+ async function migrateDryRun({ repoRoot, inputRef }) {
1452
1371
  const extraction = await readMigrationInput(repoRoot, inputRef, { requireValid: false });
1453
1372
  const violations = [];
1454
1373
  const tasks = Array.isArray(extraction?.tasks) ? extraction.tasks : [];
@@ -1521,13 +1440,6 @@ async function migrateDryRun({ repoRoot, inputRef, serializationReviewed = false
1521
1440
  taskIds: registered.map(({ task_id: taskId }) => taskId),
1522
1441
  hardDependencies: extraction.hard_dependencies, joins: extraction.joins,
1523
1442
  });
1524
- try {
1525
- assertTodoDispatchShapeReviewed({ shape: dispatchShape, reviewed: serializationReviewed });
1526
- } catch (error) {
1527
- violations.push({ code: error?.detail?.reason ?? 'plan_shape_too_serial', path: '/hard_dependencies',
1528
- task_ids: error?.detail?.critical_path_task_ids ?? [],
1529
- next_action: 'reconsider_parallel_seams_or_pass_serialization_reviewed' });
1530
- }
1531
1443
  }
1532
1444
  } catch (error) {
1533
1445
  plannedPlan = null;
@@ -1586,7 +1498,7 @@ async function migrateDryRun({ repoRoot, inputRef, serializationReviewed = false
1586
1498
  },
1587
1499
  },
1588
1500
  next_action: bounded.length === 0
1589
- ? `lattice todo migrate --input ${inputRef}${serializationReviewed ? ' --serialization-reviewed' : ''}`
1501
+ ? `lattice todo migrate --input ${inputRef}`
1590
1502
  : 'correct_all_reported_violations_and_rerun_dry_run',
1591
1503
  result_digest: '',
1592
1504
  };
@@ -3916,17 +3828,13 @@ export async function runTodoCli({ argv, cwd, stdout, stderr, env = process.env
3916
3828
  && argv[1] === '--input' && isTodoRef(argv[2])
3917
3829
  && argv[3] === '--dry-run' && argv[4] === '--json'
3918
3830
  && (argv.length === 5 || argv[5] === '--serialization-reviewed')) {
3919
- action = (repoRoot) => migrateDryRun({
3920
- repoRoot, inputRef: argv[2], serializationReviewed: argv.length === 6,
3921
- });
3831
+ action = (repoRoot) => migrateDryRun({ repoRoot, inputRef: argv[2] });
3922
3832
  } else if ((argv.length === 3 || argv.length === 4 || argv.length === 5)
3923
3833
  && argv[0] === 'migrate' && argv[1] === '--input' && isTodoRef(argv[2])
3924
3834
  && (argv.length === 3
3925
3835
  || (argv.length === 4 && ['--json', '--serialization-reviewed'].includes(argv[3]))
3926
3836
  || (argv.length === 5 && argv[3] === '--serialization-reviewed' && argv[4] === '--json'))) {
3927
- action = (repoRoot) => migrate({
3928
- repoRoot, inputRef: argv[2], serializationReviewed: argv[3] === '--serialization-reviewed',
3929
- });
3837
+ action = (repoRoot) => migrate({ repoRoot, inputRef: argv[2] });
3930
3838
  } else if (argv.length === 5 && argv[0] === 'revise'
3931
3839
  && argv[1] === '--plan' && isTodoIdentifier(argv[2])
3932
3840
  && argv[3] === '--input' && isTodoRef(argv[4])) {
@@ -3986,8 +3894,7 @@ export async function runTodoCli({ argv, cwd, stdout, stderr, env = process.env
3986
3894
  && (argv.length === 7 || argv[7] === '--serial-confirmed')))) {
3987
3895
  const overrideReason = argv.length >= 7 ? argv[6] : null;
3988
3896
  action = (repoRoot) => startTask({ repoRoot, env, planKey: argv[2], taskId: argv[4],
3989
- overrideReason, parallelFrontier: argv.length === 6,
3990
- serialConfirmed: argv.length === 8 });
3897
+ overrideReason, parallelFrontier: argv.length === 6 });
3991
3898
  } else if (argv.length === 7 && argv[0] === 'retract'
3992
3899
  && argv[1] === '--plan' && isTodoIdentifier(argv[2])
3993
3900
  && argv[3] === '--task' && isTodoIdentifier(argv[4])
@@ -1,26 +1,24 @@
1
1
  import { TodoStoreError } from './todo-store.mjs';
2
2
 
3
3
  /**
4
- * 依存グラフの「直列度」を判定する既定閾値。
4
+ * 依存グラフの「直列度」を分類する既定閾値。
5
5
  *
6
6
  * `serialization_ratio = critical_path_length / task_count` がこれを超えると、
7
7
  * 依存連鎖が全task数の半分を超えて連なっている=大半のtaskが並列候補ではなく
8
- * 一本の鎖に押し込まれていることを意味する。`todo start`側が既に持つ
9
- * `all_ready_parallel_by_default`方針をplan作成時点まで前倒しする出発点として
10
- * 0.5を採る。実測(parent-child-repair: task 26, critical path約20,
11
- * ratio≈0.77)を確実に超える一方、緩やかな分岐を持つ通常のplanまでは拾わない
12
- * 水準として選んだ。
8
+ * 一本の鎖に押し込まれていることを意味する。結果の`dispatch_shape`がこの事実を
9
+ * 載せる。拒否には使わない(ADR 0180)。
10
+ * 実測(parent-child-repair: task 26, critical path約20, ratio≈0.77)を確実に
11
+ * 超える一方、緩やかな分岐を持つ通常のplanまでは拾わない水準として選んだ。
13
12
  */
14
13
  export const DISPATCH_SHAPE_SERIALIZATION_THRESHOLD = 0.5;
15
14
 
16
15
  /**
17
- * 閾値判定の対象にする最小task数。
18
- * 3〜5 task程度の一直線planを毎回突き返しても再考の余地がなく
19
- * (並列化する意味のある規模でない)機構がノイズになるだけなので、
20
- * 6 task未満は常に素通りさせる。
16
+ * 直列度分類の対象にする最小task数。
17
+ * 3〜5 task程度の一直線は並列化する意味のある規模でないので、excessiveとはしない。
21
18
  */
22
19
  export const DISPATCH_SHAPE_MIN_TASK_COUNT_FOR_GATE = 6;
23
20
 
21
+ /** 互換のため受理するだけのflag名。門には使わない(ADR 0180)。 */
24
22
  export const DISPATCH_SHAPE_SERIALIZATION_REVIEWED_FLAG = '--serialization-reviewed';
25
23
 
26
24
  function compareText(left, right) {
@@ -128,40 +126,12 @@ export function computeTodoDispatchShape({ taskIds, edges }) {
128
126
  };
129
127
  }
130
128
 
131
- /** dispatch_shapeが、再考なしで直列のまま通してよい規模・度合いかを判定する。 */
129
+ /** dispatch_shapeが、観測上「直列に寄っている」規模・度合いかを分類する。拒否には使わない。 */
132
130
  export function isTodoDispatchShapeSerializationExcessive(shape) {
133
131
  return shape.task_count >= DISPATCH_SHAPE_MIN_TASK_COUNT_FOR_GATE
134
132
  && Number(shape.serialization_ratio) > DISPATCH_SHAPE_SERIALIZATION_THRESHOLD;
135
133
  }
136
134
 
137
- /**
138
- * dispatch_shapeが直列に寄りすぎているplanを、再考なしでは通さない。
139
- *
140
- * `todo start`の`PARALLEL_DISPATCH_RECONSIDER`と同じ二段階(一度突き返し、
141
- * 再考を経たflagが無ければ通さない)をplan作成時点へ前倒しする。ここで
142
- * 拒否する場合、呼び出し側はまだstoreへ何も書いていないこと(初期化/追加を
143
- * この呼び出しより後で行うこと)。
144
- */
145
- export function assertTodoDispatchShapeReviewed({ shape, reviewed }) {
146
- if (!isTodoDispatchShapeSerializationExcessive(shape) || reviewed) return;
147
- throw new TodoStoreError('PARALLEL_DISPATCH_RECONSIDER', 'plan_shape_too_serial', undefined, {
148
- task_count: shape.task_count,
149
- critical_path_length: shape.critical_path_length,
150
- max_frontier_width: shape.max_frontier_width,
151
- serialization_ratio: shape.serialization_ratio,
152
- critical_path_task_ids: shape.critical_path_task_ids,
153
- default_policy: 'all_ready_parallel_by_default',
154
- serialization_reviewed_flag: DISPATCH_SHAPE_SERIALIZATION_REVIEWED_FLAG,
155
- guidance: `並列を検討しなさい。task ${shape.task_count}件のうちcritical pathが`
156
- + `${shape.critical_path_length}段(serialization_ratio ${shape.serialization_ratio})で、`
157
- + '大半のtaskが並列候補ではなく一本の依存鎖に押し込まれている。'
158
- + 'critical_path_task_idsに沿った依存のうち、実際には干渉しない組を'
159
- + 'hard_dependencies/joinsから外せないか見直す'
160
- + '(実行主体が足りないなら増やす。増やせないことは直列化の理由にならない)。'
161
- + `検討した上でなお直列でよいなら ${DISPATCH_SHAPE_SERIALIZATION_REVIEWED_FLAG} を付けて再実行する。`,
162
- });
163
- }
164
-
165
135
  /**
166
136
  * plan/extractionの`tasks`・`hard_dependencies`・`joins`(nodeRef形式)から、
167
137
  * 「このproject_id/plan_keyの内側だけ」に絞ったdispatch形状を計算する高レベル入口。