@quolu/lattice 0.69.4 → 0.70.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 +5 -1
- package/package.json +1 -1
- package/src/cli-help.mjs +4 -2
- package/src/todo-cli.mjs +88 -11
- package/src/todo-store.mjs +25 -54
package/README.ja.md
CHANGED
|
@@ -309,9 +309,13 @@ required evidenceを束縛した`todo phase accept`で重監査の判断を記
|
|
|
309
309
|
```bash
|
|
310
310
|
lattice todo phase status --plan <key> # phase無しplanでも暗黙Phaseを返す(implicit: true)
|
|
311
311
|
lattice todo phase review --plan <key> --phase terminal-audit --reason <text>
|
|
312
|
-
lattice todo phase accept --plan <key> --phase terminal-audit --
|
|
312
|
+
lattice todo phase accept --plan <key> --phase terminal-audit --evidence <監査file>
|
|
313
313
|
```
|
|
314
314
|
|
|
315
|
+
`--evidence`には、commit済みの監査本文をrepo相対pathで渡します。reviewのevent digest、証拠の記述子、
|
|
316
|
+
必須evidence slotはLatticeが組み立てます。必須slotが複数あるPhaseや、記述子を自分で渡したい時は
|
|
317
|
+
`--input <file>`(`lattice.phase_accept_input.v1`、`input_digest`は空でよい)を使います。
|
|
318
|
+
|
|
315
319
|
**過去の工程は監査できません。** 監査対象のコードが既に変化しているためです。そこで
|
|
316
320
|
「監査なしで閉じた」という状態を別に持ちます——`accepted`(監査を通った)へは絶対に化けず、
|
|
317
321
|
記録は永久に区別できます。工程図では畳まれるので監査待ちの札は外れます。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quolu/lattice",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.70.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",
|
package/src/cli-help.mjs
CHANGED
|
@@ -141,6 +141,8 @@ Write commands:
|
|
|
141
141
|
# 実際に受理する最新契約のJSON Schemaを返す(storeを読まない)。
|
|
142
142
|
# 入力が契約に合わないときは、違反フィールドのpathがerror detailへ載る
|
|
143
143
|
phase review --plan <key> --phase <id> --reason <text>
|
|
144
|
+
phase accept --plan <key> --phase <id> --evidence <file> # 監査fileから入力を機械が組む
|
|
145
|
+
phase reject --plan <key> --phase <id> --reason <text> --evidence <file>
|
|
144
146
|
phase <accept|reject> --plan <key> --phase <id> --input <file>
|
|
145
147
|
phase reopen --plan <key> --phase <id> --reason <text> [--override-reason <text>]
|
|
146
148
|
phase close-unaudited --plan <key> --phase <id> --reason <text>
|
|
@@ -278,8 +280,8 @@ const SUBCOMMAND_USAGE = Object.freeze({
|
|
|
278
280
|
+ ' | baseline --reason <text> [--except <plan_key>]...',
|
|
279
281
|
'todo phase status': 'todo phase status --plan <key>',
|
|
280
282
|
'todo phase review': 'todo phase review --plan <key> --phase <id> --reason <text>',
|
|
281
|
-
'todo phase accept': 'todo phase accept --plan <key> --phase <id> --input <file>',
|
|
282
|
-
'todo phase reject': 'todo phase reject --plan <key> --phase <id> --input <file>',
|
|
283
|
+
'todo phase accept': 'todo phase accept --plan <key> --phase <id> --evidence <file> | --input <file>',
|
|
284
|
+
'todo phase reject': 'todo phase reject --plan <key> --phase <id> --reason <text> --evidence <file> | --input <file>',
|
|
283
285
|
'todo phase reopen': 'todo phase reopen --plan <key> --phase <id> --reason <text> [--override-reason <text>]',
|
|
284
286
|
'todo phase close-unaudited': 'todo phase close-unaudited --plan <key> --phase <id> --reason <text>',
|
|
285
287
|
'todo phase baseline': 'todo phase baseline --reason <text> [--except <plan_key>]...',
|
package/src/todo-cli.mjs
CHANGED
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
isPhaselessTodoPlanSchema,
|
|
61
61
|
projectTodoCrossPlanDependencies,
|
|
62
62
|
TERMINAL_AUDIT_PHASE_ID,
|
|
63
|
+
todoPhaseDefinitions,
|
|
63
64
|
readTodoIndependenceArtifact,
|
|
64
65
|
readTodoSeamProposalArtifact,
|
|
65
66
|
readTodoStore,
|
|
@@ -974,13 +975,38 @@ function validatePhaseDecisionInput(value, outcome) {
|
|
|
974
975
|
&& isTodoDigest(value.input_digest) && value.input_digest === todoSelfDigest(value, 'input_digest');
|
|
975
976
|
}
|
|
976
977
|
|
|
978
|
+
// `--input`の形が合わないとき、期待形をerrorへ同梱する(ADR 0130)。自己digestは入口が補うので
|
|
979
|
+
// 空でよい(ADR 0181)。証拠記述子を手で作らせないために、ふつうは`--evidence`を案内する。
|
|
980
|
+
const PHASE_DECISION_EXPECTED = Object.freeze({
|
|
981
|
+
accept: '{ "schema": "lattice.phase_accept_input.v1", "review_event_digest": "<phase reviewのevent_digest>",'
|
|
982
|
+
+ ' "decision_evidence": <evidence記述子>, "evidence_slots": [{ "slot_id": "<必須slot>", "evidence": <evidence記述子> }],'
|
|
983
|
+
+ ' "input_digest": "" }',
|
|
984
|
+
reject: '{ "schema": "lattice.phase_reject_input.v1", "review_event_digest": "<phase reviewのevent_digest>",'
|
|
985
|
+
+ ' "reason": "<text>", "decision_evidence": <evidence記述子>, "input_digest": "" }',
|
|
986
|
+
note: 'input_digestは入口が計算する。証拠fileがcommit済みなら、`--evidence <file>`で'
|
|
987
|
+
+ 'review_event_digest・記述子・必須slotを機械が埋める。evidence記述子の形はEVIDENCE_DESCRIPTOR_EXPECTEDを見る。',
|
|
988
|
+
});
|
|
989
|
+
|
|
977
990
|
async function phaseDecision({ repoRoot, env, planKey, phaseId, outcome, inputRef }) {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
991
|
+
let input;
|
|
992
|
+
try {
|
|
993
|
+
input = await readRevisionInput(repoRoot, inputRef, {
|
|
994
|
+
validate: (value) => validatePhaseDecisionInput(value, outcome),
|
|
995
|
+
invalidCode: 'PHASE_DECISION_INVALID', invalidReason: 'phase_decision_schema_or_digest_invalid',
|
|
996
|
+
// phase decision入力はrevision契約と別形状。既定のrevision explainを誤って当てない。
|
|
997
|
+
explain: null,
|
|
998
|
+
});
|
|
999
|
+
} catch (error) {
|
|
1000
|
+
if (error instanceof TodoStoreError && error.code === 'PHASE_DECISION_INVALID') {
|
|
1001
|
+
throw new TodoStoreError('PHASE_DECISION_INVALID', 'phase_decision_schema_or_digest_invalid', undefined, {
|
|
1002
|
+
expected: PHASE_DECISION_EXPECTED[outcome], note: PHASE_DECISION_EXPECTED.note,
|
|
1003
|
+
evidence_descriptor: EVIDENCE_DESCRIPTOR_EXPECTED,
|
|
1004
|
+
next_action: `lattice todo phase ${outcome} --plan ${planKey} --phase ${phaseId}`
|
|
1005
|
+
+ (outcome === 'reject' ? ' --reason <text>' : '') + ' --evidence <repo内の監査file>',
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
throw error;
|
|
1009
|
+
}
|
|
984
1010
|
const payload = outcome === 'accept'
|
|
985
1011
|
? { review_event_digest: input.review_event_digest, decision_evidence: input.decision_evidence,
|
|
986
1012
|
evidence_slots: input.evidence_slots }
|
|
@@ -989,6 +1015,49 @@ async function phaseDecision({ repoRoot, env, planKey, phaseId, outcome, inputRe
|
|
|
989
1015
|
return phaseMutation({ repoRoot, env, planKey, phaseId, kind: `phase_${outcome}`, payload });
|
|
990
1016
|
}
|
|
991
1017
|
|
|
1018
|
+
/**
|
|
1019
|
+
* `--evidence <file>`から判断入力を組み立てる(ADR 0181の下書き受理をphase判断へ広げる)。
|
|
1020
|
+
* review_event_digestはstoreの現在のreviewから、記述子は`todo done`と同じ処理でcommit済み
|
|
1021
|
+
* fileから作る。必須slotが1つならその証拠で埋める。複数slotへ1つの証拠を流用すると
|
|
1022
|
+
* 「各slotを別々に確かめた」ことを偽るので、その場合は`--input`で明示させる。
|
|
1023
|
+
*/
|
|
1024
|
+
async function phaseDecisionFromEvidence({ repoRoot, env, planKey, phaseId, outcome, evidenceRef, reason }) {
|
|
1025
|
+
const store = await readTodoStore({ repoRoot });
|
|
1026
|
+
const member = store.members.find(({ plan }) => plan.plan_key === planKey);
|
|
1027
|
+
if (member === undefined) {
|
|
1028
|
+
throw new TodoStoreError('PHASE_DECISION_INVALID', 'plan_not_active', undefined, { plan_key: planKey });
|
|
1029
|
+
}
|
|
1030
|
+
const state = member.phases.find(({ phase_id: current }) => current === phaseId);
|
|
1031
|
+
const definition = todoPhaseDefinitions(member.plan).find(({ phase_id: current }) => current === phaseId);
|
|
1032
|
+
if (state === undefined || definition === undefined) {
|
|
1033
|
+
throw new TodoStoreError('PHASE_DECISION_INVALID', 'phase_not_found', undefined, {
|
|
1034
|
+
plan_key: planKey, phase_id: phaseId,
|
|
1035
|
+
phases: todoPhaseDefinitions(member.plan).map(({ phase_id: id }) => id),
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
if (state.status !== 'reviewing' || state.review_event_digest === null) {
|
|
1039
|
+
throw new TodoStoreError('PHASE_DECISION_INVALID', 'phase_not_reviewing', undefined, {
|
|
1040
|
+
plan_key: planKey, phase_id: phaseId, status: state.status,
|
|
1041
|
+
next_action: `lattice todo phase review --plan ${planKey} --phase ${phaseId} --reason <text>`,
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
if (outcome === 'accept' && definition.required_evidence_slots.length !== 1) {
|
|
1045
|
+
throw new TodoStoreError('PHASE_DECISION_INVALID', 'multiple_evidence_slots_need_input', undefined, {
|
|
1046
|
+
required_evidence_slots: definition.required_evidence_slots,
|
|
1047
|
+
expected: PHASE_DECISION_EXPECTED.accept, evidence_descriptor: EVIDENCE_DESCRIPTOR_EXPECTED,
|
|
1048
|
+
next_action: `lattice todo phase accept --plan ${planKey} --phase ${phaseId} --input <file>`,
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
const evidence = await resolveDoneEvidence({
|
|
1052
|
+
repoRoot, evidenceRef, evidenceMessage: null, planKey, taskId: `${phaseId}-${outcome}`,
|
|
1053
|
+
});
|
|
1054
|
+
const payload = outcome === 'accept'
|
|
1055
|
+
? { review_event_digest: state.review_event_digest, decision_evidence: evidence,
|
|
1056
|
+
evidence_slots: definition.required_evidence_slots.map((slotId) => ({ slot_id: slotId, evidence })) }
|
|
1057
|
+
: { review_event_digest: state.review_event_digest, reason, decision_evidence: evidence };
|
|
1058
|
+
return phaseMutation({ repoRoot, env, planKey, phaseId, kind: `phase_${outcome}`, payload });
|
|
1059
|
+
}
|
|
1060
|
+
|
|
992
1061
|
async function phaseMutation({ repoRoot, env, planKey, phaseId, kind, payload }) {
|
|
993
1062
|
const { event, snapshot, phases } = await appendTodoEvent({
|
|
994
1063
|
repoRoot, writer: createTodoStoreWriter({ caller: 'g5-authoring' }), planKey,
|
|
@@ -3989,14 +4058,22 @@ export async function runTodoCli({ argv, cwd, stdout, stderr, env = process.env
|
|
|
3989
4058
|
action = (repoRoot) => phaseMutation({ repoRoot, env, planKey: argv[3], phaseId: argv[5],
|
|
3990
4059
|
kind: 'phase_review', payload: { reason: argv[7] } });
|
|
3991
4060
|
} else if (argv[0] === 'phase' && ['accept', 'reject'].includes(argv[1])) {
|
|
3992
|
-
const
|
|
3993
|
-
|
|
4061
|
+
const outcome = argv[1];
|
|
4062
|
+
const flags = matchFlagCommand(argv, ['phase', outcome], {
|
|
4063
|
+
known: ['plan', 'phase', 'input', 'evidence', 'reason'], required: ['plan', 'phase'],
|
|
3994
4064
|
});
|
|
3995
|
-
|
|
3996
|
-
|
|
4065
|
+
const base = flags !== null && isTodoIdentifier(flags.plan) && isTodoIdentifier(flags.phase);
|
|
4066
|
+
if (base && isAuthoringPathToken(flags.input) && flags.evidence === undefined && flags.reason === undefined) {
|
|
3997
4067
|
action = (repoRoot) => phaseDecision({
|
|
3998
4068
|
repoRoot, env, planKey: flags.plan, phaseId: flags.phase,
|
|
3999
|
-
outcome
|
|
4069
|
+
outcome, inputRef: flags.input,
|
|
4070
|
+
});
|
|
4071
|
+
} else if (base && flags.input === undefined && isAuthoringPathToken(flags.evidence)
|
|
4072
|
+
&& (outcome === 'accept' ? flags.reason === undefined
|
|
4073
|
+
: typeof flags.reason === 'string' && flags.reason.length > 0)) {
|
|
4074
|
+
action = (repoRoot) => phaseDecisionFromEvidence({
|
|
4075
|
+
repoRoot, env, planKey: flags.plan, phaseId: flags.phase,
|
|
4076
|
+
outcome, evidenceRef: flags.evidence, reason: flags.reason ?? null,
|
|
4000
4077
|
});
|
|
4001
4078
|
}
|
|
4002
4079
|
} else if ((argv.length === 8 || argv.length === 10) && argv[0] === 'phase'
|
package/src/todo-store.mjs
CHANGED
|
@@ -62,7 +62,6 @@ const CROSS_PLAN_RECOVERY_CLAIMS_REF = `${STORE_ROOT_REF}/.cross-plan-recovery`;
|
|
|
62
62
|
const CROSS_PLAN_IMPORT_TRANSACTION_SCHEMA = 'lattice.todo_cross_plan_import_transaction.v1';
|
|
63
63
|
const SOURCE_CUTOVER_BARRIER_REF = `${STORE_ROOT_REF}/source-cutover-recovery.json`;
|
|
64
64
|
const SOURCE_CUTOVER_RECOVERY_CAPABILITY = Symbol('lattice.todo.source-cutover-recovery');
|
|
65
|
-
const EVIDENCE_REPAIR_CAPABILITY = Symbol('lattice.todo.evidence-repair');
|
|
66
65
|
const MAX_FUTURE_SKEW_MS = 5 * 60 * 1_000;
|
|
67
66
|
const WRITER_CALLERS = new Set(['g4-migration', 'g5-authoring']);
|
|
68
67
|
const TODO_REVISION_SCHEMAS = Object.freeze([
|
|
@@ -621,8 +620,10 @@ function replay(plan, events, { now = new Date(), verifyEvidence, verifyImportSo
|
|
|
621
620
|
const decisionEvidence = event.payload.decision_evidence;
|
|
622
621
|
const slotEvidence = event.payload.evidence_slots.map((slot) => slot.evidence);
|
|
623
622
|
pendingVerifications.set(`phase:${event.phase_id}`, () => {
|
|
624
|
-
|
|
625
|
-
|
|
623
|
+
const context = { plan_key: plan.plan_key, phase_id: event.phase_id,
|
|
624
|
+
event_digest: event.event_digest };
|
|
625
|
+
verifyEvidence(decisionEvidence, context);
|
|
626
|
+
for (const evidence of slotEvidence) verifyEvidence(evidence, context);
|
|
626
627
|
});
|
|
627
628
|
}
|
|
628
629
|
state.status = 'accepted'; state.decision_event_digest = event.event_digest;
|
|
@@ -633,7 +634,9 @@ function replay(plan, events, { now = new Date(), verifyEvidence, verifyImportSo
|
|
|
633
634
|
}
|
|
634
635
|
if (verifyEvidence) {
|
|
635
636
|
const decisionEvidence = event.payload.decision_evidence;
|
|
636
|
-
pendingVerifications.set(`phase:${event.phase_id}`, () => verifyEvidence(decisionEvidence
|
|
637
|
+
pendingVerifications.set(`phase:${event.phase_id}`, () => verifyEvidence(decisionEvidence, {
|
|
638
|
+
plan_key: plan.plan_key, phase_id: event.phase_id, event_digest: event.event_digest,
|
|
639
|
+
}));
|
|
637
640
|
}
|
|
638
641
|
state.status = 'rejected'; state.decision_event_digest = event.event_digest;
|
|
639
642
|
state.decision_evidence = event.payload.decision_evidence;
|
|
@@ -1222,7 +1225,7 @@ function readEvidenceBlob(absoluteRepo, oid) {
|
|
|
1222
1225
|
return entry.bytes;
|
|
1223
1226
|
}
|
|
1224
1227
|
|
|
1225
|
-
function evidenceVerifier(manifest, repoRoot, hard,
|
|
1228
|
+
function evidenceVerifier(manifest, repoRoot, hard, newEventDigest = null) {
|
|
1226
1229
|
const repositories = new Map(manifest.repositories.map((repo) => [repo.repo_id, repo.path]));
|
|
1227
1230
|
return (descriptor, context = {}) => {
|
|
1228
1231
|
if (!validateEvidenceDescriptor(descriptor)) fail('STORE_INCONSISTENT', 'evidence_descriptor_invalid');
|
|
@@ -1245,15 +1248,8 @@ function evidenceVerifier(manifest, repoRoot, hard, repair = null) {
|
|
|
1245
1248
|
if (sha256Bytes(bytes) !== descriptor.content_digest) throw new Error('digest mismatch');
|
|
1246
1249
|
return true;
|
|
1247
1250
|
} catch {
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
&& context.plan_key === repair.planKey
|
|
1251
|
-
&& typeof context.task_id === 'string'
|
|
1252
|
-
&& context.task_id === repair.taskId;
|
|
1253
|
-
// evidence promotionだけは、同じtaskの過去eventを新しいhard-verified eventで
|
|
1254
|
-
// supersedeするためにここを通る。prospective event自身と他taskは免除しない。
|
|
1255
|
-
if (repairTarget
|
|
1256
|
-
&& (repair.eventDigest === null || context.event_digest !== repair.eventDigest)) return false;
|
|
1251
|
+
// 既存の不達は未検証として残す。新eventの証拠だけは書込み前にhard検証する。
|
|
1252
|
+
if (newEventDigest !== null && context.event_digest !== newEventDigest) return false;
|
|
1257
1253
|
if (hard) fail('STORE_INCONSISTENT', 'evidence_unverified', {
|
|
1258
1254
|
...context,
|
|
1259
1255
|
next_action: context.plan_key === undefined
|
|
@@ -1416,20 +1412,14 @@ function liveReplacementPreservesListStructure(lineBytes, replacement) {
|
|
|
1416
1412
|
return source !== null && target !== null && source[1] === target[1] && source[2] === target[2];
|
|
1417
1413
|
}
|
|
1418
1414
|
|
|
1419
|
-
function importSourceVerifier(repoRoot, hard, cache = null,
|
|
1415
|
+
function importSourceVerifier(repoRoot, hard, cache = null, newEventDigest = null) {
|
|
1420
1416
|
return (descriptor, context = {}) => {
|
|
1421
1417
|
if (!validateTodoImportSource(descriptor)) fail('STORE_INCONSISTENT', 'import_source_descriptor_invalid');
|
|
1422
1418
|
try {
|
|
1423
1419
|
pinnedSourceLine(repoRoot, descriptor, cache);
|
|
1424
1420
|
return true;
|
|
1425
1421
|
} catch {
|
|
1426
|
-
|
|
1427
|
-
&& typeof repair.taskId === 'string'
|
|
1428
|
-
&& context.plan_key === repair.planKey
|
|
1429
|
-
&& typeof context.task_id === 'string'
|
|
1430
|
-
&& context.task_id === repair.taskId;
|
|
1431
|
-
if (repairTarget
|
|
1432
|
-
&& (repair.eventDigest === null || context.event_digest !== repair.eventDigest)) return false;
|
|
1422
|
+
if (newEventDigest !== null && context.event_digest !== newEventDigest) return false;
|
|
1433
1423
|
if (hard) fail('STORE_INCONSISTENT', 'import_source_unverified', {
|
|
1434
1424
|
...context,
|
|
1435
1425
|
next_action: 'verify_source_commit_origin_path_and_line_then_retry',
|
|
@@ -1605,14 +1595,8 @@ export async function readTodoStore(options = {}) {
|
|
|
1605
1595
|
fail('STORE_INCONSISTENT', 'manifest_revision_binding_mismatch');
|
|
1606
1596
|
}
|
|
1607
1597
|
prefetchVerificationObjects(manifest, repoRoot, journal.events, pinnedSourceCache);
|
|
1608
|
-
const
|
|
1609
|
-
|
|
1610
|
-
const verifyEvidence = evidenceVerifier(
|
|
1611
|
-
manifest, repoRoot, options.forWrite === true, evidenceRepair,
|
|
1612
|
-
);
|
|
1613
|
-
const verifyImportSource = importSourceVerifier(
|
|
1614
|
-
repoRoot, options.forWrite === true, pinnedSourceCache, evidenceRepair,
|
|
1615
|
-
);
|
|
1598
|
+
const verifyEvidence = evidenceVerifier(manifest, repoRoot, false);
|
|
1599
|
+
const verifyImportSource = importSourceVerifier(repoRoot, false, pinnedSourceCache);
|
|
1616
1600
|
const tasks = replay(plan, journal.events, {
|
|
1617
1601
|
now: options.now ? new Date(options.now) : new Date(),
|
|
1618
1602
|
verifyEvidence: options.forWrite === true ? verifyEvidence : undefined,
|
|
@@ -2056,13 +2040,8 @@ export async function appendTodoEvent(options = {}) {
|
|
|
2056
2040
|
requireWriter(options.writer, 'g5-authoring');
|
|
2057
2041
|
const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
|
|
2058
2042
|
return withLock(repoRoot, async () => {
|
|
2059
|
-
const evidenceRepair = options.event.kind === 'done'
|
|
2060
|
-
&& options.event.payload?.done_mode === 'evidence_promotion'
|
|
2061
|
-
? { planKey: options.planKey, taskId: options.event.task_id, eventDigest: null }
|
|
2062
|
-
: null;
|
|
2063
2043
|
const store = await readTodoStore({
|
|
2064
|
-
repoRoot, forWrite: true, now: options.now,
|
|
2065
|
-
evidenceRepairCapability: EVIDENCE_REPAIR_CAPABILITY,
|
|
2044
|
+
repoRoot, forWrite: true, now: options.now,
|
|
2066
2045
|
// 修理扉は除去event(tombstone)の書込みだけに開く。それ以外の書込みは従来どおり
|
|
2067
2046
|
// binding_stale で fail closed する(validateMergedGraph の注記を参照)
|
|
2068
2047
|
tolerateStaleBindings: options.tolerateStaleBindings === true
|
|
@@ -2113,16 +2092,8 @@ export async function appendTodoEvent(options = {}) {
|
|
|
2113
2092
|
[...member.journal.events, event], appendSourceCache);
|
|
2114
2093
|
replay(member.plan, [...member.journal.events, event], {
|
|
2115
2094
|
now: options.now ? new Date(options.now) : new Date(),
|
|
2116
|
-
verifyEvidence: evidenceVerifier(store.manifest, repoRoot, true,
|
|
2117
|
-
|
|
2118
|
-
taskId: event.task_id,
|
|
2119
|
-
eventDigest: event.event_digest,
|
|
2120
|
-
}),
|
|
2121
|
-
verifyImportSource: importSourceVerifier(repoRoot, true, appendSourceCache, {
|
|
2122
|
-
planKey: member.plan.plan_key,
|
|
2123
|
-
taskId: event.task_id,
|
|
2124
|
-
eventDigest: event.event_digest,
|
|
2125
|
-
}),
|
|
2095
|
+
verifyEvidence: evidenceVerifier(store.manifest, repoRoot, true, event.event_digest),
|
|
2096
|
+
verifyImportSource: importSourceVerifier(repoRoot, true, appendSourceCache, event.event_digest),
|
|
2126
2097
|
});
|
|
2127
2098
|
if (options.materializedEvidence !== null && options.materializedEvidence !== undefined) {
|
|
2128
2099
|
const asset = options.materializedEvidence;
|
|
@@ -4270,8 +4241,8 @@ async function applyPhaseTodoRevisionV3(options, revision, repoRoot) {
|
|
|
4270
4241
|
await protocolStage(options, 'phase_v3_marker_durable');
|
|
4271
4242
|
const tasks = replay(revision.desired_plan, [genesis], {
|
|
4272
4243
|
now: options.now ? new Date(options.now) : new Date(),
|
|
4273
|
-
verifyEvidence: evidenceVerifier(store.manifest, repoRoot,
|
|
4274
|
-
verifyImportSource: importSourceVerifier(repoRoot,
|
|
4244
|
+
verifyEvidence: evidenceVerifier(store.manifest, repoRoot, false),
|
|
4245
|
+
verifyImportSource: importSourceVerifier(repoRoot, false),
|
|
4275
4246
|
});
|
|
4276
4247
|
const snapshot = snapshotFor(revision.desired_plan, [genesis], tasks);
|
|
4277
4248
|
for (const [stage, ref, bytes] of [
|
|
@@ -4437,8 +4408,8 @@ export async function applyPhaseTodoRevision(options = {}) {
|
|
|
4437
4408
|
const journalRef = `${base}/journal/active.jsonl`; const snapshotRef = `${base}/snapshot.json`;
|
|
4438
4409
|
const tasks = replay(revision.desired_plan, [genesis], {
|
|
4439
4410
|
now: options.now ? new Date(options.now) : new Date(),
|
|
4440
|
-
verifyEvidence: evidenceVerifier(store.manifest, repoRoot,
|
|
4441
|
-
verifyImportSource: importSourceVerifier(repoRoot,
|
|
4411
|
+
verifyEvidence: evidenceVerifier(store.manifest, repoRoot, false),
|
|
4412
|
+
verifyImportSource: importSourceVerifier(repoRoot, false),
|
|
4442
4413
|
});
|
|
4443
4414
|
const snapshot = snapshotFor(revision.desired_plan, [genesis], tasks);
|
|
4444
4415
|
const artifacts = [
|
|
@@ -4586,8 +4557,8 @@ export async function applyTodoRevision(options = {}) {
|
|
|
4586
4557
|
}
|
|
4587
4558
|
await protocolStage(options, 'revision_marker_durable');
|
|
4588
4559
|
|
|
4589
|
-
const verifyEvidence = evidenceVerifier(store.manifest, repoRoot,
|
|
4590
|
-
const verifyImportSource = importSourceVerifier(repoRoot,
|
|
4560
|
+
const verifyEvidence = evidenceVerifier(store.manifest, repoRoot, false);
|
|
4561
|
+
const verifyImportSource = importSourceVerifier(repoRoot, false);
|
|
4591
4562
|
const tasks = replay(revision.desired_plan, [genesis], {
|
|
4592
4563
|
now: options.now ? new Date(options.now) : new Date(), verifyEvidence, verifyImportSource,
|
|
4593
4564
|
});
|
|
@@ -4862,8 +4833,8 @@ export async function applyTodoRevisionSet(options = {}) {
|
|
|
4862
4833
|
}
|
|
4863
4834
|
await protocolStage(options, 'revision_set_marker_durable');
|
|
4864
4835
|
|
|
4865
|
-
const verifyEvidence = evidenceVerifier(store.manifest, repoRoot,
|
|
4866
|
-
const verifyImportSource = importSourceVerifier(repoRoot,
|
|
4836
|
+
const verifyEvidence = evidenceVerifier(store.manifest, repoRoot, false);
|
|
4837
|
+
const verifyImportSource = importSourceVerifier(repoRoot, false);
|
|
4867
4838
|
for (const entry of prepared) {
|
|
4868
4839
|
const { revision, genesis } = entry;
|
|
4869
4840
|
const tasks = replay(revision.desired_plan, [genesis], {
|