@quolu/lattice 0.46.2 → 0.48.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.
@@ -4,7 +4,7 @@ import { stat } from 'node:fs/promises';
4
4
  import path from 'node:path';
5
5
 
6
6
  import { readTodoStoreStable } from '../src/todo-store.mjs';
7
- import { projectTodoStatus } from '../src/todo-status.mjs';
7
+ import { TODO_STATUS_DISPATCH_ONLY, projectTodoStatus } from '../src/todo-status.mjs';
8
8
  import { ganttLiveHeadDigest, renderTodoGanttForProject } from '../src/todo-cli.mjs';
9
9
  import {
10
10
  forgetTodoDashboardDaemonRecord,
@@ -61,7 +61,7 @@ async function synchronize() {
61
61
  projectHasActiveRun: async (entry) => {
62
62
  try {
63
63
  const store = await readCachedStore(entry.repo_root);
64
- const active = projectTodoStatus(store).active_set.length > 0
64
+ const active = projectTodoStatus(store, TODO_STATUS_DISPATCH_ONLY).active_set.length > 0
65
65
  || store.members.some(todoDashboardMemberNeedsVisibility);
66
66
  reportedStoreReadFailures.delete(entry.project_id);
67
67
  return active;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quolu/lattice",
3
- "version": "0.46.2",
3
+ "version": "0.48.0",
4
4
  "description": "Schedulability compiler for multi-agent development: observe real code boundaries, refactor the conflicting seam, recompile the plan for parallel execution",
5
5
  "author": {
6
6
  "name": "Quo / クオ at kitepon.dev",
@@ -111,9 +111,6 @@ function inspectArray(value, state, depth) {
111
111
  if (Object.getPrototypeOf(value) !== Array.prototype) {
112
112
  invalidArtifact('array prototypeが不正');
113
113
  }
114
- if (value.length > MAX_COLLECTION_ITEMS) {
115
- invalidArtifact('array item数が上限を超えている');
116
- }
117
114
 
118
115
  const ownKeys = Reflect.ownKeys(value);
119
116
  if (ownKeys.some((key) => typeof key !== 'string')) {
package/src/cli-help.mjs CHANGED
@@ -75,7 +75,7 @@ Read commands:
75
75
 
76
76
  Write commands:
77
77
  dashboard adopt --json # 衝突したproject_idの配信元rootを現在repoへ明示的に移す
78
- note --plan <key> --task <id> (--message <text>|--input <file>)
78
+ note --plan <key> [--task <id>] (--message <text>|--input <file>)
79
79
  # ToDoへ作業継続に必要な方針・調査結果・注意をappend-onlyで追記する
80
80
  migrate --input <extraction.json> [--serialization-reviewed]
81
81
  migrate --input <extraction.json> --dry-run --json [--serialization-reviewed]
@@ -190,7 +190,7 @@ const SUBCOMMAND_USAGE = Object.freeze({
190
190
  'event verify': 'event verify --run .lattice/runs/<id>',
191
191
  'todo status': 'todo status [--json]',
192
192
  'todo show': 'todo show --plan <key> --task <id> --json',
193
- 'todo note': 'todo note --plan <key> --task <id> (--message <text>|--input <file>) | list --plan <key> [--task <id>] --json',
193
+ 'todo note': 'todo note --plan <key> [--task <id>] (--message <text>|--input <file>) | list --plan <key> [--task <id>] --json',
194
194
  'todo note list': 'todo note list --plan <key> [--task <id>] --json',
195
195
  'todo bindings': 'todo bindings [--plan <key>] [--json]',
196
196
  'todo independence': 'todo independence [--plan <key>] [--json] | compile --plan <key> --input <file> | witness migrate --plan <key>',
@@ -16,7 +16,9 @@ import {
16
16
  todoSelfDigest,
17
17
  } from './todo-contracts.mjs';
18
18
  import { projectTodoStatus } from './todo-status.mjs';
19
+ import { readTodoPlanNotesForStatus } from './todo-note-store.mjs';
19
20
  import { projectIndependenceFrontier } from './todo-independence.mjs';
21
+ import { readTodoParallelCandidatesForStatus } from './todo-parallel-candidates.mjs';
20
22
  import { isTodoIndependenceLegacyMarker } from './todo-independence-contracts.mjs';
21
23
  import { selectIndependenceGuidance } from './todo-independence-guidance.mjs';
22
24
  import { ensureTodoDashboardActivity } from './todo-dashboard-registry.mjs';
@@ -179,6 +181,7 @@ async function summarizeIndependence({ repoRoot, store, todo }) {
179
181
  .some(({ unknowns }) => unknowns.some(({ kind }) => kind === 'record_stale')),
180
182
  conflictWithActive: projected.frontier.conflicts_with_active[0]?.severability ?? null,
181
183
  conflictBetweenReady: projected.frontier.serialize_pairs[0]?.severability ?? null,
184
+ coordinationMode: member.coordination?.mode ?? null,
182
185
  }),
183
186
  unreadable_reason: null,
184
187
  parallel_groups: projected.frontier.parallel_groups.map(({ task_ids: ids }) => [...ids]),
@@ -265,7 +268,10 @@ async function resolveProjectState({ cwd, cliVersion }) {
265
268
  }
266
269
  try {
267
270
  const store = await readTodoStore({ repoRoot });
268
- const todo = projectTodoStatus(store);
271
+ const todo = projectTodoStatus(store, {
272
+ planNotes: await readTodoPlanNotesForStatus({ repoRoot, store }),
273
+ parallelCandidates: await readTodoParallelCandidatesForStatus({ repoRoot, store, gitHead }),
274
+ });
269
275
  const activeRuns = todo.active_set.map((entry) => ({
270
276
  plan_key: entry.plan_key, task_id: entry.task_id, label: entry.label,
271
277
  }));
@@ -275,7 +281,17 @@ async function resolveProjectState({ cwd, cliVersion }) {
275
281
  : todo.next_ready.length > 0
276
282
  ? { command: `lattice todo start --plan ${todo.next_ready[0].plan_key} --task ${todo.next_ready[0].task_id}${todo.next_ready.length > 1 ? ' --parallel-frontier' : ''}`,
277
283
  reason: todo.next_ready.length > 1 ? 'parallel_frontier_present' : 'next_ready_present' }
278
- : { command: 'lattice todo status', reason: 'no_ready_task' };
284
+ // 監査待ちが在る限り「残作業なし」と答えない。優先順位はactive_run > next_ready >
285
+ // audit_pending > なしで、ready frontierが在る間はADR 0063の並列開始コマンドが勝つ
286
+ // ——ここを監査で上書きするとdispatchが再直列化する。監査待ちはtodo statusの
287
+ // audit_pending欄に常在するので、順位を下げても消えない。
288
+ // commandはverbatim実行可能で読み取り専用のものにする。`phase review`は
289
+ // `--reason <text>`のplaceholderを含みjournalを書き換えるので置かない
290
+ // (`todo phase status`の結果には既に両分岐のguidanceが載っている)。
291
+ : todo.audit_pending.length > 0
292
+ ? { command: `lattice todo phase status --plan ${todo.audit_pending[0].plan_key}`,
293
+ reason: 'audit_pending' }
294
+ : { command: 'lattice todo status', reason: 'no_ready_task' };
279
295
  const result = statusResult({
280
296
  cli: { available: true, version: cliVersion },
281
297
  project: { root: repoRoot, git_head: gitHead(repoRoot), project_id: store.project_id },
@@ -334,7 +350,7 @@ export async function runSessionContext({ cwd, stdout, cliVersion }) {
334
350
  schema: SESSION_CONTEXT_SCHEMA,
335
351
  // project discoveryの答えをそのまま埋める。hostは既存の検証器を再利用できる。
336
352
  status: state.result,
337
- // todoは`todo_status_result.v4`そのもの。新しい意味論を発明しない。
353
+ // todoは`lattice todo status`のresultそのもの。新しい意味論を発明しない。
338
354
  todo: state.todo,
339
355
  independence,
340
356
  result_digest: '',
@@ -467,31 +467,30 @@ async function runScopeViolation({ scaffold }) {
467
467
  runId, plan, events, packets, todoId: 'TA', detect: detectCheckpointFindings, recordedAt: RUN_TIMESTAMP,
468
468
  });
469
469
  events = classified.events;
470
- const held = decideHoldAndCarryOver({
471
- runId, request, plan, manifests, packets, events, recordedAt: RUN_TIMESTAMP,
472
- });
473
- events = held.events;
470
+ events = await driveToClose({ runId, plan, events, packets, manifests, adapter });
471
+ const state = projectRuntimeState({ events });
474
472
  return {
475
473
  request,
476
474
  plan,
477
475
  manifests,
478
- holdDecision: held.holdDecision,
479
476
  events,
480
477
  record: conditionRecord({
481
478
  condition: 'scope_violation',
482
- // offenderとそのaffected closure(ここではTAのみ)をhold。closure外のTBは
483
- // witnessを実証してcontinueする(plan条件表「offenderとaffected closure hold」)。
479
+ // directory名はRC3 artifact互換のため維持する。現契約では単独の予測超過は
480
+ // conflictではなく、観測を残したまま有効なreceiptを受理する。
484
481
  expected: {
485
- finding_kinds: ['undeclared_write'],
486
- hold_includes_offender: true,
487
- hold: ['TA'],
488
- continue: ['TB'],
482
+ observation_kinds: ['prediction_excess'],
483
+ conflict_finding_kinds: [],
484
+ frozen: false,
485
+ accepted: ['TA', 'TB'],
486
+ closed: true,
489
487
  },
490
488
  actual: {
491
- finding_kinds: [...new Set(classified.findings.map(({ kind }) => kind))],
492
- hold_includes_offender: held.holdDecision.hold_set.includes('TA'),
493
- hold: held.holdDecision.hold_set,
494
- continue: held.holdDecision.continue_set,
489
+ observation_kinds: [...new Set(classified.observations.map(({ kind }) => kind))],
490
+ conflict_finding_kinds: [...new Set(classified.findings.map(({ kind }) => kind))],
491
+ frozen: state.freeze !== null,
492
+ accepted: state.accepted,
493
+ closed: state.closed,
495
494
  },
496
495
  events,
497
496
  plan,
@@ -1334,7 +1333,7 @@ export async function runRc3ScriptedCampaign(options = {}) {
1334
1333
  const clean = await timed('clean_parallel', () => runCleanParallel({ scaffold }));
1335
1334
  const late = await timed('late_path_conflict', () => runLateConflict({ scaffold }));
1336
1335
  // 条件名`scope_violation`はRC3 manifestのdirectory名として凍結されているので動かさない。
1337
- // 中で期待するfinding種別だけが製品に追従して`undeclared_write`になる。
1336
+ // 中では単独の予測超過を観測し、conflictへ昇格しない現契約を検証する。
1338
1337
  const scope = await timed('scope_violation', () => runScopeViolation({ scaffold }));
1339
1338
  const semantic = await timed('semantic_unknown', () => runSemanticUnknown({ scaffold }));
1340
1339
  const stale = await timed('stale_receipt', () => runStaleReceipt({ scaffold }));