@quolu/lattice 0.67.3 → 0.67.4
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 +1 -1
- package/src/todo-cli.mjs +3 -1
- package/src/todo-store.mjs +16 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quolu/lattice",
|
|
3
|
-
"version": "0.67.
|
|
3
|
+
"version": "0.67.4",
|
|
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",
|
package/src/todo-cli.mjs
CHANGED
|
@@ -1052,7 +1052,8 @@ async function dependencyConnect({
|
|
|
1052
1052
|
async function dependencyDisconnect({
|
|
1053
1053
|
repoRoot, env, fromPlanKey, fromTaskId, toPlanKey, toTaskId, reason,
|
|
1054
1054
|
}) {
|
|
1055
|
-
|
|
1055
|
+
// 修理扉: 越境依存の固定digestが陳腐化した store でも disconnect だけは通す(todo-store.mjs 参照)
|
|
1056
|
+
const store = await readTodoStore({ repoRoot, tolerateStaleBindings: true });
|
|
1056
1057
|
const live = projectTodoCrossPlanDependencies(store.members).filter((dependency) => (
|
|
1057
1058
|
dependency.from.plan_key === fromPlanKey && dependency.from.task_id === fromTaskId
|
|
1058
1059
|
&& dependency.to.plan_key === toPlanKey && dependency.to.task_id === toTaskId
|
|
@@ -1068,6 +1069,7 @@ async function dependencyDisconnect({
|
|
|
1068
1069
|
.some((event) => event.event_digest === target.event_digest));
|
|
1069
1070
|
const { event } = await appendTodoEvent({
|
|
1070
1071
|
repoRoot, writer: createTodoStoreWriter({ caller: 'g5-authoring' }), planKey: owner.plan.plan_key,
|
|
1072
|
+
tolerateStaleBindings: true,
|
|
1071
1073
|
event: {
|
|
1072
1074
|
kind: 'cross_plan_dependency_removed', actor: mutationActor(env),
|
|
1073
1075
|
payload: { target_event_digest: target.event_digest, reason },
|
package/src/todo-store.mjs
CHANGED
|
@@ -879,7 +879,13 @@ function snapshotFor(plan, events, tasks) {
|
|
|
879
879
|
return snapshot;
|
|
880
880
|
}
|
|
881
881
|
|
|
882
|
-
function validateMergedGraph(members, crossPlanDependencies = []) {
|
|
882
|
+
function validateMergedGraph(members, crossPlanDependencies = [], options = {}) {
|
|
883
|
+
// tolerateStaleBindings は dependency disconnect 専用の修理扉。plan revise が越境依存の
|
|
884
|
+
// 固定digestを陳腐化させると、通常loadは binding_stale で fail closed するが、その修理
|
|
885
|
+
// コマンド自身も load を要するため、扉が無いと修理経路が存在しない(実被弾 2026-08-29:
|
|
886
|
+
// evidence-2 改訂で store 全体が読めなくなり、disconnect も同エラーで詰んだ)。
|
|
887
|
+
// 許容するのは digest 不一致だけで、dangling / missing は修理扉でも fail する。
|
|
888
|
+
const tolerateStale = options.tolerateStaleBindings === true;
|
|
883
889
|
const tasks = new Map();
|
|
884
890
|
for (const member of members) for (const task of member.plan.tasks) {
|
|
885
891
|
tasks.set(`${member.plan.project_id}\0${member.plan.plan_key}\0${task.task_id}`, member.plan.topology_digest);
|
|
@@ -900,7 +906,7 @@ function validateMergedGraph(members, crossPlanDependencies = []) {
|
|
|
900
906
|
if (topology === undefined) fail('STORE_INCONSISTENT', 'dangling_dependency');
|
|
901
907
|
if ((ref.project_id !== ownerPlan.project_id || ref.plan_key !== ownerPlan.plan_key)
|
|
902
908
|
&& ref.expected_topology_digest === undefined) fail('STORE_INCONSISTENT', 'cross_plan_binding_missing');
|
|
903
|
-
if (ref.expected_topology_digest !== undefined && topology !== ref.expected_topology_digest) {
|
|
909
|
+
if (!tolerateStale && ref.expected_topology_digest !== undefined && topology !== ref.expected_topology_digest) {
|
|
904
910
|
fail('STORE_INCONSISTENT', 'binding_stale');
|
|
905
911
|
}
|
|
906
912
|
return key;
|
|
@@ -911,7 +917,7 @@ function validateMergedGraph(members, crossPlanDependencies = []) {
|
|
|
911
917
|
if (topology === undefined) fail('STORE_INCONSISTENT', 'dangling_phase_dependency');
|
|
912
918
|
if ((ref.project_id !== ownerPlan.project_id || ref.plan_key !== ownerPlan.plan_key)
|
|
913
919
|
&& ref.expected_topology_digest === undefined) fail('STORE_INCONSISTENT', 'cross_plan_binding_missing');
|
|
914
|
-
if (ref.expected_topology_digest !== undefined && topology !== ref.expected_topology_digest) {
|
|
920
|
+
if (!tolerateStale && ref.expected_topology_digest !== undefined && topology !== ref.expected_topology_digest) {
|
|
915
921
|
fail('STORE_INCONSISTENT', 'binding_stale');
|
|
916
922
|
}
|
|
917
923
|
return key;
|
|
@@ -1629,7 +1635,9 @@ export async function readTodoStore(options = {}) {
|
|
|
1629
1635
|
snapshot: snapshotStale ? expectedSnapshot : snapshot,
|
|
1630
1636
|
tasks, phases, coordination, snapshot_stale: snapshotStale });
|
|
1631
1637
|
}
|
|
1632
|
-
validateMergedGraph(loaded, projectTodoCrossPlanDependencies(loaded)
|
|
1638
|
+
validateMergedGraph(loaded, projectTodoCrossPlanDependencies(loaded), {
|
|
1639
|
+
tolerateStaleBindings: options.tolerateStaleBindings === true,
|
|
1640
|
+
});
|
|
1633
1641
|
return {
|
|
1634
1642
|
schema: 'lattice.todo_store_read.v1', project_id: manifest.project_id, manifest,
|
|
1635
1643
|
members: loaded, snapshot_stale: loaded.some((member) => member.snapshot_stale),
|
|
@@ -2036,6 +2044,10 @@ export async function appendTodoEvent(options = {}) {
|
|
|
2036
2044
|
const store = await readTodoStore({
|
|
2037
2045
|
repoRoot, forWrite: true, now: options.now, evidenceRepair,
|
|
2038
2046
|
evidenceRepairCapability: EVIDENCE_REPAIR_CAPABILITY,
|
|
2047
|
+
// 修理扉は除去event(tombstone)の書込みだけに開く。それ以外の書込みは従来どおり
|
|
2048
|
+
// binding_stale で fail closed する(validateMergedGraph の注記を参照)
|
|
2049
|
+
tolerateStaleBindings: options.tolerateStaleBindings === true
|
|
2050
|
+
&& options.event.kind === 'cross_plan_dependency_removed',
|
|
2039
2051
|
});
|
|
2040
2052
|
const member = store.members.find(({ descriptor }) => descriptor.plan_key === options.planKey);
|
|
2041
2053
|
if (!member) fail('STORE_INCONSISTENT', 'plan_not_active');
|