@quolu/lattice 0.25.0 → 0.26.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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quolu/lattice",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Lattice — phase-aware TODO graph compiler and conflict-aware orchestration runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,10 +59,8 @@
|
|
|
59
59
|
"prepublishOnly": "npm run verify:release-commit",
|
|
60
60
|
"test": "node scripts/run-product-tests.mjs",
|
|
61
61
|
"test:sensor": "npm --prefix sensor test",
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"check:project-identity": "node --check src/project-identity.mjs",
|
|
65
|
-
"ci": "npm run test && npm run test:sensor && npm run check && npm run check:project-identity && npm run verify:todo-store",
|
|
62
|
+
"check": "node scripts/check-syntax.mjs",
|
|
63
|
+
"ci": "npm run test && npm run test:sensor && npm run check && npm run verify:todo-store",
|
|
66
64
|
"verify:todo-store": "node bin/lattice.mjs todo verify --json"
|
|
67
65
|
}
|
|
68
66
|
}
|
|
@@ -65,6 +65,7 @@ function sha16(value) {
|
|
|
65
65
|
|
|
66
66
|
const WITNESS_KINDS = Object.freeze(['state', 'schema', 'invariant', 'effect', 'external_effect']);
|
|
67
67
|
const HEX_DIGEST = /^[0-9a-f]{64}$/u;
|
|
68
|
+
const HEX_SHA1 = /^[0-9a-f]{40}$/u;
|
|
68
69
|
const IDENTIFIER = /^[0-9A-Za-z](?:[0-9A-Za-z._-]{0,127})$/u;
|
|
69
70
|
const compareText = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
70
71
|
|
|
@@ -620,12 +621,19 @@ export function recompileNextEpochPlan(options = {}) {
|
|
|
620
621
|
if (!exactRecord(options, [
|
|
621
622
|
'runId', 'request', 'plan', 'manifests', 'packets', 'events', 'holdDecision',
|
|
622
623
|
'additionalConflicts', 'recordedAt',
|
|
624
|
+
]) && !exactRecord(options, [
|
|
625
|
+
'runId', 'request', 'plan', 'manifests', 'packets', 'events', 'holdDecision',
|
|
626
|
+
'additionalConflicts', 'recordedAt', 'successorBaseSha',
|
|
623
627
|
])) {
|
|
624
628
|
fail('recompileNextEpochPlan optionsがexact shapeでない');
|
|
625
629
|
}
|
|
626
630
|
const {
|
|
627
631
|
runId, request, plan, manifests, packets, events, holdDecision, additionalConflicts, recordedAt,
|
|
632
|
+
successorBaseSha = null,
|
|
628
633
|
} = options;
|
|
634
|
+
if (successorBaseSha !== null && !HEX_SHA1.test(successorBaseSha)) {
|
|
635
|
+
fail('successorBaseShaがgit shaでない');
|
|
636
|
+
}
|
|
629
637
|
if (!validateRuntimePlan(plan)) fail('planがruntime_plan.v1 contractを満たさない');
|
|
630
638
|
if (!validateHoldDecision(holdDecision)) fail('holdDecisionがcontractを満たさない');
|
|
631
639
|
if (!Array.isArray(additionalConflicts)) fail('additionalConflictsがarrayではない');
|
|
@@ -673,7 +681,11 @@ export function recompileNextEpochPlan(options = {}) {
|
|
|
673
681
|
plan_ref: newPlanRef,
|
|
674
682
|
plan_epoch: newEpoch,
|
|
675
683
|
request_digest: request.request_digest,
|
|
676
|
-
|
|
684
|
+
// 変換でsourceの構造が変わったなら、再開先は変換を含むbaseでなければならない。
|
|
685
|
+
// 旧baseのまま再開させると、splitが所有を宣言した新pathがworktreeに存在しない(ADR 0141)。
|
|
686
|
+
// carry-over側のrebind packetはcontent不変が要件なので、そちらは触らない——
|
|
687
|
+
// 継続する作業は自分のworktreeで走り続けており、baseを付け替える対象ではない。
|
|
688
|
+
base_sha: successorBaseSha ?? plan.base_sha,
|
|
677
689
|
nodes: structuredClone(plan.nodes),
|
|
678
690
|
precedence: structuredClone(plan.precedence),
|
|
679
691
|
conflicts: mergedConflicts,
|
|
@@ -98,7 +98,8 @@ export function buildRuntimeSeamSplit({
|
|
|
98
98
|
export async function resolveRuntimeSeamTreatment(options = {}) {
|
|
99
99
|
const {
|
|
100
100
|
finding, witnessSet, pathNames = {}, predeclaredTreatments = [],
|
|
101
|
-
applyConflict, baseSha, manifestDigest, affectedTests = [],
|
|
101
|
+
applyConflict, commitTransform, baseSha, manifestDigest, affectedTests = [],
|
|
102
|
+
taskMigrationDigest,
|
|
102
103
|
} = options;
|
|
103
104
|
|
|
104
105
|
if (finding?.kind === 'observed_write_conflict' && typeof finding.path === 'string') {
|
|
@@ -122,6 +123,13 @@ export async function resolveRuntimeSeamTreatment(options = {}) {
|
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
const applied = await applyConflict({ conflict });
|
|
126
|
+
if (applied?.outcome?.decision === 'accepted' && typeof commitTransform !== 'function') {
|
|
127
|
+
// 確定する手段が無いまま採用すると、splitは所有を宣言するのに再開先へその成果が無い。
|
|
128
|
+
// 「変換した」と言いながら再開できない状態を作らない(ADR 0141)。
|
|
129
|
+
return {
|
|
130
|
+
lane: 'intentional_serial', treatment: null, split: null, reasons: ['committer_absent'],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
125
133
|
if (applied?.outcome?.decision !== 'accepted') {
|
|
126
134
|
return {
|
|
127
135
|
lane: 'intentional_serial',
|
|
@@ -140,6 +148,15 @@ export async function resolveRuntimeSeamTreatment(options = {}) {
|
|
|
140
148
|
if (built.split === null) {
|
|
141
149
|
return { lane: 'intentional_serial', treatment: null, split: null, reasons: built.reasons };
|
|
142
150
|
}
|
|
151
|
+
// 再開先が実在するbaseを要る。branchを動かさずcommitとして確定し、そのshaを後継planへ渡す。
|
|
152
|
+
const committed = await commitTransform({
|
|
153
|
+
conflict, files: applied.files ?? {}, candidateId: conflict.candidateId,
|
|
154
|
+
});
|
|
155
|
+
if (!/^[0-9a-f]{40}$/u.test(committed?.commitSha ?? '')) {
|
|
156
|
+
return {
|
|
157
|
+
lane: 'intentional_serial', treatment: null, split: null, reasons: ['transform_not_committed'],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
143
160
|
return {
|
|
144
161
|
lane: 'seam_transform',
|
|
145
162
|
treatment: {
|
|
@@ -148,6 +165,8 @@ export async function resolveRuntimeSeamTreatment(options = {}) {
|
|
|
148
165
|
},
|
|
149
166
|
split: built.split,
|
|
150
167
|
files: applied.files ?? null,
|
|
168
|
+
successor_base_sha: committed.commitSha,
|
|
169
|
+
successor_base_ref: committed.ref ?? null,
|
|
151
170
|
reasons: [],
|
|
152
171
|
};
|
|
153
172
|
}
|
|
Binary file
|