@quolu/lattice 0.32.0 → 0.33.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/README.ja.md +11 -1
- package/README.md +11 -2
- package/bin/lattice.mjs +12 -1
- package/package.json +1 -1
- package/sensor/dist/bin/lattice-sensor.js +72 -4
- package/sensor/dist/db/migrations.d.ts +1 -1
- package/sensor/dist/db/migrations.d.ts.map +1 -1
- package/sensor/dist/db/migrations.js +32 -2
- package/sensor/dist/db/migrations.js.map +1 -1
- package/sensor/dist/db/queries.d.ts +10 -0
- package/sensor/dist/db/queries.d.ts.map +1 -1
- package/sensor/dist/db/queries.js +53 -7
- package/sensor/dist/db/queries.js.map +1 -1
- package/sensor/dist/db/schema.sql +6 -1
- package/sensor/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/sensor/dist/extraction/tree-sitter.js +89 -16
- package/sensor/dist/extraction/tree-sitter.js.map +1 -1
- package/sensor/dist/index.d.ts +8 -1
- package/sensor/dist/index.d.ts.map +1 -1
- package/sensor/dist/index.js +9 -0
- package/sensor/dist/index.js.map +1 -1
- package/sensor/dist/resolution/import-resolver.d.ts +11 -0
- package/sensor/dist/resolution/import-resolver.d.ts.map +1 -1
- package/sensor/dist/resolution/import-resolver.js +13 -5
- package/sensor/dist/resolution/import-resolver.js.map +1 -1
- package/sensor/dist/resolution/index.d.ts.map +1 -1
- package/sensor/dist/resolution/index.js +11 -0
- package/sensor/dist/resolution/index.js.map +1 -1
- package/sensor/dist/resolution/types.d.ts +4 -0
- package/sensor/dist/resolution/types.d.ts.map +1 -1
- package/sensor/dist/types.d.ts +16 -0
- package/sensor/dist/types.d.ts.map +1 -1
- package/src/artifact-contracts.mjs +3 -0
- package/src/cli-help.mjs +6 -0
- package/src/rc3-scripted-campaign.mjs +3 -1
- package/src/runtime-cli.mjs +280 -36
- package/src/runtime-contracts.mjs +1 -1
- package/src/runtime-control-store.mjs +24 -1
- package/src/runtime-decision-verifier.mjs +1 -1
- package/src/runtime-diff-observer.mjs +2 -2
- package/src/runtime-front-end.mjs +47 -13
- package/src/runtime-hold-recompile.mjs +31 -2
- package/src/runtime-io-sentinel.mjs +16 -9
- package/src/runtime-managed-supervisor.mjs +9 -1
- package/src/runtime-multi-epoch-store.mjs +2 -2
- package/src/runtime-projection.mjs +27 -0
- package/src/runtime-scripted-adapter-controller.mjs +22 -1
- package/src/runtime-seam-resolve.mjs +156 -13
- package/src/runtime-seam-treatment.mjs +2 -1
- package/src/seam-apply.mjs +101 -4
- package/src/seam-cost.mjs +322 -0
- package/src/seam-gate.mjs +146 -0
- package/src/seam-rewrite.mjs +102 -16
- package/src/seam-verification.mjs +26 -3
- package/src/sensor-adapter.mjs +6 -1
- package/src/todo-cli.mjs +55 -0
|
@@ -23,6 +23,10 @@ const sortedUnique = (values) => [...new Set(values)].sort(compareText);
|
|
|
23
23
|
* 分割で外部の消費者が影響を受けるかは、原pathの公開面が変わったかで決まる。原pathが
|
|
24
24
|
* 同じ名前を同じだけ出し続けるなら、原pathをimportしている側は一行も変わらない
|
|
25
25
|
* (ADR 0137 Decision 3)。
|
|
26
|
+
*
|
|
27
|
+
* **ESM構文(`export function` / `export {}`)を正規表現で読むJS/TS限定の検査である。**
|
|
28
|
+
* 他言語のsourceに対しては公開名を1つも読めず、比較は実質空になる——「検証済み」を
|
|
29
|
+
* 主張しない(ADR 0145)。言語非依存の網は切断参照の計数(`severed`観測)が担う。
|
|
26
30
|
*/
|
|
27
31
|
export function readExportSurface(text) {
|
|
28
32
|
if (typeof text !== 'string') return [];
|
|
@@ -149,19 +153,38 @@ const CONDITIONS = Object.freeze([
|
|
|
149
153
|
* @param {{preserved: boolean, missing: string[]}} options.exportSurface 公開面の比較
|
|
150
154
|
* @param {boolean} options.focusedTestsPassed 変換後worktreeでのfocused test結果
|
|
151
155
|
* @param {boolean} options.sensorFresh 変換後の再indexが新pathを収載したか
|
|
156
|
+
* @param {{observed: boolean, entries: Array<{file: string, name: string}>}|null} options.severed
|
|
157
|
+
* 切断参照の観測(ADR 0145)。`null`はfresh indexへ到達しなかった時で、その場合は
|
|
158
|
+
* sensor_freshが先に落ちる。`observed: false`は観測の失敗であり「切断なし」へ丸めない。
|
|
152
159
|
* @param {{targetResolved: boolean, before: number, after: number}} options.conflictPairs 競合対の増減
|
|
153
160
|
* @param {{before: number|null, after: number|null}} options.waves 実行段階数の増減
|
|
161
|
+
*
|
|
162
|
+
* behavior_equivalentは2つの観測の合成である。(1) export面の比較——**ESM構文を正規表現で
|
|
163
|
+
* 読むのでJS/TS限定**。他言語のsourceに対しては常にpreservedを返す実質空の検査であり、
|
|
164
|
+
* 「検証済み」を主張しない。(2) 切断参照の計数——fresh indexのsymbol一覧に立つので、
|
|
165
|
+
* sensorが抽出できる言語なら効く。網の言語非依存部はこちらが担う。
|
|
154
166
|
*/
|
|
155
167
|
export function evaluateSeamVerification(options = {}) {
|
|
156
168
|
const {
|
|
157
|
-
exportSurface, focusedTestsPassed, sensorFresh, conflictPairs, waves,
|
|
169
|
+
exportSurface, focusedTestsPassed, sensorFresh, conflictPairs, waves, severed = null,
|
|
158
170
|
} = options;
|
|
159
171
|
const detail = {};
|
|
160
172
|
const failures = [];
|
|
161
173
|
|
|
162
|
-
|
|
174
|
+
const surfacePreserved = exportSurface?.preserved === true;
|
|
175
|
+
// severedがnullのままここへ来るのはsensor_freshが落ちる経路だけ。fresh indexに到達したのに
|
|
176
|
+
// 観測が組めなかった(observed: false)は、切断なしではなく観測の欠落として落とす。
|
|
177
|
+
const severedObserved = severed === null || severed.observed === true;
|
|
178
|
+
const severedEntries = severed?.entries ?? [];
|
|
179
|
+
detail.behavior_equivalent = surfacePreserved && severedObserved && severedEntries.length === 0;
|
|
163
180
|
if (!detail.behavior_equivalent) {
|
|
164
|
-
|
|
181
|
+
if (!surfacePreserved) {
|
|
182
|
+
failures.push(`behavior_equivalent:${(exportSurface?.missing ?? []).join(',') || 'unknown'}`);
|
|
183
|
+
}
|
|
184
|
+
if (!severedObserved) failures.push('behavior_equivalent:severed_observation_missing');
|
|
185
|
+
for (const entry of severedEntries) {
|
|
186
|
+
failures.push(`behavior_equivalent:severed_reference:${entry.file}:${entry.name}`);
|
|
187
|
+
}
|
|
165
188
|
}
|
|
166
189
|
|
|
167
190
|
detail.focused_tests_passed = focusedTestsPassed === true;
|
package/src/sensor-adapter.mjs
CHANGED
|
@@ -333,9 +333,14 @@ async function collectOne({ cwd, query, execute, inspectAffectedPath }) {
|
|
|
333
333
|
operation,
|
|
334
334
|
target,
|
|
335
335
|
cwd,
|
|
336
|
+
// callers/calleesはCLI既定の20件で黙って切られる。fanoutの大きい関数では
|
|
337
|
+
// module値への参照(valueRef)が窓の外へ落ち、閉包が「完結した」と誤認する
|
|
338
|
+
// ——観測の打ち切りを「無い」へ丸めない。明示limitで引く。
|
|
336
339
|
args: operation === 'status'
|
|
337
340
|
? ['status', '.', '--json']
|
|
338
|
-
: [
|
|
341
|
+
: ['callers', 'callees'].includes(operation)
|
|
342
|
+
? [operation, target, '--path', '.', '--limit', '200', '--json']
|
|
343
|
+
: [operation, target, '--path', '.', '--json'],
|
|
339
344
|
};
|
|
340
345
|
const result = await executeCommand(execute, command);
|
|
341
346
|
if (result.code !== 0) {
|
package/src/todo-cli.mjs
CHANGED
|
@@ -861,6 +861,56 @@ async function independence({ repoRoot, requestedPlanKey }) {
|
|
|
861
861
|
return result;
|
|
862
862
|
}
|
|
863
863
|
|
|
864
|
+
/**
|
|
865
|
+
* 切断コストの内訳を投影する(read-only、docs/plan_seam-cost.md)。
|
|
866
|
+
*
|
|
867
|
+
* 係争fileについて「何を共有しているから単純に切れないのか」を数えられる事実として出す。
|
|
868
|
+
* task別のsymbol帰属はwitness setのconcern_anchorsから取る——係争資源に対する宣言は
|
|
869
|
+
* そこに既に在り、ここで発明しない。閾値も可否判定も返さない。
|
|
870
|
+
*
|
|
871
|
+
* 投影であって記録ではない。sensorが進めば変わる値なので、artifactへ焼き込まず
|
|
872
|
+
* stdoutへ返すだけにする(ADR 0127のindependence記録と同じ線)。
|
|
873
|
+
*/
|
|
874
|
+
async function seamProfile({ repoRoot, planKey, filePath }) {
|
|
875
|
+
const witnessSet = await readTodoWitnessSet({ repoRoot, planKey });
|
|
876
|
+
if (witnessSet === null) {
|
|
877
|
+
throw new TodoStoreError('SEAM_PROFILE_UNAVAILABLE', 'witness_set_absent', undefined, {
|
|
878
|
+
plan_key: planKey, next_action: 'declare_witness_set',
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
const ownedSymbolsByTask = {};
|
|
882
|
+
for (const [taskId, witness] of Object.entries(witnessSet.manual_witness ?? {})) {
|
|
883
|
+
const symbols = (witness.concern_anchors ?? [])
|
|
884
|
+
.filter((anchor) => anchor.within?.target === filePath)
|
|
885
|
+
.flatMap((anchor) => anchor.symbols);
|
|
886
|
+
if (symbols.length > 0) ownedSymbolsByTask[taskId] = [...symbols].sort();
|
|
887
|
+
}
|
|
888
|
+
if (Object.keys(ownedSymbolsByTask).length < 2) {
|
|
889
|
+
// 帰属が2 task未満なら「切断のコスト」という問いが立たない。宣言が無いことを
|
|
890
|
+
// 空の内訳へ丸めず、何を書けば観測できるかを返す(ADR 0130の案内規律)。
|
|
891
|
+
throw new TodoStoreError('SEAM_PROFILE_UNAVAILABLE', 'concern_anchors_below_two_tasks', undefined, {
|
|
892
|
+
plan_key: planKey, file: filePath,
|
|
893
|
+
next_action: 'declare_concern_anchors_for_contested_file',
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
let sourceText;
|
|
897
|
+
try {
|
|
898
|
+
sourceText = await readFile(path.join(repoRoot, filePath), 'utf8');
|
|
899
|
+
} catch {
|
|
900
|
+
throw new TodoStoreError('SEAM_PROFILE_UNAVAILABLE', 'contested_file_unreadable', undefined, {
|
|
901
|
+
file: filePath,
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
const { computeSeamCostProfile } = await import('./seam-cost.mjs');
|
|
905
|
+
const { profile, reasons } = await computeSeamCostProfile({
|
|
906
|
+
repoRoot, sourcePath: filePath, sourceText, ownedSymbolsByTask,
|
|
907
|
+
});
|
|
908
|
+
if (profile === null) {
|
|
909
|
+
throw new TodoStoreError('SEAM_PROFILE_UNAVAILABLE', reasons[0] ?? 'profile_unavailable');
|
|
910
|
+
}
|
|
911
|
+
return profile;
|
|
912
|
+
}
|
|
913
|
+
|
|
864
914
|
async function seamProposalCompile({ repoRoot, planKey }) {
|
|
865
915
|
requireCleanWorktree(repoRoot);
|
|
866
916
|
const currentBaseSha = currentHeadSha(repoRoot);
|
|
@@ -1811,6 +1861,11 @@ export async function runTodoCli({ argv, cwd, stdout, stderr, env = process.env
|
|
|
1811
1861
|
pathNames: await readSeamPathNames(repoRoot, argv[5]),
|
|
1812
1862
|
land: true,
|
|
1813
1863
|
});
|
|
1864
|
+
} else if ((argv.length === 5 || argv.length === 6) && argv[0] === 'seam-profile'
|
|
1865
|
+
&& argv[1] === '--plan' && isTodoIdentifier(argv[2])
|
|
1866
|
+
&& argv[3] === '--file' && isTodoRef(argv[4])
|
|
1867
|
+
&& (argv.length === 5 || argv[5] === '--json')) {
|
|
1868
|
+
action = (repoRoot) => seamProfile({ repoRoot, planKey: argv[2], filePath: argv[4] });
|
|
1814
1869
|
} else if (argv.length === 4 && argv[0] === 'seam-proposal' && argv[1] === 'compile'
|
|
1815
1870
|
&& argv[2] === '--plan' && isTodoIdentifier(argv[3])) {
|
|
1816
1871
|
action = (repoRoot) => seamProposalCompile({ repoRoot, planKey: argv[3] });
|