@fitlab-ai/agent-infra 0.11.0 → 0.11.2
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/dist/lib/internal/cli-route-inventory.js +1 -1
- package/dist/lib/internal/manual-validation.js +6 -2
- package/dist/lib/internal/platform-comment.js +59 -0
- package/dist/lib/internal/sandbox-control.js +4 -131
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +1 -0
- package/dist/lib/internal/task-review.js +5 -5
- package/dist/lib/internal/task-validate.js +0 -6
- package/dist/lib/platform/comment-safety.js +7 -1
- package/dist/lib/platform/github-provider.js +13 -3
- package/dist/lib/platform/issue-comments.js +120 -13
- package/dist/lib/platform/issues.js +3 -4
- package/dist/lib/platform/provider-contract.d.ts +2 -0
- package/dist/lib/platform/provider-validation.js +7 -2
- package/dist/lib/platform/verification-sync.js +161 -156
- package/dist/lib/sandbox/control/executor.js +0 -38
- package/dist/lib/sandbox/control/finalization-response.js +10 -2
- package/dist/lib/sandbox/control/task-view.js +3 -1
- package/dist/lib/sandbox/control/workflow-executor.js +32 -41
- package/dist/lib/task/artifact-command.js +6 -6
- package/dist/lib/task/artifact-lifecycle.js +15 -52
- package/dist/lib/task/artifact-operations.js +27 -1
- package/dist/lib/task/capabilities.js +0 -2
- package/dist/lib/task/codex-orchestration.js +10 -208
- package/dist/lib/task/commit-operation.js +3 -18
- package/dist/lib/task/control-authority.js +1 -8
- package/dist/lib/task/delegation-receipts.js +14 -76
- package/dist/lib/task/events.js +147 -278
- package/dist/lib/task/finalization-state.js +2 -1
- package/dist/lib/task/finalization.js +273 -49
- package/dist/lib/task/gate-policy.js +94 -0
- package/dist/lib/task/lifecycle-execution.js +2 -11
- package/dist/lib/task/local-artifact-finalization.js +31 -245
- package/dist/lib/task/orchestration.js +8 -24
- package/dist/lib/task/review-artifacts.js +12 -6
- package/dist/lib/task/review-command.js +0 -1
- package/dist/lib/task/review-finalization.js +47 -218
- package/dist/lib/task/verification-engine.js +28 -17
- package/dist/lib/task/verification.js +25 -9
- package/dist/lib/task/workflow-command.js +4 -1
- package/dist/lib/task/workflow-dispatch.js +55 -3
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/internal/cli-route-inventory.ts +1 -1
- package/lib/internal/manual-validation.ts +6 -2
- package/lib/internal/platform-comment.ts +38 -0
- package/lib/internal/sandbox-control.ts +3 -145
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-operation-registry.ts +1 -0
- package/lib/internal/task-review.ts +5 -5
- package/lib/internal/task-validate.ts +0 -5
- package/lib/platform/comment-safety.ts +8 -0
- package/lib/platform/github-provider.ts +11 -2
- package/lib/platform/issue-comments.ts +132 -13
- package/lib/platform/issues.ts +3 -4
- package/lib/platform/provider-contract.ts +2 -0
- package/lib/platform/provider-validation.ts +6 -2
- package/lib/platform/verification-sync.ts +178 -179
- package/lib/sandbox/control/executor.ts +0 -44
- package/lib/sandbox/control/finalization-response.ts +10 -2
- package/lib/sandbox/control/task-view.ts +3 -1
- package/lib/sandbox/control/workflow-executor.ts +31 -48
- package/lib/task/artifact-command.ts +6 -7
- package/lib/task/artifact-lifecycle.ts +12 -49
- package/lib/task/artifact-operations.ts +27 -1
- package/lib/task/capabilities.ts +0 -1
- package/lib/task/codex-orchestration.ts +8 -241
- package/lib/task/commit-operation.ts +3 -23
- package/lib/task/control-authority.ts +1 -8
- package/lib/task/delegation-receipts.ts +12 -79
- package/lib/task/events.ts +155 -287
- package/lib/task/finalization-state.ts +2 -1
- package/lib/task/finalization.ts +277 -57
- package/lib/task/gate-policy.ts +133 -0
- package/lib/task/lifecycle-execution.ts +10 -21
- package/lib/task/local-artifact-finalization.ts +29 -285
- package/lib/task/orchestration.ts +12 -41
- package/lib/task/review-artifacts.ts +8 -2
- package/lib/task/review-command.ts +0 -1
- package/lib/task/review-finalization.ts +46 -200
- package/lib/task/verification-engine.ts +24 -14
- package/lib/task/verification-types.ts +7 -0
- package/lib/task/verification.ts +25 -9
- package/lib/task/workflow-command.ts +4 -1
- package/lib/task/workflow-dispatch.ts +46 -3
- package/package.json +2 -2
- package/templates/.agents/rules/issue-sync.en.md +2 -0
- package/templates/.agents/rules/issue-sync.zh-CN.md +5 -8
- package/templates/.agents/rules/lifecycle-orchestration.en.md +7 -7
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +7 -7
- package/templates/.agents/rules/local-artifact-repair.en.md +14 -52
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -52
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -10
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/block-task/config/verify.json +1 -3
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -4
- package/templates/.agents/skills/code-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/config/verify.en.json +1 -12
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -12
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -0
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -0
- package/templates/.agents/skills/commit/config/verify.json +1 -5
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +6 -6
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +6 -6
- package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-task/config/verify.en.json +3 -14
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +3 -14
- package/templates/.agents/skills/create-pr/config/verify.json +1 -10
- package/templates/.agents/skills/create-task/config/verify.json +1 -4
- package/templates/.agents/skills/import-issue/config/verify.json +1 -2
- package/templates/.agents/skills/plan-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -10
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -10
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -10
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/review-code/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/review-plan/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -10
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/review-pr/config/verify.en.json +1 -8
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +1 -8
- package/templates/.agents/skills/run-manual-validation/config/verify.en.json +38 -13
- package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +38 -13
- package/templates/.agents/skills/run-task/SKILL.en.md +6 -6
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +2 -2
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +2 -2
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
4
4
|
import { syncPlatformComment } from '../platform/issue-comments.js';
|
|
5
|
+
import { canonicalizeSummaryBody } from '../platform/comment-safety.js';
|
|
6
|
+
import { taskIssueIdentity } from '../platform/task-identities.js';
|
|
7
|
+
import { parseTaskFrontmatter } from './frontmatter.js';
|
|
5
8
|
import { applyTaskLifecycle } from './lifecycle.js';
|
|
6
9
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
7
10
|
import { inspectShortIdRegistry } from './short-id.js';
|
|
@@ -9,8 +12,8 @@ import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-
|
|
|
9
12
|
import { verifyTaskEvent } from './verification.js';
|
|
10
13
|
import { projectFinalizationWarning } from './workflow-warning-intents.js';
|
|
11
14
|
import { mergeOperationWarnings } from './operation-outcome.js';
|
|
12
|
-
const RECEIPT_VERSION =
|
|
13
|
-
const FINALIZATION_STEPS = ['lifecycle', 'task-comment', 'verification'];
|
|
15
|
+
const RECEIPT_VERSION = 3;
|
|
16
|
+
const FINALIZATION_STEPS = ['lifecycle', 'task-comment', 'verification', 'summary', 'post-summary-verification'];
|
|
14
17
|
function finalizationRoot(repoRoot) {
|
|
15
18
|
return path.join(repoRoot, '.agents', 'workspace', '.task-finalization');
|
|
16
19
|
}
|
|
@@ -34,6 +37,8 @@ function failed(taskId, error, overrides = {}) {
|
|
|
34
37
|
lifecycle: null,
|
|
35
38
|
taskComment: null,
|
|
36
39
|
verification: null,
|
|
40
|
+
summary: null,
|
|
41
|
+
postSummaryVerification: null,
|
|
37
42
|
completedSteps: [],
|
|
38
43
|
pendingSteps: [...FINALIZATION_STEPS],
|
|
39
44
|
result: error.retryable ? 'blocked' : 'failed',
|
|
@@ -52,8 +57,11 @@ function emptyReceipt(taskId, controlBinding) {
|
|
|
52
57
|
lifecycle: 'pending',
|
|
53
58
|
taskComment: 'pending',
|
|
54
59
|
verification: 'pending',
|
|
60
|
+
summary: 'pending',
|
|
61
|
+
postSummaryVerification: 'pending',
|
|
55
62
|
warningProjection: 'done',
|
|
56
63
|
warnings: [],
|
|
64
|
+
summarySha256: null,
|
|
57
65
|
...(controlBinding ? { controlBinding } : {}),
|
|
58
66
|
updatedAt: now(),
|
|
59
67
|
lastError: null
|
|
@@ -88,8 +96,11 @@ function validateReceipt(value, taskId) {
|
|
|
88
96
|
|| !states.includes(String(receipt.lifecycle))
|
|
89
97
|
|| !states.includes(String(receipt.taskComment))
|
|
90
98
|
|| !states.includes(String(receipt.verification))
|
|
99
|
+
|| !states.includes(String(receipt.summary))
|
|
100
|
+
|| !states.includes(String(receipt.postSummaryVerification))
|
|
91
101
|
|| !['pending', 'done'].includes(String(receipt.warningProjection))
|
|
92
102
|
|| !Array.isArray(receipt.warnings) || receipt.warnings.some((warning) => !validWarning(warning))
|
|
103
|
+
|| (receipt.summarySha256 !== null && (typeof receipt.summarySha256 !== 'string' || !/^[a-f0-9]{64}$/u.test(receipt.summarySha256)))
|
|
93
104
|
|| typeof receipt.updatedAt !== 'string'
|
|
94
105
|
|| (receipt.lastError !== null && (typeof receipt.lastError !== 'object' || Array.isArray(receipt.lastError)))
|
|
95
106
|
|| (receipt.controlBinding !== undefined && (!controlBinding || typeof controlBinding !== 'object'
|
|
@@ -109,10 +120,6 @@ function readReceipt(repoRoot, taskId) {
|
|
|
109
120
|
function readTaskFinalizationReceipt(repoRoot, taskId) {
|
|
110
121
|
return readReceipt(path.resolve(repoRoot), taskId);
|
|
111
122
|
}
|
|
112
|
-
function controlBindingMatches(receipt, binding) {
|
|
113
|
-
return receipt.controlBinding?.generation === binding.generation
|
|
114
|
-
&& receipt.controlBinding.requestId === binding.requestId;
|
|
115
|
-
}
|
|
116
123
|
function writeReceipt(repoRoot, receipt) {
|
|
117
124
|
const directory = finalizationRoot(repoRoot);
|
|
118
125
|
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
@@ -132,20 +139,24 @@ function writeReceipt(repoRoot, receipt) {
|
|
|
132
139
|
}
|
|
133
140
|
function updateReceipt(repoRoot, receipt, patch) {
|
|
134
141
|
const current = readReceipt(repoRoot, receipt.taskId);
|
|
135
|
-
if (!current || current.receiptId !== receipt.receiptId
|
|
136
|
-
|
|
137
|
-
Object.assign(error, { code: 'FINALIZATION_CAPABILITY_STALE' });
|
|
138
|
-
throw error;
|
|
139
|
-
}
|
|
142
|
+
if (!current || current.receiptId !== receipt.receiptId)
|
|
143
|
+
throw capabilityError('FINALIZATION_SCOPE_INVALID', 'finalization receipt does not belong to the current task');
|
|
140
144
|
const next = { ...current, ...patch, revision: current.revision + 1, updatedAt: now() };
|
|
141
145
|
writeReceipt(repoRoot, next);
|
|
142
146
|
return next;
|
|
143
147
|
}
|
|
144
148
|
function completedSteps(receipt) {
|
|
145
|
-
return FINALIZATION_STEPS.filter((step) => receipt
|
|
149
|
+
return FINALIZATION_STEPS.filter((step) => stepState(receipt, step) !== 'pending');
|
|
146
150
|
}
|
|
147
151
|
function pendingSteps(receipt) {
|
|
148
|
-
return FINALIZATION_STEPS.filter((step) => receipt
|
|
152
|
+
return FINALIZATION_STEPS.filter((step) => stepState(receipt, step) === 'pending');
|
|
153
|
+
}
|
|
154
|
+
function stepState(receipt, step) {
|
|
155
|
+
if (step === 'task-comment')
|
|
156
|
+
return receipt.taskComment;
|
|
157
|
+
if (step === 'post-summary-verification')
|
|
158
|
+
return receipt.postSummaryVerification;
|
|
159
|
+
return receipt[step];
|
|
149
160
|
}
|
|
150
161
|
function lifecycleStep(result) {
|
|
151
162
|
return {
|
|
@@ -234,9 +245,8 @@ function mutationKeys(value) {
|
|
|
234
245
|
return Object.keys(value).sort();
|
|
235
246
|
}
|
|
236
247
|
function validateCapabilityMutation(current, capability, mutation, consumed) {
|
|
237
|
-
if (capability.receiptId !== current.receiptId
|
|
238
|
-
throw capabilityError('
|
|
239
|
-
}
|
|
248
|
+
if (capability.receiptId !== current.receiptId)
|
|
249
|
+
throw capabilityError('FINALIZATION_SCOPE_INVALID', 'finalization mutation belongs to a different task receipt');
|
|
240
250
|
if (capability.scope !== mutation.scope) {
|
|
241
251
|
throw capabilityError('FINALIZATION_SCOPE_INVALID', 'finalization capability mutation scope does not match its capability');
|
|
242
252
|
}
|
|
@@ -403,9 +413,89 @@ async function syncPendingTaskComment(input) {
|
|
|
403
413
|
return { receipt, step: { status: 'blocked', changed: false, error: detail }, changed: false, error: detail };
|
|
404
414
|
}
|
|
405
415
|
}
|
|
416
|
+
function readDeliverySummary(taskDir, taskId) {
|
|
417
|
+
const file = path.join(taskDir, '.delivery-summary.json');
|
|
418
|
+
let value;
|
|
419
|
+
try {
|
|
420
|
+
value = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
throw Object.assign(new Error('delivery summary staging record is unavailable'), { code: 'SUMMARY_STAGING_INVALID' });
|
|
424
|
+
}
|
|
425
|
+
if (value.taskId !== taskId || typeof value.body !== 'string' || typeof value.sha256 !== 'string') {
|
|
426
|
+
throw Object.assign(new Error('delivery summary staging record is invalid'), { code: 'SUMMARY_STAGING_INVALID' });
|
|
427
|
+
}
|
|
428
|
+
const canonical = canonicalizeSummaryBody(value.body);
|
|
429
|
+
if (!canonical.ok || canonical.value !== value.body) {
|
|
430
|
+
throw Object.assign(new Error('delivery summary staging body is not canonical'), { code: 'SUMMARY_STAGING_INVALID' });
|
|
431
|
+
}
|
|
432
|
+
const digest = createHash('sha256').update(canonical.value).digest('hex');
|
|
433
|
+
if (digest !== value.sha256)
|
|
434
|
+
throw Object.assign(new Error('delivery summary staging digest does not match body'), { code: 'SUMMARY_STAGING_INVALID' });
|
|
435
|
+
return { body: canonical.value, sha256: value.sha256 };
|
|
436
|
+
}
|
|
437
|
+
async function syncPendingSummary(input) {
|
|
438
|
+
let { receipt } = input;
|
|
439
|
+
if (receipt.summary !== 'pending') {
|
|
440
|
+
return { receipt, step: { status: receipt.summary === 'skipped' ? 'skipped' : 'no-op', changed: false, error: null }, changed: false, error: null };
|
|
441
|
+
}
|
|
442
|
+
try {
|
|
443
|
+
const resolved = resolveTaskRef(input.taskId, { repoRoot: input.repoRoot });
|
|
444
|
+
if (!resolved.ok || resolved.state !== 'completed')
|
|
445
|
+
throw Object.assign(new Error('completed task is unavailable for summary sync'), { code: 'SUMMARY_STAGING_INVALID' });
|
|
446
|
+
if (!taskIssueIdentity(parseTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8')))) {
|
|
447
|
+
receipt = updateReceipt(input.repoRoot, receipt, {
|
|
448
|
+
summary: 'skipped', postSummaryVerification: 'skipped', summarySha256: null, lastError: null
|
|
449
|
+
});
|
|
450
|
+
return { receipt, step: { status: 'skipped', changed: false, error: null }, changed: false, error: null };
|
|
451
|
+
}
|
|
452
|
+
const summary = readDeliverySummary(resolved.taskDir, input.taskId);
|
|
453
|
+
const result = await input.commentSync(input.taskId, {
|
|
454
|
+
kind: 'summary', agent: input.agent, body: summary.body, cwd: input.repoRoot,
|
|
455
|
+
summaryAuthorization: { sha256: summary.sha256 }
|
|
456
|
+
});
|
|
457
|
+
const step = commentStep(result);
|
|
458
|
+
if (result.status === 'applied' || result.status === 'no-op') {
|
|
459
|
+
const skipped = result.error?.code === 'ISSUE_NOT_LINKED';
|
|
460
|
+
const resolvedWarning = receipt.warnings.some((warning) => warning.step === 'summary' && warning.status === 'open');
|
|
461
|
+
const warnings = resolveStepWarnings(receipt, 'summary');
|
|
462
|
+
receipt = updateReceipt(input.repoRoot, receipt, {
|
|
463
|
+
summary: skipped ? 'skipped' : 'done', postSummaryVerification: skipped ? 'skipped' : receipt.postSummaryVerification,
|
|
464
|
+
summarySha256: skipped ? null : summary.sha256,
|
|
465
|
+
taskComment: resolvedWarning ? 'pending' : receipt.taskComment,
|
|
466
|
+
warningProjection: warnings.some((warning) => warning.status === 'open') ? 'pending' : 'done',
|
|
467
|
+
warnings,
|
|
468
|
+
lastError: null
|
|
469
|
+
});
|
|
470
|
+
return { receipt, step: skipped ? { ...step, status: 'skipped' } : step, changed: result.changed, error: null };
|
|
471
|
+
}
|
|
472
|
+
const error = step.error ?? { code: 'SUMMARY_SYNC_FAILED', message: 'delivery summary synchronization failed', retryable: true };
|
|
473
|
+
const warning = warningFromError('summary', error);
|
|
474
|
+
const alreadyOpen = receipt.warnings.some((item) => item.step === warning.step && item.code === warning.code && item.target === warning.target && item.status === 'open');
|
|
475
|
+
const warnings = replaceWarning(receipt, warning, 'open');
|
|
476
|
+
receipt = updateReceipt(input.repoRoot, receipt, { summary: 'pending', taskComment: alreadyOpen ? receipt.taskComment : 'pending', warningProjection: 'pending', warnings, lastError: error });
|
|
477
|
+
return { receipt, step, changed: result.changed, error };
|
|
478
|
+
}
|
|
479
|
+
catch (cause) {
|
|
480
|
+
const error = errorOf(cause, 'SUMMARY_SYNC_FAILED', true);
|
|
481
|
+
try {
|
|
482
|
+
const warning = warningFromError('summary', error);
|
|
483
|
+
const alreadyOpen = receipt.warnings.some((item) => item.step === warning.step && item.code === warning.code && item.target === warning.target && item.status === 'open');
|
|
484
|
+
const warnings = replaceWarning(receipt, warning, 'open');
|
|
485
|
+
receipt = updateReceipt(input.repoRoot, receipt, { summary: 'pending', taskComment: alreadyOpen ? receipt.taskComment : 'pending', warningProjection: 'pending', warnings, lastError: error });
|
|
486
|
+
}
|
|
487
|
+
catch { /* preserve primary error */ }
|
|
488
|
+
return { receipt, step: { status: 'blocked', changed: false, error }, changed: false, error };
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
function clearDeliverySummary(taskDir) {
|
|
492
|
+
const file = path.join(taskDir, '.delivery-summary.json');
|
|
493
|
+
if (fs.existsSync(file))
|
|
494
|
+
fs.unlinkSync(file);
|
|
495
|
+
}
|
|
406
496
|
function terminalResult(taskId, receipt, steps, changed, error = null) {
|
|
407
497
|
const pending = pendingSteps(receipt);
|
|
408
|
-
const blocked = [steps.lifecycle, steps.taskComment, steps.verification].some((step) => step?.status === 'blocked');
|
|
498
|
+
const blocked = [steps.lifecycle, steps.taskComment, steps.verification, steps.summary, steps.postSummaryVerification].some((step) => step?.status === 'blocked');
|
|
409
499
|
const warnings = openWarnings(receipt);
|
|
410
500
|
const postLifecyclePending = receipt.lifecycle === 'done' && (pending.some((step) => step !== 'lifecycle') || receipt.warningProjection === 'pending');
|
|
411
501
|
const hardError = error?.code.startsWith('FINALIZATION_') || error?.code === 'TASK_FINALIZATION_RECEIPT_INVALID';
|
|
@@ -413,13 +503,17 @@ function terminalResult(taskId, receipt, steps, changed, error = null) {
|
|
|
413
503
|
status: hardError ? (error?.retryable ? 'blocked' : 'failed') : pending.length === 0 ? 'completed' : postLifecyclePending ? 'completed' : blocked ? 'blocked' : 'failed',
|
|
414
504
|
changed,
|
|
415
505
|
taskId,
|
|
416
|
-
|
|
506
|
+
lifecycle: steps.lifecycle ?? null,
|
|
507
|
+
taskComment: steps.taskComment ?? null,
|
|
508
|
+
verification: steps.verification ?? null,
|
|
509
|
+
summary: steps.summary ?? null,
|
|
510
|
+
postSummaryVerification: steps.postSummaryVerification ?? null,
|
|
417
511
|
completedSteps: completedSteps(receipt),
|
|
418
512
|
pendingSteps: pending,
|
|
419
|
-
result:
|
|
420
|
-
? '
|
|
421
|
-
:
|
|
422
|
-
?
|
|
513
|
+
result: hardError
|
|
514
|
+
? (error?.retryable ? 'blocked' : 'failed')
|
|
515
|
+
: postLifecyclePending && (warnings.length > 0 || receipt.warningProjection === 'pending')
|
|
516
|
+
? 'completed_with_warnings'
|
|
423
517
|
: pending.length === 0 || postLifecyclePending
|
|
424
518
|
? 'completed'
|
|
425
519
|
: blocked
|
|
@@ -446,17 +540,9 @@ async function applyUnderLock(request, taskId, options) {
|
|
|
446
540
|
catch (error) {
|
|
447
541
|
return failed(taskId, errorOf(error, 'TASK_FINALIZATION_RECEIPT_INVALID'));
|
|
448
542
|
}
|
|
449
|
-
if (options.controlBinding &&
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
message: 'finalization receipt belongs to a different sandbox request or generation',
|
|
453
|
-
retryable: false
|
|
454
|
-
};
|
|
455
|
-
return failed(taskId, error, {
|
|
456
|
-
completedSteps: completedSteps(receipt),
|
|
457
|
-
pendingSteps: pendingSteps(receipt)
|
|
458
|
-
});
|
|
459
|
-
}
|
|
543
|
+
if (options.controlBinding && (receipt.controlBinding?.generation !== options.controlBinding.generation
|
|
544
|
+
|| receipt.controlBinding.requestId !== options.controlBinding.requestId))
|
|
545
|
+
receipt = updateReceipt(repoRoot, receipt, { controlBinding: options.controlBinding });
|
|
460
546
|
const preflightState = resolveTaskRef(taskId, { repoRoot });
|
|
461
547
|
if (options.preflight && preflightState.ok && preflightState.state === 'active') {
|
|
462
548
|
try {
|
|
@@ -546,13 +632,11 @@ async function applyUnderLock(request, taskId, options) {
|
|
|
546
632
|
let verification = null;
|
|
547
633
|
try {
|
|
548
634
|
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
verification = verificationStep(result);
|
|
555
|
-
if (result.status === 'pass') {
|
|
635
|
+
const verificationPending = receipt.verification === 'pending';
|
|
636
|
+
const result = await verify({ taskRef: taskId, event: 'complete-task.completed' }, { repoRoot });
|
|
637
|
+
verification = verificationStep(result);
|
|
638
|
+
if (result.status === 'pass') {
|
|
639
|
+
if (verificationPending) {
|
|
556
640
|
const capability = issueCapability(receipt, 'verification');
|
|
557
641
|
receipt = applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, {
|
|
558
642
|
scope: 'verification', operation: 'succeeded'
|
|
@@ -570,30 +654,170 @@ async function applyUnderLock(request, taskId, options) {
|
|
|
570
654
|
}
|
|
571
655
|
}
|
|
572
656
|
else {
|
|
573
|
-
|
|
657
|
+
receipt = updateReceipt(repoRoot, receipt, { lastError: null });
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
const detail = verification.error ?? { code: 'VERIFY_FAILED', message: 'verification failed', retryable: true };
|
|
662
|
+
if (verificationPending) {
|
|
574
663
|
const capability = issueCapability(receipt, 'verification');
|
|
575
664
|
receipt = applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, {
|
|
576
665
|
scope: 'verification', operation: 'failed', error: detail
|
|
577
666
|
}, consumedCapabilities);
|
|
578
667
|
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
579
|
-
return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification }, changed, verification.error);
|
|
580
668
|
}
|
|
669
|
+
else {
|
|
670
|
+
const warnings = replaceWarning(receipt, warningFromError('verification', detail), 'open');
|
|
671
|
+
receipt = updateReceipt(repoRoot, receipt, {
|
|
672
|
+
verification: 'pending', taskComment: 'pending', warningProjection: 'pending', warnings, lastError: detail
|
|
673
|
+
});
|
|
674
|
+
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
675
|
+
const warningComment = await syncPendingTaskComment({ repoRoot, taskId, agent: request.agent, receipt, commentSync, consumedCapabilities });
|
|
676
|
+
receipt = warningComment.receipt;
|
|
677
|
+
if (warningComment.step.status !== 'no-op')
|
|
678
|
+
taskComment = warningComment.step;
|
|
679
|
+
changed = changed || warningComment.changed;
|
|
680
|
+
}
|
|
681
|
+
return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification }, changed, detail);
|
|
581
682
|
}
|
|
582
683
|
}
|
|
583
684
|
catch (error) {
|
|
584
685
|
const detail = errorOf(error, 'VERIFY_FAILED', true);
|
|
585
686
|
try {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
687
|
+
if (receipt.verification === 'pending') {
|
|
688
|
+
const capability = issueCapability(receipt, 'verification');
|
|
689
|
+
receipt = applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, {
|
|
690
|
+
scope: 'verification', operation: 'failed', error: detail
|
|
691
|
+
}, consumedCapabilities);
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
const warnings = replaceWarning(receipt, warningFromError('verification', detail), 'open');
|
|
695
|
+
receipt = updateReceipt(repoRoot, receipt, {
|
|
696
|
+
verification: 'pending', taskComment: 'pending', warningProjection: 'pending', warnings, lastError: detail
|
|
697
|
+
});
|
|
698
|
+
}
|
|
590
699
|
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
591
700
|
}
|
|
701
|
+
catch (writeError) {
|
|
702
|
+
const persistence = errorOf(writeError, 'FINALIZATION_RECEIPT_WRITE_FAILED', true);
|
|
703
|
+
const hardError = {
|
|
704
|
+
code: 'FINALIZATION_RECEIPT_WRITE_FAILED',
|
|
705
|
+
message: `Unable to persist verification failure (${detail.code}: ${detail.message}): ${persistence.message}`,
|
|
706
|
+
retryable: true
|
|
707
|
+
};
|
|
708
|
+
return terminalResult(taskId, receipt, {
|
|
709
|
+
lifecycle: lifecycleResult, taskComment, verification: { status: 'blocked', changed: false, error: detail }
|
|
710
|
+
}, changed, hardError);
|
|
711
|
+
}
|
|
712
|
+
try {
|
|
713
|
+
const warningComment = await syncPendingTaskComment({ repoRoot, taskId, agent: request.agent, receipt, commentSync, consumedCapabilities });
|
|
714
|
+
receipt = warningComment.receipt;
|
|
715
|
+
if (warningComment.step.status !== 'no-op')
|
|
716
|
+
taskComment = warningComment.step;
|
|
717
|
+
changed = changed || warningComment.changed;
|
|
718
|
+
}
|
|
592
719
|
catch { /* preserve the primary error */ }
|
|
593
720
|
return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification: { status: 'blocked', changed: false, error: detail } }, changed, detail);
|
|
594
721
|
}
|
|
722
|
+
const summary = await syncPendingSummary({ repoRoot, taskId, agent: request.agent, receipt, commentSync });
|
|
723
|
+
receipt = summary.receipt;
|
|
724
|
+
changed = changed || summary.changed;
|
|
725
|
+
if (summary.error) {
|
|
726
|
+
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
727
|
+
const warningComment = await syncPendingTaskComment({
|
|
728
|
+
repoRoot, taskId, agent: request.agent, receipt, commentSync, consumedCapabilities
|
|
729
|
+
});
|
|
730
|
+
receipt = warningComment.receipt;
|
|
731
|
+
if (warningComment.step.status !== 'no-op')
|
|
732
|
+
taskComment = warningComment.step;
|
|
733
|
+
changed = changed || warningComment.changed;
|
|
734
|
+
return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification, summary: summary.step }, changed, summary.error);
|
|
735
|
+
}
|
|
736
|
+
let postSummaryVerification = null;
|
|
737
|
+
if (receipt.postSummaryVerification === 'skipped') {
|
|
738
|
+
postSummaryVerification = { status: 'skipped', changed: false, error: null };
|
|
739
|
+
}
|
|
740
|
+
else if (receipt.postSummaryVerification !== 'pending') {
|
|
741
|
+
const replay = await commentSync(taskId, {
|
|
742
|
+
kind: 'summary', agent: request.agent, body: '', cwd: repoRoot, verifyOnly: true,
|
|
743
|
+
summaryAuthorization: { sha256: receipt.summarySha256 ?? '' }
|
|
744
|
+
});
|
|
745
|
+
postSummaryVerification = commentStep(replay);
|
|
746
|
+
if (replay.status !== 'applied' && replay.status !== 'no-op') {
|
|
747
|
+
const error = postSummaryVerification.error ?? { code: 'SUMMARY_VERIFICATION_FAILED', message: 'summary replay verification failed', retryable: true };
|
|
748
|
+
const warnings = replaceWarning(receipt, warningFromError('post-summary-verification', error), 'open');
|
|
749
|
+
receipt = updateReceipt(repoRoot, receipt, { postSummaryVerification: 'pending', taskComment: 'pending', warningProjection: 'pending', warnings, lastError: error });
|
|
750
|
+
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
751
|
+
return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification, summary: summary.step, postSummaryVerification }, changed, error);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
try {
|
|
756
|
+
const summaryVerification = await commentSync(taskId, {
|
|
757
|
+
kind: 'summary', agent: request.agent, body: '', cwd: repoRoot, verifyOnly: true,
|
|
758
|
+
summaryAuthorization: { sha256: receipt.summarySha256 ?? '' }
|
|
759
|
+
});
|
|
760
|
+
if (summaryVerification.status !== 'applied' && summaryVerification.status !== 'no-op') {
|
|
761
|
+
const error = commentStep(summaryVerification).error ?? { code: 'SUMMARY_VERIFICATION_FAILED', message: 'summary verification failed', retryable: true };
|
|
762
|
+
const warnings = replaceWarning(receipt, warningFromError('post-summary-verification', error), 'open');
|
|
763
|
+
receipt = updateReceipt(repoRoot, receipt, { postSummaryVerification: 'pending', taskComment: 'pending', warningProjection: 'pending', warnings, lastError: error });
|
|
764
|
+
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
765
|
+
const warningComment = await syncPendingTaskComment({ repoRoot, taskId, agent: request.agent, receipt, commentSync, consumedCapabilities });
|
|
766
|
+
receipt = warningComment.receipt;
|
|
767
|
+
if (warningComment.step.status !== 'no-op')
|
|
768
|
+
taskComment = warningComment.step;
|
|
769
|
+
changed = changed || warningComment.changed;
|
|
770
|
+
return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification, summary: summary.step, postSummaryVerification: commentStep(summaryVerification) }, changed, error);
|
|
771
|
+
}
|
|
772
|
+
const result = await verify({ taskRef: taskId, event: 'complete-task.completed' }, { repoRoot });
|
|
773
|
+
postSummaryVerification = verificationStep(result);
|
|
774
|
+
if (result.status === 'pass') {
|
|
775
|
+
const resolvedWarning = receipt.warnings.some((warning) => warning.step === 'post-summary-verification' && warning.status === 'open');
|
|
776
|
+
const warnings = resolveStepWarnings(receipt, 'post-summary-verification');
|
|
777
|
+
receipt = updateReceipt(repoRoot, receipt, {
|
|
778
|
+
postSummaryVerification: 'done', taskComment: resolvedWarning ? 'pending' : receipt.taskComment,
|
|
779
|
+
warningProjection: warnings.some((warning) => warning.status === 'open') ? 'pending' : 'done', warnings, lastError: null
|
|
780
|
+
});
|
|
781
|
+
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
782
|
+
const warningComment = await syncPendingTaskComment({ repoRoot, taskId, agent: request.agent, receipt, commentSync, consumedCapabilities });
|
|
783
|
+
receipt = warningComment.receipt;
|
|
784
|
+
if (warningComment.step.status !== 'no-op')
|
|
785
|
+
taskComment = warningComment.step;
|
|
786
|
+
changed = changed || warningComment.changed;
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
const error = postSummaryVerification.error ?? { code: 'VERIFY_FAILED', message: 'post-summary verification failed', retryable: true };
|
|
790
|
+
const warnings = replaceWarning(receipt, warningFromError('post-summary-verification', error), 'open');
|
|
791
|
+
receipt = updateReceipt(repoRoot, receipt, { postSummaryVerification: 'pending', taskComment: 'pending', warningProjection: 'pending', warnings, lastError: error });
|
|
792
|
+
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
793
|
+
const warningComment = await syncPendingTaskComment({ repoRoot, taskId, agent: request.agent, receipt, commentSync, consumedCapabilities });
|
|
794
|
+
receipt = warningComment.receipt;
|
|
795
|
+
if (warningComment.step.status !== 'no-op')
|
|
796
|
+
taskComment = warningComment.step;
|
|
797
|
+
changed = changed || warningComment.changed;
|
|
798
|
+
return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification, summary: summary.step, postSummaryVerification }, changed, error);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
catch (error) {
|
|
802
|
+
const detail = errorOf(error, 'POST_SUMMARY_VERIFY_FAILED', true);
|
|
803
|
+
const warnings = replaceWarning(receipt, warningFromError('post-summary-verification', detail), 'open');
|
|
804
|
+
receipt = updateReceipt(repoRoot, receipt, { postSummaryVerification: 'pending', taskComment: 'pending', warningProjection: 'pending', warnings, lastError: detail });
|
|
805
|
+
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
806
|
+
const warningComment = await syncPendingTaskComment({ repoRoot, taskId, agent: request.agent, receipt, commentSync, consumedCapabilities });
|
|
807
|
+
receipt = warningComment.receipt;
|
|
808
|
+
if (warningComment.step.status !== 'no-op')
|
|
809
|
+
taskComment = warningComment.step;
|
|
810
|
+
changed = changed || warningComment.changed;
|
|
811
|
+
return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification, summary: summary.step, postSummaryVerification: { status: 'blocked', changed: false, error: detail } }, changed, detail);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
595
814
|
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
596
|
-
|
|
815
|
+
if (receipt.summary !== 'pending' && receipt.postSummaryVerification !== 'pending' && receipt.warningProjection === 'done' && openWarnings(receipt).length === 0) {
|
|
816
|
+
const resolved = resolveTaskRef(taskId, { repoRoot });
|
|
817
|
+
if (resolved.ok && resolved.state === 'completed')
|
|
818
|
+
clearDeliverySummary(resolved.taskDir);
|
|
819
|
+
}
|
|
820
|
+
return terminalResult(taskId, receipt, { lifecycle: lifecycleResult, taskComment, verification, summary: summary.step, postSummaryVerification }, changed);
|
|
597
821
|
}
|
|
598
822
|
async function applyTaskFinalization(request, options) {
|
|
599
823
|
if (request.intent !== 'complete' || !request.taskRef || !request.agent) {
|
|
@@ -613,5 +837,5 @@ async function applyTaskFinalization(request, options) {
|
|
|
613
837
|
return failed(resolved.taskId, detail);
|
|
614
838
|
}
|
|
615
839
|
}
|
|
616
|
-
export { applyFinalizationReceiptMutation, applyTaskFinalization, issueCapability as createFinalizationCapability, readTaskFinalizationReceipt };
|
|
840
|
+
export { applyFinalizationReceiptMutation, applyTaskFinalization, issueCapability as createFinalizationCapability, readTaskFinalizationReceipt, terminalResult };
|
|
617
841
|
//# sourceMappingURL=finalization.js.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const OPTIONAL_PLATFORM_AUDITS = new Set([
|
|
2
|
+
'closed-status-labels', 'status-label', 'comment-marker', 'pr-comment-marker',
|
|
3
|
+
'pr-comment-last-commit', 'pr-comment-content', 'comment-content', 'task-comment-content',
|
|
4
|
+
'in-labels-computed', 'pr-type-label', 'in-labels-match-pr', 'pr-assignee',
|
|
5
|
+
'requirements', 'issue-type', 'issue-fields', 'milestone'
|
|
6
|
+
]);
|
|
7
|
+
const STATUS_LABELS = {
|
|
8
|
+
'create-task': 'status: waiting-for-triage',
|
|
9
|
+
'analyze-task': 'status: pending-design-work',
|
|
10
|
+
'review-analysis': 'status: pending-design-work',
|
|
11
|
+
'plan-task': 'status: pending-design-work',
|
|
12
|
+
'review-plan': 'status: pending-design-work',
|
|
13
|
+
'code-task': 'status: in-progress',
|
|
14
|
+
'review-code': 'status: in-progress'
|
|
15
|
+
};
|
|
16
|
+
const ARTIFACT_COMMENT_SKILLS = new Set([
|
|
17
|
+
'analyze-task', 'plan-task', 'review-analysis', 'review-plan', 'code-task',
|
|
18
|
+
'review-code', 'review-pr', 'run-manual-validation'
|
|
19
|
+
]);
|
|
20
|
+
const PR_AUDIT_SKILLS = new Set(['create-pr']);
|
|
21
|
+
const IN_LABEL_AUDIT_SKILLS = new Set(['code-task', 'commit', 'create-pr']);
|
|
22
|
+
export function platformAuditPolicy(checkId, context) {
|
|
23
|
+
const skillName = context.skillName || '';
|
|
24
|
+
const artifactComment = Boolean(context.artifactFile) && ARTIFACT_COMMENT_SKILLS.has(skillName);
|
|
25
|
+
const prAudit = PR_AUDIT_SKILLS.has(skillName);
|
|
26
|
+
const inLabelAudit = IN_LABEL_AUDIT_SKILLS.has(skillName);
|
|
27
|
+
switch (checkId) {
|
|
28
|
+
case 'status-label':
|
|
29
|
+
return { classification: 'soft', enabled: Boolean(STATUS_LABELS[skillName]), expectedStatusLabel: STATUS_LABELS[skillName] };
|
|
30
|
+
case 'comment-marker':
|
|
31
|
+
return {
|
|
32
|
+
classification: 'soft',
|
|
33
|
+
enabled: artifactComment || skillName === 'complete-task',
|
|
34
|
+
...(artifactComment ? { expectedCommentMarkerKey: 'artifact' } : skillName === 'complete-task' ? { expectedCommentMarkerKey: 'summary' } : {})
|
|
35
|
+
};
|
|
36
|
+
case 'pr-comment-marker':
|
|
37
|
+
return {
|
|
38
|
+
classification: 'soft',
|
|
39
|
+
enabled: skillName === 'commit' || prAudit,
|
|
40
|
+
...(skillName === 'commit' || prAudit ? { expectedPrCommentMarkerKey: 'prSummary' } : {})
|
|
41
|
+
};
|
|
42
|
+
case 'pr-comment-last-commit':
|
|
43
|
+
return {
|
|
44
|
+
classification: 'soft',
|
|
45
|
+
enabled: skillName === 'commit',
|
|
46
|
+
...(skillName === 'commit' ? { expectedPrCommentMarkerKey: 'prSummary' } : {})
|
|
47
|
+
};
|
|
48
|
+
case 'pr-comment-content':
|
|
49
|
+
return {
|
|
50
|
+
classification: 'soft',
|
|
51
|
+
enabled: skillName === 'complete-manual-validation',
|
|
52
|
+
...(skillName === 'complete-manual-validation' ? { expectedPrCommentMarkerKey: 'prSummary' } : {})
|
|
53
|
+
};
|
|
54
|
+
case 'comment-content':
|
|
55
|
+
return { classification: 'soft', enabled: artifactComment, expectedCommentMarkerKey: 'artifact' };
|
|
56
|
+
case 'task-comment-content':
|
|
57
|
+
return { classification: 'soft', enabled: true };
|
|
58
|
+
case 'in-labels-computed':
|
|
59
|
+
return { classification: 'soft', enabled: inLabelAudit };
|
|
60
|
+
case 'pr-type-label':
|
|
61
|
+
case 'in-labels-match-pr':
|
|
62
|
+
case 'pr-assignee':
|
|
63
|
+
return { classification: 'soft', enabled: prAudit };
|
|
64
|
+
case 'requirements':
|
|
65
|
+
return { classification: 'soft', enabled: skillName === 'complete-task' };
|
|
66
|
+
case 'milestone':
|
|
67
|
+
return { classification: 'soft', enabled: true, requireSpecificMilestone: skillName === 'code-task' };
|
|
68
|
+
case 'closed-status-labels':
|
|
69
|
+
case 'issue-type':
|
|
70
|
+
case 'issue-fields':
|
|
71
|
+
return { classification: 'soft', enabled: true };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function classificationForCheck(checkId) {
|
|
75
|
+
return checkId.startsWith('platform.') && OPTIONAL_PLATFORM_AUDITS.has(checkId.slice('platform.'.length))
|
|
76
|
+
? 'soft'
|
|
77
|
+
: 'hard';
|
|
78
|
+
}
|
|
79
|
+
export function effectiveStatus(status, classification) {
|
|
80
|
+
return classification === 'hard' ? status : 'pass';
|
|
81
|
+
}
|
|
82
|
+
export function normalizeVerificationRecord(record) {
|
|
83
|
+
const checkId = record.checkId ?? record.type;
|
|
84
|
+
const classification = record.classification ?? classificationForCheck(checkId);
|
|
85
|
+
return {
|
|
86
|
+
...record,
|
|
87
|
+
checkId,
|
|
88
|
+
classification,
|
|
89
|
+
effectiveStatus: record.effectiveStatus ?? effectiveStatus(record.status, classification),
|
|
90
|
+
reason: record.reason ?? record.fail_type ?? (classification === 'info' ? 'NOT_APPLICABLE' : record.status === 'pass' ? 'OK' : 'CHECK_FAILED'),
|
|
91
|
+
action: record.action ?? (classification === 'info' || record.status === 'pass' ? 'No action required' : 'Review the check evidence and retry after correction')
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=gate-policy.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { inspectOrchestrationStage, pauseOrchestration, planOrchestrationStageCompletion
|
|
1
|
+
import { inspectOrchestrationStage, pauseOrchestration, planOrchestrationStageCompletion } from './orchestration.js';
|
|
2
2
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
3
3
|
function failure(mode, code, message) {
|
|
4
4
|
return { ok: false, mode, completionPlan: null, error: { code, message } };
|
|
@@ -8,16 +8,7 @@ function inspectLifecycleExecution(taskRef, request, options = {}) {
|
|
|
8
8
|
if (!resolved.ok)
|
|
9
9
|
return failure(request.mode, resolved.code, resolved.message);
|
|
10
10
|
if (request.mode === 'standalone') {
|
|
11
|
-
|
|
12
|
-
const run = readRun(resolved.taskDir);
|
|
13
|
-
if (run?.pendingDelegation) {
|
|
14
|
-
return failure(request.mode, 'ORCHESTRATION_STANDALONE_BUSY', 'standalone lifecycle execution is blocked by a pending orchestration delegation');
|
|
15
|
-
}
|
|
16
|
-
return { ok: true, mode: request.mode, completionPlan: null, error: null };
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
return failure(request.mode, 'ORCHESTRATION_STATE_INVALID', error instanceof Error ? error.message : String(error));
|
|
20
|
-
}
|
|
11
|
+
return { ok: true, mode: request.mode, completionPlan: null, error: null };
|
|
21
12
|
}
|
|
22
13
|
if (request.agent) {
|
|
23
14
|
const planned = planOrchestrationStageCompletion(taskRef, {
|