@quolu/lattice 0.57.2 → 0.57.3

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quolu/lattice",
3
- "version": "0.57.2",
3
+ "version": "0.57.3",
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",
@@ -681,8 +681,10 @@ export async function intakePullTask({ repoRoot, runDir, taskId, environment = p
681
681
  affected_tests: [], graph_evidence: [], witness_provenance: {}, manifest_digest: '',
682
682
  };
683
683
  manifest.manifest_digest = selfDigest(manifest, 'manifest_digest');
684
- verdict.state = 'hold'; verdict.reason = 'boundary_unverified';
685
- verdict.next_action = 'declare_and_recompile'; verdict.detail = { cause: error.code };
684
+ if (verdict.state !== 'hold') {
685
+ verdict.state = 'hold'; verdict.reason = 'boundary_unverified';
686
+ verdict.next_action = 'declare_and_recompile'; verdict.detail = { cause: error.code };
687
+ }
686
688
  }
687
689
  const constraint = verdict.state === 'none'
688
690
  ? planningConstraint(verdict.artifact, taskId, state, member) : null;
@@ -760,8 +762,10 @@ export async function intakePullTask({ repoRoot, runDir, taskId, environment = p
760
762
  affected_tests: [], graph_evidence: [], witness_provenance: {}, manifest_digest: '',
761
763
  };
762
764
  manifest.manifest_digest = selfDigest(manifest, 'manifest_digest');
763
- verdict.state = 'hold'; verdict.reason = 'boundary_unverified';
764
- verdict.next_action = 'declare_and_recompile'; verdict.detail = { cause: error.code };
765
+ if (verdict.state !== 'hold') {
766
+ verdict.state = 'hold'; verdict.reason = 'boundary_unverified';
767
+ verdict.next_action = 'declare_and_recompile'; verdict.detail = { cause: error.code };
768
+ }
765
769
  }
766
770
  const packet = packetFor({ meta: current.meta, taskId, baseSha, manifest });
767
771
  const worktreePath = await ensureScriptedWorktree({ repoRoot, runDir, packet });
package/src/todo-cli.mjs CHANGED
@@ -1759,6 +1759,9 @@ async function independenceCompile({ repoRoot, planKey, inputRef }) {
1759
1759
  previousArtifact,
1760
1760
  });
1761
1761
  const { ref } = await writeTodoIndependenceArtifact({ repoRoot, artifact });
1762
+ // compile成功後にだけ、受理した宣言をruntime readerが要求するcanonical bytesで固定する。
1763
+ // inputがstore自身でも外部draftでも、唯一の正規writerを通して同じ契約へ収束させる。
1764
+ await writeTodoWitnessSet({ repoRoot, witnessSet });
1762
1765
 
