@fitlab-ai/agent-infra 0.9.14 → 0.10.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.md +10 -0
- package/README.zh-CN.md +10 -0
- package/bin/internal-cli.sh +45 -0
- package/dist/bin/internal-cli.js +93 -30
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +9 -4
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +43 -3
- package/dist/lib/defaults.json +103 -103
- package/dist/lib/fs/durable-write.js +39 -0
- package/dist/lib/fs/file-lock.js +111 -0
- package/dist/lib/host-control/audit.js +19 -0
- package/dist/lib/host-control/client.js +142 -0
- package/dist/lib/host-control/command.js +49 -0
- package/dist/lib/host-control/path.js +160 -0
- package/dist/lib/host-control/secure-fs.js +140 -0
- package/dist/lib/host-control/server.js +159 -0
- package/dist/lib/host-control/service.js +112 -0
- package/dist/lib/init.js +11 -2
- package/dist/lib/internal/cli-route-inventory.js +4 -2
- package/dist/lib/internal/codex-lifecycle.js +6 -6
- package/dist/lib/internal/demo-promotion.js +322 -0
- package/dist/lib/internal/demo-transcript.js +454 -0
- package/dist/lib/internal/host-control.js +28 -0
- package/dist/lib/internal/manual-validation.js +331 -0
- package/dist/lib/internal/platform-pr.js +18 -4
- package/dist/lib/internal/release-workflow.js +63 -84
- package/dist/lib/internal/sandbox-control.js +149 -2
- package/dist/lib/internal/task-artifact.js +16 -263
- package/dist/lib/internal/task-create.js +6 -5
- package/dist/lib/internal/task-event.js +37 -37
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-operation-registry.js +101 -4
- package/dist/lib/internal/task-review.js +11 -56
- package/dist/lib/internal/task-validate.js +30 -10
- package/dist/lib/owned-path.js +33 -0
- package/dist/lib/platform/check-status.js +11 -0
- package/dist/lib/platform/comment-safety.js +4 -1
- package/dist/lib/platform/completion-backfill.js +1 -1
- package/dist/lib/platform/github-data.js +241 -0
- package/dist/lib/platform/github-provider.js +15 -20
- package/dist/lib/platform/issue-comments.js +18 -12
- package/dist/lib/platform/issues.js +2 -180
- package/dist/lib/platform/pr-change-report.js +5 -4
- package/dist/lib/platform/pr-checks.js +12 -65
- package/dist/lib/platform/pr-summary.js +117 -33
- package/dist/lib/platform/pull-requests.js +5 -108
- package/dist/lib/platform/snapshots.js +2 -0
- package/dist/lib/platform/task-identities.js +2 -9
- package/dist/lib/platform/verification-sync.js +132 -143
- package/dist/lib/pr-review/evidence-grading.js +4 -8
- package/dist/lib/release/workflow.js +1 -1
- package/dist/lib/sandbox/commands/create.js +7 -2
- package/dist/lib/sandbox/commands/rm.js +19 -1511
- package/dist/lib/sandbox/control/audit.js +203 -0
- package/dist/lib/sandbox/control/client.js +93 -54
- package/dist/lib/sandbox/control/executor.js +129 -65
- package/dist/lib/sandbox/control/finalization-response.js +27 -0
- package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
- package/dist/lib/sandbox/control/lifecycle.js +36 -2
- package/dist/lib/sandbox/control/native-file-lock.js +6 -98
- package/dist/lib/sandbox/control/protocol.js +55 -4
- package/dist/lib/sandbox/control/server.js +518 -127
- package/dist/lib/sandbox/control/state.js +64 -0
- package/dist/lib/sandbox/control/task-workflow.js +74 -0
- package/dist/lib/sandbox/control/workflow-executor.js +89 -0
- package/dist/lib/sandbox/index.js +1 -2
- package/dist/lib/sandbox/recovery.js +28 -4
- package/dist/lib/sandbox/removal.js +822 -0
- package/dist/lib/sandbox/task-cleanup.js +217 -0
- package/dist/lib/sandbox/workspace-identity.js +17 -1
- package/dist/lib/sandbox/workspace-view.js +13 -14
- package/dist/lib/task/activity-intent.js +2 -1
- package/dist/lib/task/activity-log.js +30 -24
- package/dist/lib/task/artifact-command.js +79 -0
- package/dist/lib/task/artifact-lifecycle.js +30 -28
- package/dist/lib/task/artifact-name.js +36 -0
- package/dist/lib/task/artifact-operations.js +29 -289
- package/dist/lib/task/artifact-receipts.js +3 -15
- package/dist/lib/task/artifact-recovery.js +430 -0
- package/dist/lib/task/artifact-repair-intent.js +134 -29
- package/dist/lib/task/artifact-schema.js +6 -14
- package/dist/lib/task/capabilities.js +12 -19
- package/dist/lib/task/codex-orchestration.js +71 -25
- package/dist/lib/task/commit-identity.js +28 -0
- package/dist/lib/task/commit-operation.js +33 -20
- package/dist/lib/task/control-authority.js +403 -6
- package/dist/lib/task/control-recovery.js +140 -0
- package/dist/lib/task/create-service.js +1 -8
- package/dist/lib/task/create.js +62 -9
- package/dist/lib/task/decision-details.js +2 -46
- package/dist/lib/task/delegation-receipts.js +64 -3
- package/dist/lib/task/events.js +275 -22
- package/dist/lib/task/finalization-state.js +9 -0
- package/dist/lib/task/human-override.js +8 -14
- package/dist/lib/task/implementation-inputs.js +3 -3
- package/dist/lib/task/intermediate-cleanup.js +441 -0
- package/dist/lib/task/invalidation.js +18 -65
- package/dist/lib/task/ledger-intents.js +7 -22
- package/dist/lib/task/ledger.js +1 -3
- package/dist/lib/task/lifecycle-recovery.js +549 -0
- package/dist/lib/task/lifecycle.js +31 -4
- package/dist/lib/task/local-artifact-finalization.js +197 -197
- package/dist/lib/task/manual-validation-completion.js +26 -0
- package/dist/lib/task/manual-validation-evidence.js +130 -0
- package/dist/lib/task/manual-validation-receipt.js +105 -0
- package/dist/lib/task/manual-validation-shared.js +40 -0
- package/dist/lib/task/manual-validation-transaction.js +243 -0
- package/dist/lib/task/markdown.js +47 -0
- package/dist/lib/task/orchestration.js +66 -19
- package/dist/lib/task/pr-delivery-fact.js +12 -56
- package/dist/lib/task/qualification-audit.js +20 -34
- package/dist/lib/task/recovery-warning.js +19 -0
- package/dist/lib/task/review-artifacts.js +2 -18
- package/dist/lib/task/review-command.js +26 -0
- package/dist/lib/task/review-finalization.js +175 -216
- package/dist/lib/task/review-fingerprint.js +2 -2
- package/dist/lib/task/sections.js +34 -56
- package/dist/lib/task/short-id.js +15 -7
- package/dist/lib/task/task-execution-lock.js +1 -1
- package/dist/lib/task/verification-engine.js +119 -337
- package/dist/lib/task/verification.js +1 -1
- package/dist/lib/task/workflow-command.js +16 -0
- package/dist/lib/task/workflow-warning-intents.js +0 -16
- package/dist/lib/task/workflow-warnings.js +28 -2
- package/dist/lib/update.js +2 -0
- package/dist/lib/version.js +1 -11
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +10 -4
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +55 -3
- package/lib/fs/durable-write.ts +30 -0
- package/lib/fs/file-lock.ts +113 -0
- package/lib/host-control/audit.ts +22 -0
- package/lib/host-control/client.ts +172 -0
- package/lib/host-control/command.ts +60 -0
- package/lib/host-control/path.ts +167 -0
- package/lib/host-control/secure-fs.ts +135 -0
- package/lib/host-control/server.ts +180 -0
- package/lib/host-control/service.ts +133 -0
- package/lib/init.ts +15 -2
- package/lib/internal/cli-route-inventory.ts +4 -2
- package/lib/internal/codex-lifecycle.ts +6 -6
- package/lib/internal/demo-promotion.ts +354 -0
- package/lib/internal/demo-transcript.ts +419 -0
- package/lib/internal/host-control.ts +28 -0
- package/lib/internal/manual-validation.ts +315 -0
- package/lib/internal/platform-pr.ts +15 -4
- package/lib/internal/release-workflow.ts +74 -82
- package/lib/internal/sandbox-control.ts +162 -1
- package/lib/internal/task-artifact.ts +14 -217
- package/lib/internal/task-create.ts +5 -5
- package/lib/internal/task-event.ts +20 -11
- package/lib/internal/task-lifecycle.ts +4 -3
- package/lib/internal/task-operation-registry.ts +111 -4
- package/lib/internal/task-review.ts +9 -54
- package/lib/internal/task-validate.ts +26 -10
- package/lib/owned-path.ts +26 -0
- package/lib/platform/check-status.ts +9 -0
- package/lib/platform/comment-safety.ts +5 -0
- package/lib/platform/completion-backfill.ts +1 -1
- package/lib/platform/github-data.ts +322 -0
- package/lib/platform/github-provider.ts +15 -20
- package/lib/platform/issue-comments.ts +21 -14
- package/lib/platform/issues.ts +5 -246
- package/lib/platform/pr-change-report.ts +7 -5
- package/lib/platform/pr-checks.ts +13 -77
- package/lib/platform/pr-summary.ts +123 -35
- package/lib/platform/pull-requests.ts +6 -173
- package/lib/platform/snapshots.ts +53 -0
- package/lib/platform/task-identities.ts +3 -14
- package/lib/platform/verification-sync.ts +150 -156
- package/lib/pr-review/evidence-grading.ts +4 -9
- package/lib/release/workflow.ts +3 -3
- package/lib/sandbox/commands/create.ts +7 -6
- package/lib/sandbox/commands/rm.ts +21 -1895
- package/lib/sandbox/control/audit.ts +253 -0
- package/lib/sandbox/control/client.ts +109 -66
- package/lib/sandbox/control/executor.ts +134 -74
- package/lib/sandbox/control/finalization-response.ts +29 -0
- package/lib/sandbox/control/identity-sentinel.ts +137 -0
- package/lib/sandbox/control/lifecycle.ts +45 -3
- package/lib/sandbox/control/native-file-lock.ts +6 -107
- package/lib/sandbox/control/protocol.ts +80 -6
- package/lib/sandbox/control/server.ts +567 -132
- package/lib/sandbox/control/state.ts +86 -0
- package/lib/sandbox/control/task-workflow.ts +95 -0
- package/lib/sandbox/control/workflow-executor.ts +92 -0
- package/lib/sandbox/index.ts +1 -2
- package/lib/sandbox/recovery.ts +28 -5
- package/lib/sandbox/removal.ts +1142 -0
- package/lib/sandbox/task-cleanup.ts +209 -0
- package/lib/sandbox/workspace-identity.ts +19 -3
- package/lib/sandbox/workspace-view.ts +17 -15
- package/lib/task/activity-intent.ts +2 -2
- package/lib/task/activity-log.ts +27 -19
- package/lib/task/artifact-command.ts +85 -0
- package/lib/task/artifact-lifecycle.ts +31 -26
- package/lib/task/artifact-name.ts +55 -0
- package/lib/task/artifact-operations.ts +34 -310
- package/lib/task/artifact-receipts.ts +3 -14
- package/lib/task/artifact-recovery.ts +519 -0
- package/lib/task/artifact-repair-intent.ts +162 -33
- package/lib/task/artifact-schema.ts +5 -34
- package/lib/task/capabilities.ts +13 -22
- package/lib/task/codex-orchestration.ts +85 -24
- package/lib/task/commit-identity.ts +31 -0
- package/lib/task/commit-operation.ts +37 -20
- package/lib/task/control-authority.ts +540 -10
- package/lib/task/control-recovery.ts +186 -0
- package/lib/task/create-service.ts +1 -10
- package/lib/task/create.ts +63 -8
- package/lib/task/decision-details.ts +3 -71
- package/lib/task/delegation-receipts.ts +73 -2
- package/lib/task/events.ts +309 -24
- package/lib/task/finalization-state.ts +11 -0
- package/lib/task/human-override.ts +8 -16
- package/lib/task/implementation-inputs.ts +3 -3
- package/lib/task/intermediate-cleanup.ts +493 -0
- package/lib/task/invalidation.ts +18 -62
- package/lib/task/ledger-intents.ts +7 -24
- package/lib/task/ledger.ts +1 -3
- package/lib/task/lifecycle-recovery.ts +691 -0
- package/lib/task/lifecycle.ts +30 -5
- package/lib/task/local-artifact-finalization.ts +244 -234
- package/lib/task/manual-validation-completion.ts +40 -0
- package/lib/task/manual-validation-evidence.ts +209 -0
- package/lib/task/manual-validation-receipt.ts +156 -0
- package/lib/task/manual-validation-shared.ts +50 -0
- package/lib/task/manual-validation-transaction.ts +304 -0
- package/lib/task/markdown.ts +70 -0
- package/lib/task/orchestration.ts +84 -19
- package/lib/task/pr-delivery-fact.ts +15 -62
- package/lib/task/qualification-audit.ts +22 -33
- package/lib/task/recovery-warning.ts +21 -0
- package/lib/task/review-artifacts.ts +1 -20
- package/lib/task/review-command.ts +24 -0
- package/lib/task/review-finalization.ts +183 -292
- package/lib/task/review-fingerprint.ts +2 -2
- package/lib/task/sections.ts +33 -54
- package/lib/task/short-id.ts +27 -5
- package/lib/task/task-execution-lock.ts +1 -1
- package/lib/task/verification-engine.ts +113 -383
- package/lib/task/verification-types.ts +15 -0
- package/lib/task/verification.ts +1 -1
- package/lib/task/workflow-command.ts +17 -0
- package/lib/task/workflow-warning-intents.ts +0 -13
- package/lib/task/workflow-warnings.ts +21 -2
- package/lib/update.ts +6 -0
- package/lib/version.ts +1 -15
- package/package.json +6 -6
- package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
- package/templates/.agents/rules/create-issue.en.md +1 -1
- package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.en.md +4 -2
- package/templates/.agents/rules/issue-sync.zh-CN.md +4 -3
- package/templates/.agents/rules/local-artifact-repair.en.md +46 -39
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +43 -36
- package/templates/.agents/rules/testing-discipline.en.md +2 -0
- package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
- package/templates/.agents/scripts/package.json +3 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +6 -6
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/block-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/block-task/config/verify.json +1 -1
- package/templates/.agents/skills/cancel-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +7 -7
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +7 -7
- package/templates/.agents/skills/code-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +33 -21
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +33 -21
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
- 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 +2 -2
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +2 -2
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +1 -1
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/SKILL.en.md +2 -2
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/create-pr/config/verify.json +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +2 -2
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +2 -2
- package/templates/.agents/skills/create-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/create-task/config/verify.json +1 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +8 -8
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/import-issue/config/verify.json +2 -2
- package/templates/.agents/skills/plan-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/release/SKILL.en.md +7 -3
- package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
- package/templates/.agents/skills/restore-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/restore-task/config/verify.json +1 -1
- 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 -1
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +7 -7
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +6 -6
- package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-code/reference/report-template.en.md +12 -12
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +12 -12
- 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 -1
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +7 -7
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +7 -7
- package/templates/.agents/skills/review-pr/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +3 -3
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +3 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +20 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +20 -3
- package/templates/.agents/skills/run-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/test/SKILL.en.md +17 -6
- package/templates/.agents/skills/test/SKILL.zh-CN.md +17 -6
- package/templates/.agents/templates/task.en.md +1 -1
- package/templates/.agents/templates/task.zh-CN.md +1 -1
- package/templates/.claude/commands/import-issue.en.md +1 -1
- package/templates/.claude/commands/import-issue.zh-CN.md +1 -1
- package/templates/.claude/commands/restore-task.en.md +1 -1
- package/templates/.claude/commands/restore-task.zh-CN.md +1 -1
- package/templates/.claude/commands/run-manual-validation.en.md +1 -1
- package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
- package/dist/lib/platform/adapters.js +0 -56
- package/lib/platform/adapters.ts +0 -197
|
@@ -12,12 +12,16 @@ import { resolveMaterializedReviewedHeadRelation } from "../platform/change-requ
|
|
|
12
12
|
import { resolveReviewedHeadRelation } from "../platform/merged-pr-equivalence.js";
|
|
13
13
|
import { resolveLocalReviewedCommitRelation } from "../git/reviewed-commit-equivalence.js";
|
|
14
14
|
import { parseTypedTaskFrontmatter } from "./frontmatter.js";
|
|
15
|
-
import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.js";
|
|
15
|
+
import { LEDGER_TERMINAL, LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.js";
|
|
16
16
|
import { isValidAgentInfraVersion } from "../version.js";
|
|
17
17
|
import { equalCounts, parseReviewSummary } from "./review-artifacts.js";
|
|
18
18
|
import { inspectDecisionDetailDuplicates } from "./decision-details.js";
|
|
19
|
+
import { parseImplementationInputs } from "./implementation-inputs.js";
|
|
20
|
+
import { scanVisibleMarkdown } from "./markdown.js";
|
|
19
21
|
import { loadVerificationConfig } from "./verification-config.js";
|
|
20
22
|
import { snapshotReview } from "../git/review-snapshot.js";
|
|
23
|
+
import { inspectActivityLog } from "./activity-log.js";
|
|
24
|
+
import { parseWorkflowWarnings } from "./workflow-warnings.js";
|
|
21
25
|
import { OrchestrationStateError, readRun } from "./orchestration.js";
|
|
22
26
|
import { resolveDeliveryTarget } from "./delivery-target.js";
|
|
23
27
|
import { readPrDeliveryFact } from "./pr-delivery-fact.js";
|
|
@@ -25,6 +29,11 @@ import { validateLocalArtifact } from "./local-artifact-finalization.js";
|
|
|
25
29
|
import { validateQualificationAudit } from "./qualification-audit.js";
|
|
26
30
|
import { getArtifactSchema } from "./artifact-schema.js";
|
|
27
31
|
import { inspectArtifactContract } from "./artifact-operations.js";
|
|
32
|
+
import { manualValidationFinalSummaryProjectionMatches } from "./manual-validation-receipt.js";
|
|
33
|
+
import { readManualValidationCompletion } from "./manual-validation-completion.js";
|
|
34
|
+
import { sha256File } from "./artifact-receipts.js";
|
|
35
|
+
import { summaryCommentState } from "../platform/pr-summary.js";
|
|
36
|
+
import { taskIssueIdentity } from "../platform/task-identities.js";
|
|
28
37
|
const TASK_ENUMS = {
|
|
29
38
|
type: ["feature", "bugfix", "refactor", "docs", "chore"],
|
|
30
39
|
workflow: ["feature-development", "bug-fix", "refactoring"],
|
|
@@ -42,7 +51,6 @@ const DEFAULT_REQUIRED_FIELDS = [
|
|
|
42
51
|
"assigned_to"
|
|
43
52
|
];
|
|
44
53
|
const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
|
|
45
|
-
const ACTIVITY_LOG_PATTERN = /^- (\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?) — \*\*(.+?)\*\* by (.+?) — (.+)$/;
|
|
46
54
|
// Start markers (action suffixed with ` [started]`) are excluded from the
|
|
47
55
|
// "latest action" / freshness computation so a step's in-flight marker never
|
|
48
56
|
// satisfies a skill's expected_action_pattern; the matching done entry does.
|
|
@@ -50,27 +58,11 @@ const ACTIVITY_LOG_STARTED_RE = /\s*\[started\]\s*$/;
|
|
|
50
58
|
const BRANCH_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
51
59
|
// Review disagreement ledger (see .agents/rules/review-handshake.md).
|
|
52
60
|
const LEDGER_SECTION_NAMES = ["审查分歧账本", "Review Disagreement Ledger"];
|
|
53
|
-
const LEDGER_STATUSES = new Set([
|
|
54
|
-
"open",
|
|
55
|
-
"accepted",
|
|
56
|
-
"adjusted",
|
|
57
|
-
"refuted",
|
|
58
|
-
"cannot-judge",
|
|
59
|
-
"confirmed",
|
|
60
|
-
"needs-human-decision",
|
|
61
|
-
"closed",
|
|
62
|
-
"human-decided"
|
|
63
|
-
]);
|
|
64
|
-
const LEDGER_TERMINAL_OK = new Set(["confirmed", "closed", "human-decided"]);
|
|
65
61
|
const DEFAULT_MAX_HANDSHAKE_ROUNDS = 3;
|
|
66
62
|
const POST_REVIEW_COMMIT_STAGE = "post-review-commit";
|
|
67
63
|
const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
|
|
68
|
-
const WORKFLOW_WARNING_SECTION_NAMES = ["工作流告警", "Workflow Warnings"];
|
|
69
|
-
const WORKFLOW_WARNING_STATUSES = new Set(["open", "resolved", "ignored"]);
|
|
70
|
-
const WORKFLOW_WARNING_SEVERITIES = new Set(["IMPORTANT", "ACTION_REQUIRED"]);
|
|
71
|
-
const WORKFLOW_WARNING_ID_PATTERN = /^WW-\d+$/;
|
|
72
64
|
const scriptPath = fileURLToPath(import.meta.url);
|
|
73
|
-
|
|
65
|
+
const defaultRepoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
|
|
74
66
|
const PLATFORM_ADAPTERS = {
|
|
75
67
|
"platform-sync": checkPlatformSync,
|
|
76
68
|
"platform-sync-preflight": async (context, shared) => ({ ...await checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
|
|
@@ -87,8 +79,6 @@ const sharedUtils = {
|
|
|
87
79
|
failResult,
|
|
88
80
|
blockedResult,
|
|
89
81
|
safeStat,
|
|
90
|
-
parseIssueNumber,
|
|
91
|
-
parsePrNumber
|
|
92
82
|
};
|
|
93
83
|
async function runCheck(type, context, shared) {
|
|
94
84
|
switch (type) {
|
|
@@ -175,14 +165,12 @@ function exactText(value) {
|
|
|
175
165
|
function validateCleanCompletionEvidence(run) {
|
|
176
166
|
const evidence = run.completionEvidence;
|
|
177
167
|
const shaPattern = /^[0-9a-f]{40}$/i;
|
|
178
|
-
if (evidence
|
|
179
|
-
|| !exactText(evidence.observedAt)
|
|
168
|
+
if (!evidence
|
|
180
169
|
|| Number.isNaN(Date.parse(evidence.observedAt))
|
|
181
170
|
|| !shaPattern.test(evidence.head)
|
|
182
171
|
|| !shaPattern.test(evidence.headTree)
|
|
183
172
|
|| !shaPattern.test(evidence.worktreeTree)
|
|
184
173
|
|| !shaPattern.test(evidence.lastReviewedCommit)
|
|
185
|
-
|| !(evidence.prNumber === null || (Number.isInteger(evidence.prNumber) && evidence.prNumber > 0))
|
|
186
174
|
|| !(evidence.prHead === null || shaPattern.test(evidence.prHead))) {
|
|
187
175
|
return 'Clean completion evidence has an invalid structure';
|
|
188
176
|
}
|
|
@@ -195,7 +183,6 @@ function validateCleanCompletionEvidence(run) {
|
|
|
195
183
|
|| run.pendingDelegation !== null
|
|
196
184
|
|| run.commitAuthorization?.issuedAt !== null
|
|
197
185
|
|| run.commitAuthorization?.consumedAt !== null
|
|
198
|
-
|| !Array.isArray(run.receipts)
|
|
199
186
|
|| run.receipts.some((receipt) => receipt.stage === 'commit')) {
|
|
200
187
|
return 'Clean completion evidence conflicts with commit delegation state';
|
|
201
188
|
}
|
|
@@ -214,43 +201,10 @@ function checkOrchestrationEvidence({ taskDir }) {
|
|
|
214
201
|
const message = error instanceof OrchestrationStateError ? error.message : String(error);
|
|
215
202
|
return failResult('orchestration-evidence', `Invalid orchestration.json: ${message}`);
|
|
216
203
|
}
|
|
204
|
+
if (!run)
|
|
205
|
+
return failResult('orchestration-evidence', 'orchestration.json is missing');
|
|
206
|
+
// readRun validates the persisted schema, receipt identities and client provenance.
|
|
217
207
|
const policy = run.modelPolicy;
|
|
218
|
-
if (!policy
|
|
219
|
-
|| !exactText(policy.executor?.model)
|
|
220
|
-
|| !exactText(policy.executor?.reasoningEffort)
|
|
221
|
-
|| !exactText(policy.reviewer?.model)
|
|
222
|
-
|| !exactText(policy.reviewer?.reasoningEffort)) {
|
|
223
|
-
return failResult('orchestration-evidence', 'Run model policy requires exact executor and reviewer model and effort');
|
|
224
|
-
}
|
|
225
|
-
if (!run.modelPolicySource
|
|
226
|
-
|| !['explicit', 'project-config'].includes(run.modelPolicySource.kind)
|
|
227
|
-
|| !exactText(run.modelPolicySource.client)
|
|
228
|
-
|| !exactText(run.modelPolicySource.resolvedAt)
|
|
229
|
-
|| !Array.isArray(run.recoveryHistory)) {
|
|
230
|
-
return failResult('orchestration-evidence', 'Run model policy source or recovery history is invalid');
|
|
231
|
-
}
|
|
232
|
-
for (const recovery of run.recoveryHistory) {
|
|
233
|
-
const guards = recovery.guards;
|
|
234
|
-
const validClaudeCodeRecovery = recovery.code === 'CLIENT_CAPABILITY_ENABLED'
|
|
235
|
-
&& recovery.previousStatus === 'paused'
|
|
236
|
-
&& recovery.previousPause?.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED'
|
|
237
|
-
&& recovery.client === 'claude-code'
|
|
238
|
-
&& recovery.resultingStatus === 'running'
|
|
239
|
-
&& exactText(recovery.recoveredAt)
|
|
240
|
-
&& guards?.stepCount === 0
|
|
241
|
-
&& guards?.nextStage === null
|
|
242
|
-
&& guards?.baselineEmpty === true
|
|
243
|
-
&& guards?.receiptCount === 0
|
|
244
|
-
&& guards?.pendingDelegation === false
|
|
245
|
-
&& guards?.commitAuthorizationUnused === true
|
|
246
|
-
&& guards?.completionEvidenceAbsent === true;
|
|
247
|
-
if (!validClaudeCodeRecovery) {
|
|
248
|
-
return failResult('orchestration-evidence', 'Run recovery history contains invalid provenance');
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
if (!Array.isArray(run.receipts)) {
|
|
252
|
-
return failResult('orchestration-evidence', 'Run receipts must be an array');
|
|
253
|
-
}
|
|
254
208
|
if (run.completionEvidence != null) {
|
|
255
209
|
const evidenceError = validateCleanCompletionEvidence(run);
|
|
256
210
|
if (evidenceError)
|
|
@@ -282,10 +236,6 @@ function checkOrchestrationEvidence({ taskDir }) {
|
|
|
282
236
|
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has no host-observed actual reasoning effort`);
|
|
283
237
|
}
|
|
284
238
|
}
|
|
285
|
-
// parentId/childId 校验对所有 client 保持统一(不新增分支);spawnMode 检查按 client 判断
|
|
286
|
-
if (!exactText(receipt.parentId) || !exactText(receipt.childId) || receipt.parentId === receipt.childId) {
|
|
287
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid delegation identity`);
|
|
288
|
-
}
|
|
289
239
|
if (!isClaudeCode && receipt.spawnMode !== 'fresh') {
|
|
290
240
|
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid fresh delegation identity`);
|
|
291
241
|
}
|
|
@@ -307,41 +257,6 @@ function checkOrchestrationEvidence({ taskDir }) {
|
|
|
307
257
|
&& receipt.reasoningEffortFallbackReason !== null) {
|
|
308
258
|
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has an unrelated reasoning-effort fallback reason`);
|
|
309
259
|
}
|
|
310
|
-
if (receipt.client === 'codex') {
|
|
311
|
-
const activatedCodex = ['activated', 'stage-completed', 'sealed', 'consumed'].includes(receipt.status);
|
|
312
|
-
const host = receipt.hostEvidence;
|
|
313
|
-
const provenance = receipt.lifecycleProvenance;
|
|
314
|
-
if (!provenance
|
|
315
|
-
|| (activatedCodex && (host?.kind !== 'codex-lifecycle-v2'
|
|
316
|
-
|| host.protocolVersion !== provenance.protocolVersion
|
|
317
|
-
|| host.hookDefinitionHash !== provenance.hookDefinitionHash
|
|
318
|
-
|| host.hookSource !== provenance.hookSource
|
|
319
|
-
|| host.hookSourcePathDigest !== provenance.hookSourcePathDigest
|
|
320
|
-
|| host.hookSourceHash !== provenance.hookSourceHash
|
|
321
|
-
|| host.capabilitySessionId !== provenance.capabilitySessionId
|
|
322
|
-
|| receipt.parentId !== provenance.capabilitySessionId
|
|
323
|
-
|| host.capabilityTurnId !== provenance.capabilityTurnId
|
|
324
|
-
|| host.controllerInstanceDigest !== provenance.controllerInstanceDigest
|
|
325
|
-
|| host.controlGeneration !== provenance.controlGeneration
|
|
326
|
-
|| host.spawnToolUseId === provenance.capabilityToolUseId
|
|
327
|
-
|| !exactText(host.spawnToolUseId)
|
|
328
|
-
|| !Number.isFinite(Date.parse(host.spawnObservedAt ?? ''))
|
|
329
|
-
|| !Number.isFinite(Date.parse(receipt.spawnDispatchedAt ?? ''))
|
|
330
|
-
|| !Number.isFinite(Date.parse(receipt.activationDeadlineAt ?? ''))
|
|
331
|
-
|| Date.parse(host.spawnObservedAt ?? '') < Date.parse(receipt.spawnDispatchedAt ?? '')
|
|
332
|
-
|| Date.parse(host.spawnObservedAt ?? '') > Date.parse(receipt.activationDeadlineAt ?? '')
|
|
333
|
-
|| !exactText(host.hookDefinitionHash)
|
|
334
|
-
|| !Number.isSafeInteger(host.startRevision)
|
|
335
|
-
|| host.startRevision < 1))) {
|
|
336
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid Codex start evidence`);
|
|
337
|
-
}
|
|
338
|
-
if (['sealed', 'consumed'].includes(receipt.status) && (!Number.isSafeInteger(host.stopRevision)
|
|
339
|
-
|| host.stopRevision <= host.startRevision
|
|
340
|
-
|| host.consumer !== receipt.id
|
|
341
|
-
|| !exactText(host.consumedAt))) {
|
|
342
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid Codex consumed stop evidence`);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
260
|
}
|
|
346
261
|
}
|
|
347
262
|
if (run.receipts.some((receipt) => receipt.status !== 'consumed')) {
|
|
@@ -350,7 +265,7 @@ function checkOrchestrationEvidence({ taskDir }) {
|
|
|
350
265
|
return passResult('orchestration-evidence', 'Persisted orchestration model and delegation evidence is internally consistent');
|
|
351
266
|
}
|
|
352
267
|
// === Check Functions ===
|
|
353
|
-
function checkTaskMeta({ taskDir, config }) {
|
|
268
|
+
function checkTaskMeta({ taskDir, config, repositoryRoot }) {
|
|
354
269
|
const task = loadTask(taskDir);
|
|
355
270
|
if (!task.ok) {
|
|
356
271
|
return failResult("task-meta", task.message);
|
|
@@ -380,13 +295,15 @@ function checkTaskMeta({ taskDir, config }) {
|
|
|
380
295
|
return failResult("task-meta", `Invalid ${field}: ${metadata[field]}`);
|
|
381
296
|
}
|
|
382
297
|
}
|
|
383
|
-
const branchValidationError = validateTaskBranch(metadata);
|
|
298
|
+
const branchValidationError = validateTaskBranch(metadata, repositoryRoot);
|
|
384
299
|
if (branchValidationError) {
|
|
385
300
|
return failResult("task-meta", branchValidationError);
|
|
386
301
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
302
|
+
try {
|
|
303
|
+
parseWorkflowWarnings(task.content);
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
return failResult("task-meta", `Invalid Workflow Warnings: ${error instanceof Error ? error.message : String(error)}`);
|
|
390
307
|
}
|
|
391
308
|
const expectedStep = config.expected_step;
|
|
392
309
|
if (expectedStep && metadata.current_step !== expectedStep) {
|
|
@@ -396,8 +313,8 @@ function checkTaskMeta({ taskDir, config }) {
|
|
|
396
313
|
if (expectedStatus && metadata.status !== expectedStatus) {
|
|
397
314
|
return failResult("task-meta", `Expected status '${expectedStatus}', got '${metadata.status || "(empty)"}'`);
|
|
398
315
|
}
|
|
399
|
-
if (config.
|
|
400
|
-
return failResult("task-meta", "Expected a valid
|
|
316
|
+
if (config.require_platform_issue_identity && !taskIssueIdentity(metadata)) {
|
|
317
|
+
return failResult("task-meta", "Expected a valid platform_issue_identity in task metadata");
|
|
401
318
|
}
|
|
402
319
|
if (config.require_completed_at && isBlank(metadata.completed_at)) {
|
|
403
320
|
return failResult("task-meta", "Expected completed_at to be present");
|
|
@@ -481,11 +398,11 @@ async function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }) {
|
|
|
481
398
|
}
|
|
482
399
|
return passResult('required-pr-delivery', `Pull request delivery policy satisfied (${status})`);
|
|
483
400
|
}
|
|
484
|
-
function validateTaskBranch(metadata) {
|
|
401
|
+
function validateTaskBranch(metadata, repoRoot) {
|
|
485
402
|
if (isBlank(metadata.branch)) {
|
|
486
403
|
return null;
|
|
487
404
|
}
|
|
488
|
-
const projectName = loadProjectName();
|
|
405
|
+
const projectName = loadProjectName(repoRoot);
|
|
489
406
|
const expectedPrefix = projectName ? `${projectName}-${metadata.type}-` : "";
|
|
490
407
|
if (expectedPrefix && !String(metadata.branch).startsWith(expectedPrefix)) {
|
|
491
408
|
return `Invalid branch: expected prefix '${expectedPrefix}', got '${metadata.branch}'`;
|
|
@@ -496,7 +413,7 @@ function validateTaskBranch(metadata) {
|
|
|
496
413
|
}
|
|
497
414
|
return null;
|
|
498
415
|
}
|
|
499
|
-
function loadProjectName() {
|
|
416
|
+
function loadProjectName(repoRoot) {
|
|
500
417
|
const configPath = path.join(repoRoot, ".agents", ".airc.json");
|
|
501
418
|
if (!fs.existsSync(configPath)) {
|
|
502
419
|
return "";
|
|
@@ -647,30 +564,17 @@ function checkImplementationInput({ taskDir, artifactFile }) {
|
|
|
647
564
|
const artifactPath = path.join(taskDir, artifactFile);
|
|
648
565
|
if (!safeStat(artifactPath)?.isFile())
|
|
649
566
|
return failResult("implementation-input", `Artifact not found: ${artifactFile}`);
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
const table = inputSection.split(/\r?\n/).filter((line) => line.trim().startsWith("|"));
|
|
654
|
-
const cells = (line) => line.split("|").slice(1, -1).map((cell) => cell.trim());
|
|
655
|
-
const expected = ["id", "ledger_id", "decision_evidence", "stage", "needs_implementation", "decided_at", "status", "consumed_by"];
|
|
656
|
-
if (table.length < 2 || JSON.stringify(cells(table[0])) !== JSON.stringify(expected)) {
|
|
657
|
-
return failResult("implementation-input", "Implementation Inputs table schema is invalid");
|
|
658
|
-
}
|
|
659
|
-
const seen = new Set();
|
|
660
|
-
for (const line of table.slice(2)) {
|
|
661
|
-
const row = cells(line);
|
|
662
|
-
if (row.length !== 8 || !/^II-[1-9]\d*$/.test(row[0]) || seen.has(row[0])) {
|
|
663
|
-
return failResult("implementation-input", "Implementation Inputs table contains an invalid or duplicate id");
|
|
664
|
-
}
|
|
665
|
-
seen.add(row[0]);
|
|
666
|
-
rows.push({ id: row[0], ledgerId: row[1], evidence: row[2], stage: row[3], needs: row[4], status: row[6], consumedBy: row[7] });
|
|
667
|
-
}
|
|
567
|
+
let rows;
|
|
568
|
+
try {
|
|
569
|
+
rows = parseImplementationInputs(task.content).rows;
|
|
668
570
|
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
571
|
+
catch (error) {
|
|
572
|
+
return failResult("implementation-input", `Invalid Implementation Inputs: ${error instanceof Error ? error.message : String(error)}`);
|
|
573
|
+
}
|
|
574
|
+
const doneActions = (inspectActivityLog(task.content).section?.entries ?? [])
|
|
575
|
+
.filter((entry) => !ACTIVITY_LOG_STARTED_RE.test(entry.step))
|
|
576
|
+
.map((entry) => entry.step)
|
|
577
|
+
.filter((step) => /^(?:Code Task|Code) \(Round \d+/.test(step));
|
|
674
578
|
const latestAction = doneActions.at(-1) || "";
|
|
675
579
|
const actionDecision = /(?:Code Task|Code) \(Round \d+, decision (II-[1-9]\d*)\)/.exec(latestAction)?.[1] || null;
|
|
676
580
|
const report = fs.readFileSync(artifactPath, "utf8");
|
|
@@ -698,10 +602,10 @@ function checkImplementationInput({ taskDir, artifactFile }) {
|
|
|
698
602
|
if (matches.length !== 1)
|
|
699
603
|
return failResult("implementation-input", `${actionDecision} is missing or duplicated in task table`);
|
|
700
604
|
const row = matches[0];
|
|
701
|
-
if (row.stage !== "code" || row.
|
|
605
|
+
if (row.stage !== "code" || !row.needsImplementation || row.status !== "consumed" || row.consumedBy !== artifactFile || !row.decisionEvidence) {
|
|
702
606
|
return failResult("implementation-input", `${actionDecision} is not a consumed input for ${artifactFile}`);
|
|
703
607
|
}
|
|
704
|
-
if (reportLedger !== row.ledgerId || reportEvidence !== row.
|
|
608
|
+
if (reportLedger !== row.ledgerId || reportEvidence !== row.decisionEvidence) {
|
|
705
609
|
return failResult("implementation-input", `${actionDecision} report identity does not match task table evidence`);
|
|
706
610
|
}
|
|
707
611
|
return passResult("implementation-input", `${actionDecision} matches Activity Log, report, and task table`);
|
|
@@ -711,27 +615,22 @@ function checkActivityLog({ taskDir, config }) {
|
|
|
711
615
|
if (!task.ok) {
|
|
712
616
|
return failResult("activity-log", task.message);
|
|
713
617
|
}
|
|
714
|
-
const
|
|
715
|
-
if (!
|
|
716
|
-
return failResult("activity-log", "Activity Log section not found");
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
.filter((line) => line.startsWith("- "));
|
|
722
|
-
if (entries.length === 0) {
|
|
618
|
+
const { section, invalidEntries } = inspectActivityLog(task.content);
|
|
619
|
+
if (!section)
|
|
620
|
+
return failResult("activity-log", "Activity Log section not found or ambiguous");
|
|
621
|
+
if (invalidEntries.length)
|
|
622
|
+
return failResult("activity-log", `Invalid Activity Log entry format: ${invalidEntries[0]}`);
|
|
623
|
+
const entries = section.entries;
|
|
624
|
+
if (entries.length === 0)
|
|
723
625
|
return failResult("activity-log", "Activity Log has no entries");
|
|
724
|
-
}
|
|
725
626
|
let previousTimestamp = "";
|
|
726
627
|
let latestAction = "";
|
|
727
628
|
let latestTimestamp = "";
|
|
728
629
|
const doneActions = [];
|
|
729
630
|
for (const entry of entries) {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
}
|
|
734
|
-
const [, timestamp, action] = match;
|
|
631
|
+
if (!entry.note.trim())
|
|
632
|
+
return failResult("activity-log", "Activity Log entry note is required");
|
|
633
|
+
const { time: timestamp, step: action } = entry;
|
|
735
634
|
if (previousTimestamp && timestamp < previousTimestamp) {
|
|
736
635
|
return failResult("activity-log", "Activity Log timestamps are not in ascending order");
|
|
737
636
|
}
|
|
@@ -786,111 +685,7 @@ function checkCompletionChecklist({ taskDir, config }) {
|
|
|
786
685
|
}
|
|
787
686
|
return passResult("completion-checklist", `Completion Checklist valid (${items.length} items checked)`);
|
|
788
687
|
}
|
|
789
|
-
function
|
|
790
|
-
let value = String(line || "").trim();
|
|
791
|
-
if (!value.startsWith("|")) {
|
|
792
|
-
return [];
|
|
793
|
-
}
|
|
794
|
-
value = value.replace(/^\|/, "").replace(/\|$/, "");
|
|
795
|
-
const cells = [];
|
|
796
|
-
let cell = "";
|
|
797
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
798
|
-
const char = value[index];
|
|
799
|
-
if (char === "|" && !isEscapedAt(value, index)) {
|
|
800
|
-
cells.push(unescapeMarkdownTableCell(cell.trim()));
|
|
801
|
-
cell = "";
|
|
802
|
-
continue;
|
|
803
|
-
}
|
|
804
|
-
cell += char;
|
|
805
|
-
}
|
|
806
|
-
cells.push(unescapeMarkdownTableCell(cell.trim()));
|
|
807
|
-
return cells;
|
|
808
|
-
}
|
|
809
|
-
function unescapeMarkdownTableCell(value) {
|
|
810
|
-
let output = "";
|
|
811
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
812
|
-
const char = value[index];
|
|
813
|
-
const next = value[index + 1];
|
|
814
|
-
if (char === "\\" && (next === "\\" || next === "|")) {
|
|
815
|
-
output += next;
|
|
816
|
-
index += 1;
|
|
817
|
-
continue;
|
|
818
|
-
}
|
|
819
|
-
output += char;
|
|
820
|
-
}
|
|
821
|
-
return output;
|
|
822
|
-
}
|
|
823
|
-
function isEscapedAt(value, index) {
|
|
824
|
-
let backslashes = 0;
|
|
825
|
-
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
826
|
-
backslashes += 1;
|
|
827
|
-
}
|
|
828
|
-
return backslashes % 2 === 1;
|
|
829
|
-
}
|
|
830
|
-
function parseWorkflowWarningRows(section) {
|
|
831
|
-
const rows = [];
|
|
832
|
-
for (const rawLine of String(section || "").split(/\r?\n/)) {
|
|
833
|
-
const cells = splitMarkdownTableRow(rawLine);
|
|
834
|
-
if (cells.length === 0) {
|
|
835
|
-
continue;
|
|
836
|
-
}
|
|
837
|
-
if ((cells[0] || "").toLowerCase() === "id") {
|
|
838
|
-
continue;
|
|
839
|
-
}
|
|
840
|
-
if (cells.every((cell) => /^:?-{3,}:?$/.test(cell))) {
|
|
841
|
-
continue;
|
|
842
|
-
}
|
|
843
|
-
rows.push(cells);
|
|
844
|
-
}
|
|
845
|
-
return rows;
|
|
846
|
-
}
|
|
847
|
-
function validateWorkflowWarnings(content) {
|
|
848
|
-
const section = getSectionContent(content, WORKFLOW_WARNING_SECTION_NAMES);
|
|
849
|
-
if (!section.trim()) {
|
|
850
|
-
return [];
|
|
851
|
-
}
|
|
852
|
-
const rows = parseWorkflowWarningRows(section);
|
|
853
|
-
const errors = [];
|
|
854
|
-
for (const cells of rows) {
|
|
855
|
-
if (cells.length < 11) {
|
|
856
|
-
errors.push(`malformed row (expected 11 columns): ${cells.join(" | ")}`);
|
|
857
|
-
continue;
|
|
858
|
-
}
|
|
859
|
-
const [id, time, step, severity, code, status, target, message, action, resolvedAt, resolution] = cells;
|
|
860
|
-
if (!WORKFLOW_WARNING_ID_PATTERN.test(id)) {
|
|
861
|
-
errors.push(`${id || "(empty id)"}: invalid id`);
|
|
862
|
-
}
|
|
863
|
-
if (!DATE_TIME_PATTERN.test(time)) {
|
|
864
|
-
errors.push(`${id}: invalid time '${time}'`);
|
|
865
|
-
}
|
|
866
|
-
if (isBlank(step)) {
|
|
867
|
-
errors.push(`${id}: step is required`);
|
|
868
|
-
}
|
|
869
|
-
if (!WORKFLOW_WARNING_SEVERITIES.has(severity)) {
|
|
870
|
-
errors.push(`${id}: illegal severity '${severity}'`);
|
|
871
|
-
}
|
|
872
|
-
if (isBlank(code)) {
|
|
873
|
-
errors.push(`${id}: code is required`);
|
|
874
|
-
}
|
|
875
|
-
if (!WORKFLOW_WARNING_STATUSES.has(status)) {
|
|
876
|
-
errors.push(`${id}: illegal status '${status}'`);
|
|
877
|
-
}
|
|
878
|
-
if (isBlank(target)) {
|
|
879
|
-
errors.push(`${id}: target is required`);
|
|
880
|
-
}
|
|
881
|
-
if (isBlank(message)) {
|
|
882
|
-
errors.push(`${id}: message is required`);
|
|
883
|
-
}
|
|
884
|
-
if (status === "open" && isBlank(action)) {
|
|
885
|
-
errors.push(`${id}: open warning requires action`);
|
|
886
|
-
}
|
|
887
|
-
if ((status === "resolved" || status === "ignored") && (isBlank(resolvedAt) || isBlank(resolution))) {
|
|
888
|
-
errors.push(`${id}: ${status} warning requires resolved_at and resolution`);
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
return errors;
|
|
892
|
-
}
|
|
893
|
-
function resolveReviewSetting(config, key, fallback) {
|
|
688
|
+
function resolveReviewSetting(config, key, fallback, repoRoot) {
|
|
894
689
|
if (config && config[key] !== undefined && config[key] !== null) {
|
|
895
690
|
return config[key];
|
|
896
691
|
}
|
|
@@ -900,7 +695,7 @@ function resolveReviewSetting(config, key, fallback) {
|
|
|
900
695
|
}
|
|
901
696
|
return fallback;
|
|
902
697
|
}
|
|
903
|
-
function checkReviewLedger({ taskDir, config }) {
|
|
698
|
+
function checkReviewLedger({ taskDir, config, repositoryRoot }) {
|
|
904
699
|
const task = loadTask(taskDir);
|
|
905
700
|
if (!task.ok) {
|
|
906
701
|
return failResult("review-ledger", task.message);
|
|
@@ -910,9 +705,7 @@ function checkReviewLedger({ taskDir, config }) {
|
|
|
910
705
|
const ledger = parseLedgerDocument(task.content);
|
|
911
706
|
if (!ledger.present)
|
|
912
707
|
return failResult("review-ledger", `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
|
|
913
|
-
rows = ledger.rows
|
|
914
|
-
row.id, row.stage, row.round, row.severity, row.status, row.evidence
|
|
915
|
-
]);
|
|
708
|
+
rows = ledger.rows;
|
|
916
709
|
}
|
|
917
710
|
catch (error) {
|
|
918
711
|
return failResult("review-ledger", `Invalid disagreement ledger: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -921,15 +714,11 @@ function checkReviewLedger({ taskDir, config }) {
|
|
|
921
714
|
return passResult("review-ledger", "Disagreement ledger has no entries");
|
|
922
715
|
}
|
|
923
716
|
const stageScope = Array.isArray(config.stage_scope) ? config.stage_scope : null;
|
|
924
|
-
const maxRounds = Number(resolveReviewSetting(config, "maxHandshakeRounds", DEFAULT_MAX_HANDSHAKE_ROUNDS));
|
|
717
|
+
const maxRounds = Number(resolveReviewSetting(config, "maxHandshakeRounds", DEFAULT_MAX_HANDSHAKE_ROUNDS, repositoryRoot));
|
|
925
718
|
const problems = [];
|
|
926
719
|
let inScopeCount = 0;
|
|
927
|
-
for (const
|
|
928
|
-
|
|
929
|
-
problems.push(`malformed row (expected 6 columns): ${cells.join(" | ")}`);
|
|
930
|
-
continue;
|
|
931
|
-
}
|
|
932
|
-
const [id, stage, roundRaw, , status, evidence] = cells;
|
|
720
|
+
for (const row of rows) {
|
|
721
|
+
const { id, stage, round: roundRaw, status, evidence } = row;
|
|
933
722
|
const stageScoped = stageScope ? stageScope.includes(stage) : true;
|
|
934
723
|
// post-review-commit exemption rows are consumed by the post-review-commit
|
|
935
724
|
// check, not enforced here.
|
|
@@ -940,8 +729,9 @@ function checkReviewLedger({ taskDir, config }) {
|
|
|
940
729
|
continue;
|
|
941
730
|
}
|
|
942
731
|
inScopeCount += 1;
|
|
943
|
-
|
|
944
|
-
|
|
732
|
+
const invalid = validateLedgerRows([row]);
|
|
733
|
+
if (invalid) {
|
|
734
|
+
problems.push(`${invalid.code}: ${invalid.message}`);
|
|
945
735
|
continue;
|
|
946
736
|
}
|
|
947
737
|
if (status !== "open" && evidence === "") {
|
|
@@ -950,11 +740,11 @@ function checkReviewLedger({ taskDir, config }) {
|
|
|
950
740
|
const round = Number.parseInt(roundRaw, 10);
|
|
951
741
|
if (Number.isFinite(round) &&
|
|
952
742
|
round >= maxRounds &&
|
|
953
|
-
!
|
|
743
|
+
!LEDGER_TERMINAL.has(status) &&
|
|
954
744
|
status !== "needs-human-decision") {
|
|
955
745
|
problems.push(`${id}: round ${round} reached limit ${maxRounds} without convergence; escalate to needs-human-decision`);
|
|
956
746
|
}
|
|
957
|
-
if (!
|
|
747
|
+
if (!LEDGER_TERMINAL.has(status)) {
|
|
958
748
|
problems.push(`${id}: unresolved (status '${status}')`);
|
|
959
749
|
}
|
|
960
750
|
}
|
|
@@ -964,7 +754,7 @@ function checkReviewLedger({ taskDir, config }) {
|
|
|
964
754
|
const scopeLabel = stageScope ? ` for stages [${stageScope.join(", ")}]` : "";
|
|
965
755
|
return passResult("review-ledger", `Disagreement ledger clean (${inScopeCount} in-scope entries terminal${scopeLabel})`);
|
|
966
756
|
}
|
|
967
|
-
function checkManualValidation({ taskDir }) {
|
|
757
|
+
async function checkManualValidation({ taskDir, repositoryRoot }) {
|
|
968
758
|
// 1. Latest review-code artifact; none -> pass (no review, check not applicable).
|
|
969
759
|
const review = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
970
760
|
if (!review.ok) {
|
|
@@ -995,10 +785,23 @@ function checkManualValidation({ taskDir }) {
|
|
|
995
785
|
const task = loadTask(taskDir);
|
|
996
786
|
if (!task.ok)
|
|
997
787
|
return failResult("manual-validation", task.message);
|
|
998
|
-
const
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
788
|
+
const completion = readManualValidationCompletion(taskDir, {
|
|
789
|
+
taskId: task.metadata.id,
|
|
790
|
+
artifact: artifactName
|
|
791
|
+
});
|
|
792
|
+
if (!completion.ok) {
|
|
793
|
+
const source = completion.error.code.startsWith('MANUAL_VALIDATION_RECEIPT_') ? 'receipt' : 'transaction';
|
|
794
|
+
return failResult("manual-validation", `Manual validation ${source} is unavailable: ${completion.error.message}`);
|
|
795
|
+
}
|
|
796
|
+
const { receipt, transaction } = completion.value;
|
|
797
|
+
if (transaction.phase !== "committed" || !transaction.eventAppended || !transaction.postWriteVerified) {
|
|
798
|
+
return failResult("manual-validation", "Manual validation transaction has not reached the committed post-write-verified state");
|
|
799
|
+
}
|
|
800
|
+
if (transaction.pendingSummaryDigest !== receipt.pendingSummaryDigest || transaction.finalSummaryDigest !== receipt.finalSummaryDigest) {
|
|
801
|
+
return failResult("manual-validation", "Manual validation summary digests do not match the committed receipt");
|
|
802
|
+
}
|
|
803
|
+
if (sha256File(resolved.path) !== receipt.artifactSha256) {
|
|
804
|
+
return failResult("manual-validation", `Manual validation artifact digest does not match the receipt for ${artifactName}`);
|
|
1002
805
|
}
|
|
1003
806
|
// 6. Timing correlation (PL-3 fix, PL-4 corrected): the completion entry must
|
|
1004
807
|
// sit AFTER the latest review-code round's completion entry in the
|
|
@@ -1007,21 +810,39 @@ function checkManualValidation({ taskDir }) {
|
|
|
1007
810
|
// which indexOf never matches). Not reusing completed.exec().index: exec
|
|
1008
811
|
// anchors to the first '**Complete Manual Validation**' heading, which can
|
|
1009
812
|
// belong to an earlier round's entry and misorder the standard path.
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
if (
|
|
1020
|
-
return failResult("manual-validation", `Latest review-code (round ${review.round})
|
|
1021
|
-
|
|
1022
|
-
|
|
813
|
+
const inspectedLog = inspectActivityLog(task.content);
|
|
814
|
+
if (!inspectedLog.section)
|
|
815
|
+
return failResult("manual-validation", "Activity Log is missing or invalid");
|
|
816
|
+
const reviewDoneIndex = inspectedLog.section.entries.findIndex((entry) => entry.step === `Review Code (Round ${review.round})`);
|
|
817
|
+
const completedIndex = inspectedLog.section.entries.findIndex((entry) => entry.step === "Complete Manual Validation"
|
|
818
|
+
&& entry.note.includes(`Manual validation passed → ${artifactName};`)
|
|
819
|
+
&& entry.note.includes(`transaction=${receipt.transactionId};`)
|
|
820
|
+
&& entry.note.includes(`receipt=${receipt.receiptDigest};`)
|
|
821
|
+
&& entry.note.includes(`head=${receipt.prHeadSha}`));
|
|
822
|
+
if (reviewDoneIndex === -1)
|
|
823
|
+
return failResult("manual-validation", `Latest review-code (round ${review.round}) completion entry is missing from the Activity Log`);
|
|
824
|
+
if (completedIndex === -1)
|
|
825
|
+
return failResult("manual-validation", `Committed manual validation completion is not recorded for ${artifactName}`);
|
|
826
|
+
if (completedIndex < reviewDoneIndex)
|
|
827
|
+
return failResult("manual-validation", `Latest review-code (round ${review.round}) came after the manual validation completion recorded for ${artifactName}`);
|
|
828
|
+
const fact = readPrDeliveryFact(task.metadata);
|
|
829
|
+
if (fact.status === "invalid")
|
|
830
|
+
return failResult("manual-validation", fact.error.message);
|
|
831
|
+
if (fact.status === "valid" && fact.fact.state === "bound") {
|
|
832
|
+
const inspected = await inspectPlatformPullRequest(task.metadata.id, { cwd: repositoryRoot });
|
|
833
|
+
if (!inspected.pullRequest)
|
|
834
|
+
return failResult("manual-validation", inspected.error?.message ?? "canonical pull-request head is unavailable");
|
|
835
|
+
if (inspected.pullRequest.head.sha !== receipt.prHeadSha)
|
|
836
|
+
return failResult("manual-validation", "manual validation receipt is stale for the current pull-request head");
|
|
837
|
+
const summary = await summaryCommentState(task.metadata.id, { cwd: repositoryRoot });
|
|
838
|
+
if (!summary.comment)
|
|
839
|
+
return failResult("manual-validation", "canonical pull-request summary comment is unavailable");
|
|
840
|
+
if (!manualValidationFinalSummaryProjectionMatches(summary.comment.body, receipt))
|
|
841
|
+
return failResult("manual-validation", "canonical pull-request summary does not match the committed manual validation projection");
|
|
842
|
+
}
|
|
843
|
+
return passResult("manual-validation", `Manual validation completed → ${artifactName} (committed receipt and post-write verification)`);
|
|
1023
844
|
}
|
|
1024
|
-
async function checkPostReviewCommit({ taskDir, config }) {
|
|
845
|
+
async function checkPostReviewCommit({ taskDir, config, repositoryRoot }) {
|
|
1025
846
|
const reviewArtifact = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
1026
847
|
if (!reviewArtifact.ok) {
|
|
1027
848
|
if (reviewArtifact.error)
|
|
@@ -1043,7 +864,7 @@ async function checkPostReviewCommit({ taskDir, config }) {
|
|
|
1043
864
|
return failResult("post-review-commit", factRead.error.message);
|
|
1044
865
|
const fact = factRead.status === 'valid' ? factRead.fact : null;
|
|
1045
866
|
const lastReviewedCommit = task.ok ? (task.metadata.last_reviewed_commit || "").trim() : "";
|
|
1046
|
-
const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(
|
|
867
|
+
const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(repositoryRoot));
|
|
1047
868
|
const hasPullRequest = fact?.state === 'bound';
|
|
1048
869
|
let inspected = null;
|
|
1049
870
|
if (hasPullRequest) {
|
|
@@ -1189,7 +1010,7 @@ function resolvePostReviewExemption(content) {
|
|
|
1189
1010
|
};
|
|
1190
1011
|
}
|
|
1191
1012
|
}
|
|
1192
|
-
function checkReviewFact({ taskDir, artifactFile }) {
|
|
1013
|
+
function checkReviewFact({ taskDir, artifactFile, repositoryRoot }) {
|
|
1193
1014
|
const resolvedArtifact = resolveArtifactPath(taskDir, "review-code.md|review-code-r{N}.md", artifactFile);
|
|
1194
1015
|
if (!resolvedArtifact.ok) {
|
|
1195
1016
|
return failResult("review-fact", resolvedArtifact.message);
|
|
@@ -1255,7 +1076,7 @@ function checkReviewFact({ taskDir, artifactFile }) {
|
|
|
1255
1076
|
mode: "worktree",
|
|
1256
1077
|
baseline,
|
|
1257
1078
|
diffBase,
|
|
1258
|
-
globs: resolvePostReviewGlobs({}, loadPostReviewConfig(
|
|
1079
|
+
globs: resolvePostReviewGlobs({}, loadPostReviewConfig(repositoryRoot))
|
|
1259
1080
|
});
|
|
1260
1081
|
}
|
|
1261
1082
|
catch {
|
|
@@ -1342,40 +1163,12 @@ function resolveArtifactPath(taskDir, filePattern, artifactFile) {
|
|
|
1342
1163
|
return { ok: true, path: path.join(taskDir, matches[0].fileName) };
|
|
1343
1164
|
}
|
|
1344
1165
|
function getSectionContent(content, names) {
|
|
1345
|
-
const
|
|
1346
|
-
function visibleHeadings() {
|
|
1347
|
-
const headings = [];
|
|
1348
|
-
let fence = null;
|
|
1349
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
1350
|
-
const line = lines[index];
|
|
1351
|
-
if (fence) {
|
|
1352
|
-
const closer = line.match(/^ {0,3}(`+|~+)\s*$/);
|
|
1353
|
-
if (closer && closer[1][0] === fence.character && closer[1].length >= fence.length) {
|
|
1354
|
-
fence = null;
|
|
1355
|
-
}
|
|
1356
|
-
continue;
|
|
1357
|
-
}
|
|
1358
|
-
const opener = line.match(/^ {0,3}(`{3,}|~{3,})(?:[^`~].*)?$/);
|
|
1359
|
-
if (opener) {
|
|
1360
|
-
fence = { character: opener[1][0], length: opener[1].length };
|
|
1361
|
-
continue;
|
|
1362
|
-
}
|
|
1363
|
-
if (line.startsWith("## ")) {
|
|
1364
|
-
headings.push({ index, text: line.trim() });
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
return headings;
|
|
1368
|
-
}
|
|
1369
|
-
const headings = visibleHeadings();
|
|
1166
|
+
const headings = scanVisibleMarkdown(content).headings.filter((heading) => heading.level === 2);
|
|
1370
1167
|
for (const name of names) {
|
|
1371
|
-
const
|
|
1372
|
-
|
|
1373
|
-
if (position === -1) {
|
|
1168
|
+
const position = headings.findIndex((heading) => heading.text === name);
|
|
1169
|
+
if (position === -1)
|
|
1374
1170
|
continue;
|
|
1375
|
-
|
|
1376
|
-
const startIndex = headings[position].index;
|
|
1377
|
-
const endIndex = headings[position + 1]?.index ?? lines.length;
|
|
1378
|
-
return lines.slice(startIndex + 1, endIndex).join("\n").trim();
|
|
1171
|
+
return content.slice(headings[position].end + 1, headings[position + 1]?.start ?? content.length).replace(/\r\n/g, "\n").trim();
|
|
1379
1172
|
}
|
|
1380
1173
|
return "";
|
|
1381
1174
|
}
|
|
@@ -1391,16 +1184,6 @@ function getCheckedRequirements(content) {
|
|
|
1391
1184
|
.filter(Boolean)
|
|
1392
1185
|
.map((match) => match[1].trim());
|
|
1393
1186
|
}
|
|
1394
|
-
function parseIssueNumber(value) {
|
|
1395
|
-
if (isBlank(value) || value === "N/A") {
|
|
1396
|
-
return null;
|
|
1397
|
-
}
|
|
1398
|
-
const match = String(value).match(/\d+/);
|
|
1399
|
-
return match ? Number(match[0]) : null;
|
|
1400
|
-
}
|
|
1401
|
-
function parsePrNumber(value) {
|
|
1402
|
-
return parseIssueNumber(value);
|
|
1403
|
-
}
|
|
1404
1187
|
// === Utilities ===
|
|
1405
1188
|
function normalizeContent(text) {
|
|
1406
1189
|
return String(text || "")
|
|
@@ -1479,9 +1262,8 @@ function isBlank(value) {
|
|
|
1479
1262
|
return value === undefined || value === null || String(value).trim() === "";
|
|
1480
1263
|
}
|
|
1481
1264
|
async function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }) {
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
else {
|
|
1265
|
+
let repoRoot = repositoryRoot ? path.resolve(repositoryRoot) : defaultRepoRoot;
|
|
1266
|
+
if (!repositoryRoot) {
|
|
1485
1267
|
let cursor = path.resolve(taskDir);
|
|
1486
1268
|
while (path.dirname(cursor) !== cursor && !fs.existsSync(path.join(cursor, ".agents")))
|
|
1487
1269
|
cursor = path.dirname(cursor);
|