1763
1766
  const result = {
1764
1767
  schema: 'lattice.todo_independence_compile_result.v2',
@@ -2286,8 +2286,19 @@ function localTaskRef(ref, plan, taskId) {
2286
2286
  && ref.task_id === taskId;
2287
2287
  }
2288
2288
 
2289
+ function removedTaskIdsFor(revision) {
2290
+ return new Set(revision.task_migration
2291
+ .filter(({ to_task_id, state_policy }) => to_task_id === 'removed' && state_policy === 'removed')
2292
+ .map(({ from_task_id }) => from_task_id));
2293
+ }
2294
+
2295
+ function removedTaskRef(ref, plan, removedTaskIds) {
2296
+ return ref.project_id === plan.project_id && ref.plan_key === plan.plan_key
2297
+ && removedTaskIds.has(ref.task_id);
2298
+ }
2299
+
2289
2300
  function taskSemantics(plan, taskId, idMap, {
2290
- reconciliationMetadata = false, includeDesignMemo = false,
2301
+ reconciliationMetadata = false, includeDesignMemo = false, removedTaskIds = new Set(),
2291
2302
  } = {}) {
2292
2303
  const task = plan.tasks.find(({ task_id }) => task_id === taskId);
2293
2304
  if (!task) return null;
@@ -2302,17 +2313,23 @@ function taskSemantics(plan, taskId, idMap, {
2302
2313
  compile_binding: task.compile_binding, parent_task_id: mapId(task.parent_task_id ?? null),
2303
2314
  };
2304
2315
  const edges = plan.hard_dependencies
2305
- .filter(({ from, to }) => localTaskRef(from, plan, taskId) || localTaskRef(to, plan, taskId))
2316
+ .filter(({ from, to }) => !removedTaskRef(from, plan, removedTaskIds)
2317
+ && !removedTaskRef(to, plan, removedTaskIds)
2318
+ && (localTaskRef(from, plan, taskId) || localTaskRef(to, plan, taskId)))
2306
2319
  .map(({ from, to }) => ({ from: mappedNodeRef(from, plan, idMap), to: mappedNodeRef(to, plan, idMap) }))
2307
2320
  .sort((left, right) => canonicalizeTodoArtifact(left) < canonicalizeTodoArtifact(right) ? -1 : 1);
2308
2321
  const joins = plan.joins
2309
- .filter(({ after, before }) => localTaskRef(before, plan, taskId)
2310
- || after.some((ref) => localTaskRef(ref, plan, taskId)))
2311
- .map((join) => ({ ...join,
2312
- after: join.after.map((ref) => mappedNodeRef(ref, plan, idMap))
2322
+ .flatMap((join) => {
2323
+ if (removedTaskRef(join.before, plan, removedTaskIds)) return [];
2324
+ const after = join.after.filter((ref) => !removedTaskRef(ref, plan, removedTaskIds));
2325
+ if (after.length === 0 || (!localTaskRef(join.before, plan, taskId)
2326
+ && !after.some((ref) => localTaskRef(ref, plan, taskId)))) return [];
2327
+ return [{ ...join,
2328
+ after: after.map((ref) => mappedNodeRef(ref, plan, idMap))
2313
2329
  .sort((left, right) => canonicalizeTodoArtifact(left) < canonicalizeTodoArtifact(right) ? -1 : 1),
2314
- before: mappedNodeRef(join.before, plan, idMap),
2315
- })).sort((left, right) => left.id < right.id ? -1 : 1);
2330
+ before: mappedNodeRef(join.before, plan, idMap),
2331
+ }];
2332
+ }).sort((left, right) => left.id < right.id ? -1 : 1);
2316
2333
  const phaseAcceptDependencies = isDecoupledPhaseTodoPlanSchema(plan.schema)
2317
2334
  ? plan.phase_accept_dependencies
2318
2335
  .filter(({ to }) => localTaskRef(to, plan, taskId))
@@ -2323,7 +2340,7 @@ function taskSemantics(plan, taskId, idMap, {
2323
2340
  }
2324
2341
 
2325
2342
  function phaseV3CarrySemantics(plan, taskId, taskIdMap, phaseIdMap,
2326
- { reconciliationMetadata = false, includeDesignMemo = false } = {}) {
2343
+ { reconciliationMetadata = false, includeDesignMemo = false, removedTaskIds = new Set() } = {}) {
2327
2344
  const task = plan.tasks.find(({ task_id: id }) => id === taskId);
2328
2345
  if (task === undefined) return null;
2329
2346
  const mapTaskRef = (ref) => ref.project_id === plan.project_id && ref.plan_key === plan.plan_key
@@ -2351,13 +2368,17 @@ function phaseV3CarrySemantics(plan, taskId, taskIdMap, phaseIdMap,
2351
2368
  const incoming = [];
2352
2369
  const outgoing = [];
2353
2370
  for (const edge of plan.hard_dependencies) {
2371
+ if (removedTaskRef(edge.from, plan, removedTaskIds)
2372
+ || removedTaskRef(edge.to, plan, removedTaskIds)) continue;
2354
2373
  const mapped = { kind: 'hard', from: mapTaskRef(edge.from), to: mapTaskRef(edge.to) };
2355
2374
  if (localTaskRef(edge.to, plan, taskId)) incoming.push(mapped);
2356
2375
  if (localTaskRef(edge.from, plan, taskId)) outgoing.push(mapped);
2357
2376
  }
2358
2377
  for (const join of plan.joins) {
2378
+ if (removedTaskRef(join.before, plan, removedTaskIds)) continue;
2359
2379
  const to = mapTaskRef(join.before);
2360
2380
  for (const after of join.after) {
2381
+ if (removedTaskRef(after, plan, removedTaskIds)) continue;
2361
2382
  const tuple = { kind: 'join', join_id: join.id, from: mapTaskRef(after), to };
2362
2383
  if (localTaskRef(join.before, plan, taskId)) incoming.push(tuple);
2363
2384
  if (localTaskRef(after, plan, taskId)) outgoing.push(tuple);
@@ -2375,11 +2396,12 @@ function validatePhaseV3Carry(previous, revision, migration, idMap, state) {
2375
2396
  const reconciliationMetadata = migration.state_policy === 'carry_reconciled_metadata';
2376
2397
  const predecessorTask = previous.plan.tasks.find(({ task_id }) => task_id === migration.from_task_id);
2377
2398
  const includeDesignMemo = !reconciliationMetadata && typeof predecessorTask?.design_memo === 'string';
2399
+ const removedTaskIds = removedTaskIdsFor(revision);
2378
2400
  const phaseIdMap = new Map(revision.phase_migration
2379
2401
  .filter(({ from_phase_id, to_phase_id }) => from_phase_id !== null && to_phase_id !== 'removed')
2380
2402
  .map(({ from_phase_id, to_phase_id }) => [from_phase_id, to_phase_id]));
2381
2403
  const before = phaseV3CarrySemantics(previous.plan, migration.from_task_id, idMap, phaseIdMap,
2382
- { reconciliationMetadata, includeDesignMemo });
2404
+ { reconciliationMetadata, includeDesignMemo, removedTaskIds });
2383
2405
  const after = phaseV3CarrySemantics(revision.desired_plan, migration.to_task_id,
2384
2406
  new Map(), new Map(),
2385
2407
  { reconciliationMetadata, includeDesignMemo });
@@ -2412,8 +2434,9 @@ function validateAcquirePhaseCarry(previous, revision, migration, idMap) {
2412
2434
  .map(({ from_phase_id, to_phase_id }) => [from_phase_id, to_phase_id]));
2413
2435
  const predecessorTask = previous.plan.tasks.find(({ task_id }) => task_id === migration.from_task_id);
2414
2436
  const includeDesignMemo = typeof predecessorTask?.design_memo === 'string';
2437
+ const removedTaskIds = removedTaskIdsFor(revision);
2415
2438
  const before = phaseV3CarrySemantics(previous.plan, migration.from_task_id, idMap, phaseIdMap,
2416
- { includeDesignMemo });
2439
+ { includeDesignMemo, removedTaskIds });
2417
2440
  const after = phaseV3CarrySemantics(revision.desired_plan, migration.to_task_id, new Map(), new Map(),
2418
2441
  { includeDesignMemo });
2419
2442
  if (before.task.phase_id !== null) {
@@ -2448,6 +2471,7 @@ function stateMigrationFor(previous, revision) {
2448
2471
  const idMap = new Map(revision.task_migration
2449
2472
  .filter(({ to_task_id }) => to_task_id !== 'removed')
2450
2473
  .map(({ from_task_id, to_task_id }) => [from_task_id, to_task_id]));
2474
+ const removedTaskIds = removedTaskIdsFor(revision);
2451
2475
  const states = new Map(previous.tasks.map((state) => [state.task_id, state]));
2452
2476
  return revision.task_migration.map((migration) => {
2453
2477
  const carriesState = ['carry', 'carry_reconciled_metadata', 'acquire_phase'].includes(migration.state_policy);
@@ -2467,7 +2491,7 @@ function stateMigrationFor(previous, revision) {
2467
2491
  .find(({ task_id }) => task_id === migration.from_task_id);
2468
2492
  const includeDesignMemo = typeof predecessorTask?.design_memo === 'string';
2469
2493
  const before = taskSemantics(previous.plan, migration.from_task_id, idMap,
2470
- { includeDesignMemo });
2494
+ { includeDesignMemo, removedTaskIds });
2471
2495
  const after = taskSemantics(revision.desired_plan, migration.to_task_id, new Map(),
2472
2496
  { includeDesignMemo });
2473
2497
  if (canonicalizeTodoArtifact(before) !== canonicalizeTodoArtifact(after)) {
@@ -2482,7 +2506,7 @@ function stateMigrationFor(previous, revision) {
2482
2506
  const includeDesignMemo = !reconciliationMetadata
2483
2507
  && typeof predecessorTask?.design_memo === 'string';
2484
2508
  const before = taskSemantics(previous.plan, migration.from_task_id, idMap,
2485
- { reconciliationMetadata, includeDesignMemo });
2509
+ { reconciliationMetadata, includeDesignMemo, removedTaskIds });
2486
2510
  const after = taskSemantics(revision.desired_plan, migration.to_task_id, new Map(),
2487
2511
  { reconciliationMetadata, includeDesignMemo });
2488
2512
  if (canonicalizeTodoArtifact(before) !== canonicalizeTodoArtifact(after)) {