@revisium/orchestrator 0.2.0-alpha.3 → 0.2.0-alpha.4
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 +3 -3
- package/control-plane/bootstrap.config.json +104 -550
- package/control-plane/default-playbook/catalog/pipelines.json +394 -1122
- package/control-plane/default-playbook/catalog/run-profiles.json +208 -0
- package/control-plane/default-playbook/package.json +1 -1
- package/control-plane/default-playbook/playbook.json +2 -1
- package/control-plane/default-playbook/prompts/developer.md +6 -6
- package/dist/__generated__/client/browser.js +18 -0
- package/dist/__generated__/client/browser.js.map +1 -0
- package/dist/__generated__/client/client.js +32 -0
- package/dist/__generated__/client/client.js.map +1 -0
- package/dist/__generated__/client/commonInputTypes.js +11 -0
- package/dist/__generated__/client/commonInputTypes.js.map +1 -0
- package/dist/__generated__/client/enums.js +19 -0
- package/dist/__generated__/client/enums.js.map +1 -0
- package/dist/__generated__/client/internal/class.js +53 -0
- package/dist/__generated__/client/internal/class.js.map +1 -0
- package/dist/__generated__/client/internal/prismaNamespace.js +451 -0
- package/dist/__generated__/client/internal/prismaNamespace.js.map +1 -0
- package/dist/__generated__/client/internal/prismaNamespaceBrowser.js +422 -0
- package/dist/__generated__/client/internal/prismaNamespaceBrowser.js.map +1 -0
- package/dist/__generated__/client/models/Branch.js +2 -0
- package/dist/__generated__/client/models/Branch.js.map +1 -0
- package/dist/__generated__/client/models/CostLedgerEntry.js +2 -0
- package/dist/__generated__/client/models/CostLedgerEntry.js.map +1 -0
- package/dist/__generated__/client/models/FileBlob.js +2 -0
- package/dist/__generated__/client/models/FileBlob.js.map +1 -0
- package/dist/__generated__/client/models/InboxItem.js +2 -0
- package/dist/__generated__/client/models/InboxItem.js.map +1 -0
- package/dist/__generated__/client/models/ProjectFileUsage.js +2 -0
- package/dist/__generated__/client/models/ProjectFileUsage.js.map +1 -0
- package/dist/__generated__/client/models/Revision.js +2 -0
- package/dist/__generated__/client/models/Revision.js.map +1 -0
- package/dist/__generated__/client/models/RevoProject.js +2 -0
- package/dist/__generated__/client/models/RevoProject.js.map +1 -0
- package/dist/__generated__/client/models/Row.js +2 -0
- package/dist/__generated__/client/models/Row.js.map +1 -0
- package/dist/__generated__/client/models/RunAttempt.js +2 -0
- package/dist/__generated__/client/models/RunAttempt.js.map +1 -0
- package/dist/__generated__/client/models/RunEvent.js +2 -0
- package/dist/__generated__/client/models/RunEvent.js.map +1 -0
- package/dist/__generated__/client/models/RunOutput.js +2 -0
- package/dist/__generated__/client/models/RunOutput.js.map +1 -0
- package/dist/__generated__/client/models/RunTask.js +2 -0
- package/dist/__generated__/client/models/RunTask.js.map +1 -0
- package/dist/__generated__/client/models/Table.js +2 -0
- package/dist/__generated__/client/models/Table.js.map +1 -0
- package/dist/__generated__/client/models/TableMigration.js +2 -0
- package/dist/__generated__/client/models/TableMigration.js.map +1 -0
- package/dist/__generated__/client/models/TaskRun.js +2 -0
- package/dist/__generated__/client/models/TaskRun.js.map +1 -0
- package/dist/__generated__/client/models.js +2 -0
- package/dist/__generated__/client/models.js.map +1 -0
- package/dist/api/graphql-api/graphql-ws/pubsub.module.js +2 -1
- package/dist/api/graphql-api/graphql-ws/pubsub.module.js.map +1 -1
- package/dist/api/graphql-api/graphql-ws/subscription-bridge.service.js +110 -28
- package/dist/api/graphql-api/graphql-ws/subscription-bridge.service.js.map +1 -1
- package/dist/api/graphql-api/graphql-ws/subscription-mappers.js +3 -1
- package/dist/api/graphql-api/graphql-ws/subscription-mappers.js.map +1 -1
- package/dist/api/graphql-api/pr/inputs/pr-readiness.input.js +6 -0
- package/dist/api/graphql-api/pr/inputs/pr-readiness.input.js.map +1 -1
- package/dist/api/graphql-api/registerGraphqlEnums.js +2 -0
- package/dist/api/graphql-api/registerGraphqlEnums.js.map +1 -1
- package/dist/api/graphql-api/runs/inputs/create-run.input.js +17 -0
- package/dist/api/graphql-api/runs/inputs/create-run.input.js.map +1 -1
- package/dist/api/graphql-api/runs/inputs/execution-profile.input.js +85 -0
- package/dist/api/graphql-api/runs/inputs/execution-profile.input.js.map +1 -0
- package/dist/api/graphql-api/runs/inputs/simulate-route.input.js +11 -0
- package/dist/api/graphql-api/runs/inputs/simulate-route.input.js.map +1 -1
- package/dist/api/graphql-api/runs/model/run-workflow.model.js +5 -0
- package/dist/api/graphql-api/runs/model/run-workflow.model.js.map +1 -1
- package/dist/api/graphql-api/share/model/issue-action.model.js +7 -0
- package/dist/api/graphql-api/share/model/issue-action.model.js.map +1 -0
- package/dist/cli/commands/doctor-report.js +1 -13
- package/dist/cli/commands/doctor-report.js.map +1 -1
- package/dist/cli/commands/lifecycle.js +50 -65
- package/dist/cli/commands/lifecycle.js.map +1 -1
- package/dist/cli/commands/{revisium-helpers.js → process-helpers.js} +1 -24
- package/dist/cli/commands/process-helpers.js.map +1 -0
- package/dist/config.js +17 -55
- package/dist/config.js.map +1 -1
- package/dist/control-plane/bootstrap-json-validator.js +65 -0
- package/dist/control-plane/bootstrap-json-validator.js.map +1 -0
- package/dist/control-plane/bootstrap.js +25 -38
- package/dist/control-plane/bootstrap.js.map +1 -1
- package/dist/control-plane/change-notifications.js +45 -14
- package/dist/control-plane/change-notifications.js.map +1 -1
- package/dist/control-plane/data-access.js +1 -106
- package/dist/control-plane/data-access.js.map +1 -1
- package/dist/control-plane/default-playbook-policy.js +497 -94
- package/dist/control-plane/default-playbook-policy.js.map +1 -1
- package/dist/control-plane/definitions.js +4 -5
- package/dist/control-plane/definitions.js.map +1 -1
- package/dist/control-plane/engine-transport.js +381 -0
- package/dist/control-plane/engine-transport.js.map +1 -0
- package/dist/control-plane/inbox.js +15 -7
- package/dist/control-plane/inbox.js.map +1 -1
- package/dist/control-plane/index.js +0 -1
- package/dist/control-plane/index.js.map +1 -1
- package/dist/control-plane/merge-override-audit.js +2 -2
- package/dist/control-plane/merge-override-audit.js.map +1 -1
- package/dist/control-plane/pipeline-coverage-registry.js +478 -0
- package/dist/control-plane/pipeline-coverage-registry.js.map +1 -0
- package/dist/control-plane/query-types.js +2 -0
- package/dist/control-plane/query-types.js.map +1 -0
- package/dist/control-plane/run-profiles.js +89 -0
- package/dist/control-plane/run-profiles.js.map +1 -0
- package/dist/control-plane/schema-migration.js +0 -35
- package/dist/control-plane/schema-migration.js.map +1 -1
- package/dist/control-plane/seed-default-playbook.js +2 -31
- package/dist/control-plane/seed-default-playbook.js.map +1 -1
- package/dist/control-plane/tables.js +8 -0
- package/dist/control-plane/tables.js.map +1 -1
- package/dist/control-plane/transport.js +16 -0
- package/dist/control-plane/transport.js.map +1 -0
- package/dist/control-plane/versioned-meaning.js +56 -14
- package/dist/control-plane/versioned-meaning.js.map +1 -1
- package/dist/e2e/kit/agents.js +60 -6
- package/dist/e2e/kit/agents.js.map +1 -1
- package/dist/e2e/kit/assertions.js +13 -1
- package/dist/e2e/kit/assertions.js.map +1 -1
- package/dist/e2e/kit/drive.js +46 -11
- package/dist/e2e/kit/drive.js.map +1 -1
- package/dist/e2e/kit/env.js +17 -1
- package/dist/e2e/kit/env.js.map +1 -1
- package/dist/e2e/kit/fake-integrator.js +25 -5
- package/dist/e2e/kit/fake-integrator.js.map +1 -1
- package/dist/e2e/kit/gh-emulator.js +158 -24
- package/dist/e2e/kit/gh-emulator.js.map +1 -1
- package/dist/e2e/kit/harness.js +44 -10
- package/dist/e2e/kit/harness.js.map +1 -1
- package/dist/e2e/kit/index.js +1 -0
- package/dist/e2e/kit/index.js.map +1 -1
- package/dist/e2e/kit/scenario.js +165 -0
- package/dist/e2e/kit/scenario.js.map +1 -0
- package/dist/e2e/kit/scenarios.js +12 -18
- package/dist/e2e/kit/scenarios.js.map +1 -1
- package/dist/engine/dbos.service.js +8 -1
- package/dist/engine/dbos.service.js.map +1 -1
- package/dist/features/pr/queries/impl/get-pr-readiness.query.js.map +1 -1
- package/dist/features/runs/commands/impl/create-run.command.js.map +1 -1
- package/dist/host/daemon.js +32 -8
- package/dist/host/daemon.js.map +1 -1
- package/dist/host/ensure-host.js +3 -3
- package/dist/host/ensure-host.js.map +1 -1
- package/dist/host/host-runtime.js.map +1 -1
- package/dist/host/host.lifecycle.js +3 -16
- package/dist/host/host.lifecycle.js.map +1 -1
- package/dist/http/graphql-host.js +17 -8
- package/dist/http/graphql-host.js.map +1 -1
- package/dist/mcp/mcp-capabilities.js +3 -2
- package/dist/mcp/mcp-capabilities.js.map +1 -1
- package/dist/mcp/mcp-facade.service.js +21 -0
- package/dist/mcp/mcp-facade.service.js.map +1 -1
- package/dist/mcp/mcp-tools.js +35 -1
- package/dist/mcp/mcp-tools.js.map +1 -1
- package/dist/pipeline/data-driven-task.workflow.js +276 -57
- package/dist/pipeline/data-driven-task.workflow.js.map +1 -1
- package/dist/pipeline/pipeline.service.js +27 -5
- package/dist/pipeline/pipeline.service.js.map +1 -1
- package/dist/pipeline/route-contract.js +123 -3
- package/dist/pipeline/route-contract.js.map +1 -1
- package/dist/pipeline-core/condition-scopes.js +15 -0
- package/dist/pipeline-core/condition-scopes.js.map +1 -0
- package/dist/pipeline-core/index.js +2 -0
- package/dist/pipeline-core/index.js.map +1 -1
- package/dist/pipeline-core/kit/fixtures.js +81 -44
- package/dist/pipeline-core/kit/fixtures.js.map +1 -1
- package/dist/pipeline-core/materialize.js +221 -0
- package/dist/pipeline-core/materialize.js.map +1 -0
- package/dist/pipeline-core/types.js +5 -0
- package/dist/pipeline-core/types.js.map +1 -1
- package/dist/pipeline-core/validate-loops.js +2 -15
- package/dist/pipeline-core/validate-loops.js.map +1 -1
- package/dist/pipeline-core/validate-resilience.js +257 -0
- package/dist/pipeline-core/validate-resilience.js.map +1 -0
- package/dist/pipeline-core/validate.js +2 -0
- package/dist/pipeline-core/validate.js.map +1 -1
- package/dist/playbook/catalog-loader.js +39 -2
- package/dist/playbook/catalog-loader.js.map +1 -1
- package/dist/playbook/catalog-schema-validator.js +438 -0
- package/dist/playbook/catalog-schema-validator.js.map +1 -0
- package/dist/playbook/import-mapper.js +41 -0
- package/dist/playbook/import-mapper.js.map +1 -1
- package/dist/playbook/manifest.js +5 -0
- package/dist/playbook/manifest.js.map +1 -1
- package/dist/playbook/playbook-installer.js +17 -1
- package/dist/playbook/playbook-installer.js.map +1 -1
- package/dist/poller/pr-readiness-core.js +257 -93
- package/dist/poller/pr-readiness-core.js.map +1 -1
- package/dist/poller/pr-readiness.js +2 -2
- package/dist/poller/pr-readiness.js.map +1 -1
- package/dist/revisium/inbox.service.js +8 -8
- package/dist/revisium/inbox.service.js.map +1 -1
- package/dist/revisium/playbooks.service.js +116 -21
- package/dist/revisium/playbooks.service.js.map +1 -1
- package/dist/revisium/revisium.module.js +8 -8
- package/dist/revisium/revisium.module.js.map +1 -1
- package/dist/revisium/roles.service.js +3 -1
- package/dist/revisium/roles.service.js.map +1 -1
- package/dist/revisium/run.service.js +9 -8
- package/dist/revisium/run.service.js.map +1 -1
- package/dist/revisium/tokens.js +0 -1
- package/dist/revisium/tokens.js.map +1 -1
- package/dist/run/create-run.js +1 -1
- package/dist/run/create-run.js.map +1 -1
- package/dist/run/inspect-run.js +32 -28
- package/dist/run/inspect-run.js.map +1 -1
- package/dist/run/issue-ref.js +97 -2
- package/dist/run/issue-ref.js.map +1 -1
- package/dist/run/prisma-runtime-data-access.js +619 -0
- package/dist/run/prisma-runtime-data-access.js.map +1 -0
- package/dist/run/run-outputs.js +39 -14
- package/dist/run/run-outputs.js.map +1 -1
- package/dist/run/terminal-run-status.js.map +1 -1
- package/dist/runners/integrator.js +657 -56
- package/dist/runners/integrator.js.map +1 -1
- package/dist/runners/worktree.service.js +10 -8
- package/dist/runners/worktree.service.js.map +1 -1
- package/dist/schema/ajv-errors.js +15 -0
- package/dist/schema/ajv-errors.js.map +1 -0
- package/dist/smoke/isolation.js +7 -16
- package/dist/smoke/isolation.js.map +1 -1
- package/dist/storage/ensure-storage.js +117 -0
- package/dist/storage/ensure-storage.js.map +1 -0
- package/dist/storage/revo-database.js +39 -0
- package/dist/storage/revo-database.js.map +1 -0
- package/dist/storage/revo-prisma.service.js +31 -0
- package/dist/storage/revo-prisma.service.js.map +1 -0
- package/dist/storage/revo-storage.module.js +18 -0
- package/dist/storage/revo-storage.module.js.map +1 -0
- package/dist/task-control-plane/pr-readiness.service.js +5 -2
- package/dist/task-control-plane/pr-readiness.service.js.map +1 -1
- package/dist/task-control-plane/run-watch.service.js +3 -6
- package/dist/task-control-plane/run-watch.service.js.map +1 -1
- package/dist/task-control-plane/task-control-plane-api.service.js +225 -43
- package/dist/task-control-plane/task-control-plane-api.service.js.map +1 -1
- package/dist/testing/runtime-data-access.js +175 -0
- package/dist/testing/runtime-data-access.js.map +1 -0
- package/dist/worker/build-context.js +178 -2
- package/dist/worker/build-context.js.map +1 -1
- package/dist/worker/claude-code-runner.js +22 -3
- package/dist/worker/claude-code-runner.js.map +1 -1
- package/dist/worker/codex-runner.js +6 -1
- package/dist/worker/codex-runner.js.map +1 -1
- package/package.json +20 -7
- package/prisma/migrations/20260707080500_initial_schema/migration.sql +259 -0
- package/prisma/migrations/20260707103000_prisma_runtime_tables/migration.sql +235 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +339 -0
- package/prisma.config.ts +11 -0
- package/dist/cli/commands/revisium-helpers.js.map +0 -1
- package/dist/control-plane/client-transport.js +0 -168
- package/dist/control-plane/client-transport.js.map +0 -1
- package/dist/engine/ensure-postgres.js +0 -46
- package/dist/engine/ensure-postgres.js.map +0 -1
- package/dist/host/ensure-revisium.js +0 -135
- package/dist/host/ensure-revisium.js.map +0 -1
- package/revisium.config.json +0 -10
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { step as coreStep, initialState, validateTemplate, InterpretError, selectJoinWinner, reduceJoinVerdict, } from '../pipeline-core/index.js';
|
|
2
|
-
import { runnerNeedsLivePreflight, runnerUsesRealIntegrator } from './route-contract.js';
|
|
2
|
+
import { resolveLaunchOverrides, runnerNeedsLivePreflight, runnerUsesRealIntegrator } from './route-contract.js';
|
|
3
3
|
import { redactEventPayload } from '../run/append-event.js';
|
|
4
4
|
import { redactSecrets } from '../control-plane/inbox.js';
|
|
5
5
|
import { fnv1a64Hex } from '../control-plane/steps.js';
|
|
6
|
-
import { normalizeIssueRef } from '../run/issue-ref.js';
|
|
6
|
+
import { normalizeIssueAction, normalizeIssueRef } from '../run/issue-ref.js';
|
|
7
7
|
import { RUNNER_IDLE_TIMEOUT_KIND, RUNNER_WALL_CLOCK_LIMIT_KIND, } from '../worker/process-executor.js';
|
|
8
8
|
export const RUN_PROGRESS_EVENT_KEY = 'run-progress';
|
|
9
|
+
export const INTEGRATOR_PROGRESS_EVENT_TYPES = ['integrate_succeeded', 'foreign_pr_adopted'];
|
|
9
10
|
const MAX_STEPS = 1_000;
|
|
10
11
|
const DEFAULT_RUNNER_TRANSIENT_MAX_ATTEMPTS = 2;
|
|
11
12
|
const DEFAULT_RUNNER_TRANSIENT_RETRY_BACKOFF_MS = 2_000;
|
|
@@ -108,10 +109,12 @@ function producedChangeArtifact(value) {
|
|
|
108
109
|
if (typeof headSha !== 'string' || headSha.trim().length === 0)
|
|
109
110
|
return undefined;
|
|
110
111
|
const issueRef = normalizeArtifactIssueRef(candidate.issueRef);
|
|
112
|
+
const issueAction = normalizeArtifactIssueAction(candidate.issueAction);
|
|
111
113
|
return {
|
|
112
114
|
branch,
|
|
113
115
|
headSha,
|
|
114
116
|
...(issueRef ? { issueRef } : {}),
|
|
117
|
+
...(issueAction ? { issueAction } : {}),
|
|
115
118
|
...(typeof candidate.worktreePath === 'string' && candidate.worktreePath.trim() ? { worktreePath: candidate.worktreePath } : {}),
|
|
116
119
|
...(typeof candidate.artifactRef === 'string' && candidate.artifactRef.trim() ? { artifactRef: candidate.artifactRef } : {}),
|
|
117
120
|
...(typeof candidate.prNumber === 'number' && Number.isSafeInteger(candidate.prNumber) ? { prNumber: candidate.prNumber } : {}),
|
|
@@ -125,7 +128,15 @@ function normalizeArtifactIssueRef(value) {
|
|
|
125
128
|
return undefined;
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
|
-
function
|
|
131
|
+
function normalizeArtifactIssueAction(value) {
|
|
132
|
+
try {
|
|
133
|
+
return normalizeIssueAction(value, 'change.issueAction');
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function changeWithRunIssueContract(change, issueRef, issueAction) {
|
|
129
140
|
const normalized = { ...change };
|
|
130
141
|
if (issueRef) {
|
|
131
142
|
normalized.issueRef = issueRef;
|
|
@@ -133,6 +144,12 @@ function changeWithRunIssueRef(change, issueRef) {
|
|
|
133
144
|
else {
|
|
134
145
|
delete normalized.issueRef;
|
|
135
146
|
}
|
|
147
|
+
if (issueAction) {
|
|
148
|
+
normalized.issueAction = issueAction;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
delete normalized.issueAction;
|
|
152
|
+
}
|
|
136
153
|
return normalized;
|
|
137
154
|
}
|
|
138
155
|
function producedChangeFromInputs(inputs) {
|
|
@@ -150,7 +167,16 @@ function mergeReadinessFromInputs(inputs) {
|
|
|
150
167
|
const headSha = value.headSha;
|
|
151
168
|
if (typeof headSha !== 'string' || headSha.trim().length === 0)
|
|
152
169
|
return undefined;
|
|
153
|
-
|
|
170
|
+
const override = isRecord(value.override) && value.override.accepted === true
|
|
171
|
+
? { accepted: true }
|
|
172
|
+
: undefined;
|
|
173
|
+
return { headSha, ...(override ? { override } : {}) };
|
|
174
|
+
}
|
|
175
|
+
function headShaFromPayload(value) {
|
|
176
|
+
if (!isRecord(value))
|
|
177
|
+
return undefined;
|
|
178
|
+
const headSha = value.headSha;
|
|
179
|
+
return typeof headSha === 'string' && headSha.trim().length > 0 ? headSha.trim() : undefined;
|
|
154
180
|
}
|
|
155
181
|
function attachProducedChange(output, change) {
|
|
156
182
|
if (isRecord(output))
|
|
@@ -275,13 +301,24 @@ function gateVerdict(decision, outcomes) {
|
|
|
275
301
|
return outcomes[0];
|
|
276
302
|
return outcomes.length > 1 ? outcomes.at(-1) : undefined;
|
|
277
303
|
}
|
|
278
|
-
function gateResolutionOutput(decision, verdict, fallbackInboxId) {
|
|
304
|
+
function gateResolutionOutput(decision, verdict, fallbackInboxId, trustedGateHeadSha) {
|
|
305
|
+
const decisionRecord = isRecord(decision) ? decision : {};
|
|
306
|
+
const answer = isRecord(decision.answer) ? decision.answer : {};
|
|
307
|
+
const note = decision.note ?? (typeof answer.note === 'string' ? answer.note : undefined);
|
|
308
|
+
const resolvedBy = decision.resolvedBy ?? (typeof answer.resolvedBy === 'string' ? answer.resolvedBy : '');
|
|
309
|
+
const resolvedAt = decision.resolvedAt ?? (typeof answer.resolvedAt === 'string' ? answer.resolvedAt : '');
|
|
310
|
+
const inboxId = decision.inboxId ?? (typeof answer.inboxId === 'string' ? answer.inboxId : fallbackInboxId);
|
|
311
|
+
const mergeOverrideAudit = answer.mergeOverrideAudit ?? decisionRecord['mergeOverrideAudit'];
|
|
312
|
+
const adoptionAudit = answer.adoptionAudit ?? decisionRecord['adoptionAudit'];
|
|
279
313
|
return {
|
|
280
314
|
outcome: decision.outcome ?? verdict ?? decision.decision,
|
|
281
|
-
...(
|
|
282
|
-
resolvedBy
|
|
283
|
-
resolvedAt
|
|
284
|
-
inboxId
|
|
315
|
+
...(note !== undefined ? { note } : {}),
|
|
316
|
+
resolvedBy,
|
|
317
|
+
resolvedAt,
|
|
318
|
+
inboxId,
|
|
319
|
+
...(trustedGateHeadSha !== undefined ? { trustedGateHeadSha } : {}),
|
|
320
|
+
...(mergeOverrideAudit !== undefined ? { mergeOverrideAudit } : {}),
|
|
321
|
+
...(adoptionAudit !== undefined ? { adoptionAudit } : {}),
|
|
285
322
|
...(decision.decision ? { decision: decision.decision } : {}),
|
|
286
323
|
};
|
|
287
324
|
}
|
|
@@ -317,9 +354,19 @@ function gateArtifactView(row, as) {
|
|
|
317
354
|
payloadRef: `attempt:${row.attemptId ?? ''}`,
|
|
318
355
|
};
|
|
319
356
|
}
|
|
320
|
-
|
|
357
|
+
function freshMergeGateArtifact(decision, lastVerdict, lastProducedOutput) {
|
|
358
|
+
if (decision.nodeId !== 'mergeGate')
|
|
359
|
+
return undefined;
|
|
360
|
+
if (lastProducedOutput?.nodeId === 'mergeRecheck' && lastVerdict === 'clean')
|
|
361
|
+
return lastProducedOutput;
|
|
362
|
+
if (lastProducedOutput?.nodeId === 'mergeApproveReverify' && lastVerdict === 'recheck')
|
|
363
|
+
return lastProducedOutput;
|
|
364
|
+
return undefined;
|
|
365
|
+
}
|
|
366
|
+
export function buildGateSummary(decision, outputsByNode, lastVerdict, lastProducedOutput) {
|
|
321
367
|
const summary = { nodeId: decision.nodeId, outcomes: decision.outcomes };
|
|
322
|
-
const artRow =
|
|
368
|
+
const artRow = freshMergeGateArtifact(decision, lastVerdict, lastProducedOutput)
|
|
369
|
+
?? resolveGateRow(decision.gatedArtifact, outputsByNode);
|
|
323
370
|
if (artRow)
|
|
324
371
|
summary.gatedArtifact = gateArtifactView(artRow, decision.gatedArtifact?.as);
|
|
325
372
|
const verdictRow = resolveGateRow(decision.verdictFrom, outputsByNode);
|
|
@@ -329,21 +376,91 @@ export function buildGateSummary(decision, outputsByNode, lastVerdict) {
|
|
|
329
376
|
summary.reviewerVerdict = { verdict: lastVerdict };
|
|
330
377
|
return summary;
|
|
331
378
|
}
|
|
379
|
+
function approvedMergeGateHeadSha(decision, verdict, summary) {
|
|
380
|
+
if (decision.nodeId !== 'mergeGate')
|
|
381
|
+
return undefined;
|
|
382
|
+
if (verdict === 'approved' || verdict === 'override_merge') {
|
|
383
|
+
return headShaFromPayload(summary.gatedArtifact?.payload) ?? null;
|
|
384
|
+
}
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
function approvedHeadMove(decision, approvedHeadSha, pointer, verdict) {
|
|
388
|
+
if (decision.nodeId !== 'mergeApproveReverify' || verdict !== 'clean' || approvedHeadSha === undefined)
|
|
389
|
+
return undefined;
|
|
390
|
+
const reverifyHeadSha = headShaFromPayload(pointer);
|
|
391
|
+
if (reverifyHeadSha === undefined || reverifyHeadSha === approvedHeadSha)
|
|
392
|
+
return undefined;
|
|
393
|
+
return { approvedHeadSha, reverifyHeadSha };
|
|
394
|
+
}
|
|
395
|
+
function reapprovalRequiredFeedback(pointer, approvedHeadSha, reverifyHeadSha) {
|
|
396
|
+
if (!isRecord(pointer))
|
|
397
|
+
return pointer;
|
|
398
|
+
const evidence = Array.isArray(pointer.evidence)
|
|
399
|
+
? pointer.evidence.filter((item) => typeof item === 'string')
|
|
400
|
+
: [];
|
|
401
|
+
return {
|
|
402
|
+
...pointer,
|
|
403
|
+
verdict: 'recheck',
|
|
404
|
+
evidence: [
|
|
405
|
+
...evidence,
|
|
406
|
+
`approved mergeGate headSha=${approvedHeadSha}; reverify headSha=${reverifyHeadSha}; reapproval required`,
|
|
407
|
+
],
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
function reopenNodeState(state, nodeId) {
|
|
411
|
+
return { ...state, activeNodeIds: new Set([nodeId]), status: 'running' };
|
|
412
|
+
}
|
|
413
|
+
function integratorResultPointer(result) {
|
|
414
|
+
return {
|
|
415
|
+
prUrl: result.prUrl,
|
|
416
|
+
branch: result.branch,
|
|
417
|
+
prNumber: result.prNumber,
|
|
418
|
+
headSha: result.headSha,
|
|
419
|
+
status: result.status,
|
|
420
|
+
...(result.issueRef ? { issueRef: result.issueRef } : {}),
|
|
421
|
+
...(result.foreignPr ? { foreignPr: true } : {}),
|
|
422
|
+
...(result.prAuthor ? { prAuthor: result.prAuthor } : {}),
|
|
423
|
+
...(result.integratorAccount ? { integratorAccount: result.integratorAccount } : {}),
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function integratorProgressEventType(result) {
|
|
427
|
+
return result.foreignPr ? 'foreign_pr_adopted' : 'integrate_succeeded';
|
|
428
|
+
}
|
|
429
|
+
function mergeOverrideEventPayload(result) {
|
|
430
|
+
const audit = result.override.audit;
|
|
431
|
+
return {
|
|
432
|
+
actor: result.override.actor,
|
|
433
|
+
note: result.override.note,
|
|
434
|
+
reason: audit?.reason ?? result.override.reason ?? '',
|
|
435
|
+
risk: audit?.risk ?? '',
|
|
436
|
+
verificationResponsibility: audit?.verificationResponsibility ?? '',
|
|
437
|
+
headSha: audit?.headSha ?? result.headSha,
|
|
438
|
+
freshHeadSha: result.headSha,
|
|
439
|
+
prNumber: result.prNumber,
|
|
440
|
+
source: result.override.source,
|
|
441
|
+
overriddenFacts: result.override.facts,
|
|
442
|
+
replied: result.override.replied,
|
|
443
|
+
resolved: result.override.resolved,
|
|
444
|
+
...(result.override.reason ? { refusalReason: result.override.reason } : {}),
|
|
445
|
+
};
|
|
446
|
+
}
|
|
332
447
|
export function buildSystemScriptRegistry(deps) {
|
|
333
|
-
const { appendEvent, releaseWorktreeFn, integrateFn, runStub, confirmMergeFn, runConfirmStub, pollPrFn, runPollStub, respondThreadsFn, runRespondStub } = deps;
|
|
448
|
+
const { appendEvent, releaseWorktreeFn, integrateFn, runStub, confirmMergeFn, runConfirmStub, pollPrFn, runPollStub, overrideMergeFn, runOverrideStub, respondThreadsFn, runRespondStub, } = deps;
|
|
334
449
|
function buildIntegratorInput(runId, ctx, inputs) {
|
|
335
|
-
const { taskId, title, base, issueRef } = ctx;
|
|
450
|
+
const { taskId, title, base, issueRef, issueAction } = ctx;
|
|
336
451
|
const change = producedChangeFromInputs(inputs);
|
|
337
452
|
const mergeReadiness = mergeReadinessFromInputs(inputs);
|
|
338
|
-
const changeForIntegrator = change ?
|
|
453
|
+
const changeForIntegrator = change ? changeWithRunIssueContract(change, issueRef, issueAction) : undefined;
|
|
339
454
|
return {
|
|
340
455
|
runId,
|
|
341
456
|
taskId,
|
|
342
457
|
title,
|
|
343
458
|
base,
|
|
344
459
|
...(issueRef ? { issueRef } : {}),
|
|
460
|
+
...(issueAction ? { issueAction } : {}),
|
|
345
461
|
...(changeForIntegrator ? { change: changeForIntegrator } : {}),
|
|
346
462
|
...(inputs.triage === undefined ? {} : { triage: inputs.triage }),
|
|
463
|
+
...(inputs.gateResolution === undefined ? {} : { gateResolution: inputs.gateResolution }),
|
|
347
464
|
...(mergeReadiness ? { mergeReadiness } : {}),
|
|
348
465
|
};
|
|
349
466
|
}
|
|
@@ -357,12 +474,13 @@ export function buildSystemScriptRegistry(deps) {
|
|
|
357
474
|
result = useReal ? await desc.real(integratorInput) : desc.stub(integratorInput);
|
|
358
475
|
}
|
|
359
476
|
catch (err) {
|
|
477
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
360
478
|
await appendEvent({
|
|
361
479
|
runId, taskId: ctx.taskId, stepId: '', stepKey,
|
|
362
480
|
type: 'step_failed',
|
|
363
|
-
payload: { scriptRef: decision.scriptRef, error:
|
|
481
|
+
payload: { scriptRef: decision.scriptRef, error: reason },
|
|
364
482
|
});
|
|
365
|
-
return { outcome: 'failed' };
|
|
483
|
+
return { outcome: 'failed', reason };
|
|
366
484
|
}
|
|
367
485
|
if ('needsHuman' in result) {
|
|
368
486
|
await appendEvent({
|
|
@@ -378,10 +496,38 @@ export function buildSystemScriptRegistry(deps) {
|
|
|
378
496
|
};
|
|
379
497
|
}
|
|
380
498
|
const cleanupWorktree = async ({ runId, decision, ctx, stepKey }) => {
|
|
499
|
+
let releaseResult;
|
|
381
500
|
try {
|
|
382
|
-
await releaseWorktreeFn(runId, ctx.taskId);
|
|
501
|
+
releaseResult = await releaseWorktreeFn(runId, ctx.taskId);
|
|
502
|
+
}
|
|
503
|
+
catch (err) {
|
|
504
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
505
|
+
await appendEvent({
|
|
506
|
+
runId,
|
|
507
|
+
taskId: ctx.taskId,
|
|
508
|
+
stepId: '',
|
|
509
|
+
stepKey,
|
|
510
|
+
type: 'cleanup_failed',
|
|
511
|
+
payload: { nodeId: decision.nodeId, error, released: false },
|
|
512
|
+
});
|
|
513
|
+
return { outcome: 'ok', pointer: { released: false, error } };
|
|
514
|
+
}
|
|
515
|
+
if (!releaseResult.released) {
|
|
516
|
+
const pointer = {
|
|
517
|
+
released: false,
|
|
518
|
+
reason: releaseResult.reason,
|
|
519
|
+
worktreePath: releaseResult.worktreePath,
|
|
520
|
+
};
|
|
521
|
+
await appendEvent({
|
|
522
|
+
runId,
|
|
523
|
+
taskId: ctx.taskId,
|
|
524
|
+
stepId: '',
|
|
525
|
+
stepKey,
|
|
526
|
+
type: 'cleanup_failed',
|
|
527
|
+
payload: { nodeId: decision.nodeId, ...pointer },
|
|
528
|
+
});
|
|
529
|
+
return { outcome: 'ok', pointer };
|
|
383
530
|
}
|
|
384
|
-
catch { /* best-effort */ }
|
|
385
531
|
await appendEvent({ runId, taskId: ctx.taskId, stepId: '', stepKey, type: 'worktree_released', payload: { nodeId: decision.nodeId } });
|
|
386
532
|
return { outcome: 'ok', pointer: { released: true } };
|
|
387
533
|
};
|
|
@@ -390,23 +536,9 @@ export function buildSystemScriptRegistry(deps) {
|
|
|
390
536
|
stub: runStub,
|
|
391
537
|
blockedReason: 'integrate',
|
|
392
538
|
mapSuccess: (result) => ({
|
|
393
|
-
eventType:
|
|
394
|
-
payload:
|
|
395
|
-
|
|
396
|
-
branch: result.branch,
|
|
397
|
-
prNumber: result.prNumber,
|
|
398
|
-
headSha: result.headSha,
|
|
399
|
-
status: result.status,
|
|
400
|
-
...(result.issueRef ? { issueRef: result.issueRef } : {}),
|
|
401
|
-
},
|
|
402
|
-
pointer: {
|
|
403
|
-
prUrl: result.prUrl,
|
|
404
|
-
branch: result.branch,
|
|
405
|
-
prNumber: result.prNumber,
|
|
406
|
-
headSha: result.headSha,
|
|
407
|
-
status: result.status,
|
|
408
|
-
...(result.issueRef ? { issueRef: result.issueRef } : {}),
|
|
409
|
-
},
|
|
539
|
+
eventType: integratorProgressEventType(result),
|
|
540
|
+
payload: integratorResultPointer(result),
|
|
541
|
+
pointer: integratorResultPointer(result),
|
|
410
542
|
}),
|
|
411
543
|
});
|
|
412
544
|
const confirmMergeScript = makeIntegratorScript({
|
|
@@ -447,6 +579,53 @@ export function buildSystemScriptRegistry(deps) {
|
|
|
447
579
|
verdict: result.verdict,
|
|
448
580
|
}),
|
|
449
581
|
});
|
|
582
|
+
const overrideMergeScript = async ({ runId, decision, ctx, bindingByRef, stepKey, inputs }) => {
|
|
583
|
+
const integratorInput = buildIntegratorInput(runId, ctx, inputs);
|
|
584
|
+
const binding = bindingByRef.get(decision.scriptRef) ?? bindingByRef.get('script:integrator');
|
|
585
|
+
const useReal = !!binding && runnerUsesRealIntegrator(binding.resolvedRunnerId);
|
|
586
|
+
let result;
|
|
587
|
+
try {
|
|
588
|
+
result = useReal ? await overrideMergeFn(integratorInput) : runOverrideStub(integratorInput);
|
|
589
|
+
}
|
|
590
|
+
catch (err) {
|
|
591
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
592
|
+
await appendEvent({
|
|
593
|
+
runId, taskId: ctx.taskId, stepId: '', stepKey,
|
|
594
|
+
type: 'step_failed',
|
|
595
|
+
payload: { scriptRef: decision.scriptRef, error: reason },
|
|
596
|
+
});
|
|
597
|
+
return { outcome: 'failed', reason };
|
|
598
|
+
}
|
|
599
|
+
if ('needsHuman' in result) {
|
|
600
|
+
await appendEvent({
|
|
601
|
+
runId, taskId: ctx.taskId, stepId: '', stepKey: 'pipeline',
|
|
602
|
+
type: 'pipeline_blocked',
|
|
603
|
+
payload: { reason: 'override-merge', lesson: result.lesson, nodeId: decision.nodeId },
|
|
604
|
+
});
|
|
605
|
+
return { outcome: 'blocked' };
|
|
606
|
+
}
|
|
607
|
+
if (result.override.replied > 0 || result.override.resolved > 0) {
|
|
608
|
+
await appendEvent({
|
|
609
|
+
runId,
|
|
610
|
+
taskId: ctx.taskId,
|
|
611
|
+
stepId: '',
|
|
612
|
+
stepKey,
|
|
613
|
+
type: 'threads_responded',
|
|
614
|
+
payload: { replied: result.override.replied, resolved: result.override.resolved },
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
if (result.override.accepted || result.verdict !== 'merged') {
|
|
618
|
+
await appendEvent({
|
|
619
|
+
runId,
|
|
620
|
+
taskId: ctx.taskId,
|
|
621
|
+
stepId: '',
|
|
622
|
+
stepKey,
|
|
623
|
+
type: result.override.accepted ? 'merge_overridden' : 'merge_override_refused',
|
|
624
|
+
payload: mergeOverrideEventPayload(result),
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
return { outcome: 'ok', pointer: result, verdict: result.verdict };
|
|
628
|
+
};
|
|
450
629
|
const respondThreadsScript = makeIntegratorScript({
|
|
451
630
|
real: respondThreadsFn,
|
|
452
631
|
stub: runRespondStub,
|
|
@@ -461,6 +640,7 @@ export function buildSystemScriptRegistry(deps) {
|
|
|
461
640
|
['script:cleanupWorktree', cleanupWorktree],
|
|
462
641
|
['script:confirmMerge', confirmMergeScript],
|
|
463
642
|
['script:pollPr', pollPrScript],
|
|
643
|
+
['script:overrideMerge', overrideMergeScript],
|
|
464
644
|
['script:respondThreads', respondThreadsScript],
|
|
465
645
|
// Unknown refs fall through to this entry, matching the original else-branch behavior.
|
|
466
646
|
['script:integrator', integratorScript],
|
|
@@ -501,7 +681,7 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
501
681
|
}
|
|
502
682
|
async function recordOutput(runId, node, ordinal, attemptId, output, outputsByNode) {
|
|
503
683
|
if (!('produces' in node) || !node.produces)
|
|
504
|
-
return;
|
|
684
|
+
return undefined;
|
|
505
685
|
const row = {
|
|
506
686
|
runId,
|
|
507
687
|
nodeId: node.id,
|
|
@@ -515,6 +695,7 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
515
695
|
list.push(row);
|
|
516
696
|
outputsByNode.set(node.id, list);
|
|
517
697
|
await appendRunOutput(row);
|
|
698
|
+
return row;
|
|
518
699
|
}
|
|
519
700
|
return async function dataDrivenTaskImpl(runId, opts) {
|
|
520
701
|
try {
|
|
@@ -537,7 +718,7 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
537
718
|
if (diagnostics.length > 0) {
|
|
538
719
|
throw new Error(`PINNED_TEMPLATE_INVALID: ${template.pipelineId} — ${diagnostics.map((d) => d.code).join(', ')}`);
|
|
539
720
|
}
|
|
540
|
-
const { taskId, title, base, issueRef } = await loadRunTaskContext(runId);
|
|
721
|
+
const { taskId, title, base, issueRef, issueAction } = await loadRunTaskContext(runId);
|
|
541
722
|
const live = route.roleBindings.some((b) => runnerNeedsLivePreflight(b.resolvedRunnerId));
|
|
542
723
|
if (live) {
|
|
543
724
|
const pf = await preflightFn(taskId, base);
|
|
@@ -548,9 +729,9 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
548
729
|
if (live) {
|
|
549
730
|
await createWorktreeFn(runId, taskId, title, base, issueRef);
|
|
550
731
|
}
|
|
551
|
-
return runGraph(runId, opts, taskId, title, base, issueRef, live);
|
|
732
|
+
return runGraph(runId, opts, taskId, title, base, issueRef, issueAction, live);
|
|
552
733
|
}
|
|
553
|
-
async function runGraph(runId, opts, taskId, title, base, issueRef, live) {
|
|
734
|
+
async function runGraph(runId, opts, taskId, title, base, issueRef, issueAction, live) {
|
|
554
735
|
const { route, template, runnerRetryPolicy } = opts;
|
|
555
736
|
const bindingByRef = new Map();
|
|
556
737
|
for (const binding of route.roleBindings) {
|
|
@@ -565,7 +746,9 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
565
746
|
let state = initialState(template);
|
|
566
747
|
let lastResult;
|
|
567
748
|
let lastVerdict = '';
|
|
749
|
+
let lastProducedOutput;
|
|
568
750
|
let lastFailureReason = '';
|
|
751
|
+
let approvedMergeGateHeadShaValue;
|
|
569
752
|
let stepCount = 0;
|
|
570
753
|
const effectOrdinalByNode = new Map();
|
|
571
754
|
const outputsByNode = new Map();
|
|
@@ -577,10 +760,12 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
577
760
|
return await finish(runId, decision.status, lastVerdict, stepCount, lastFailureReason);
|
|
578
761
|
}
|
|
579
762
|
const eff = await applyDecision(decision, {
|
|
580
|
-
runId, template, state, bindingByRef, executionProfile, taskId, title, base, issueRef,
|
|
763
|
+
runId, template, state, bindingByRef, executionProfile, taskId, title, base, issueRef, issueAction,
|
|
581
764
|
effectOrdinalByNode, outputsByNode, runnerRetryPolicy,
|
|
582
765
|
live,
|
|
583
766
|
lastVerdict,
|
|
767
|
+
lastProducedOutput,
|
|
768
|
+
approvedMergeGateHeadSha: approvedMergeGateHeadShaValue,
|
|
584
769
|
});
|
|
585
770
|
stepCount += eff.stepDelta;
|
|
586
771
|
if (eff.terminal) {
|
|
@@ -591,9 +776,12 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
591
776
|
await deps.setProgress?.(runId, progressCursor(state, eff.lastResult));
|
|
592
777
|
}
|
|
593
778
|
lastResult = eff.lastResult;
|
|
594
|
-
|
|
595
|
-
|
|
779
|
+
lastVerdict = eff.lastVerdict ?? lastVerdict;
|
|
780
|
+
lastProducedOutput = eff.producedOutput ?? lastProducedOutput;
|
|
596
781
|
lastFailureReason = eff.failureReason ?? '';
|
|
782
|
+
if (eff.approvedMergeGateHeadSha !== undefined) {
|
|
783
|
+
approvedMergeGateHeadShaValue = eff.approvedMergeGateHeadSha ?? undefined;
|
|
784
|
+
}
|
|
597
785
|
}
|
|
598
786
|
throw new InterpretError(`data-driven ${template.pipelineId} did not terminate within ${MAX_STEPS} steps (template loop bug)`);
|
|
599
787
|
}
|
|
@@ -648,6 +836,7 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
648
836
|
};
|
|
649
837
|
let lastResult;
|
|
650
838
|
let lastVerdict = '';
|
|
839
|
+
let lastProducedOutput;
|
|
651
840
|
let stepDelta = 0;
|
|
652
841
|
for (let i = 0; i < MAX_STEPS; i++) {
|
|
653
842
|
const next = coreStep(branchTemplate, state, lastResult);
|
|
@@ -670,6 +859,7 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
670
859
|
template: branchTemplate,
|
|
671
860
|
state,
|
|
672
861
|
lastVerdict,
|
|
862
|
+
lastProducedOutput,
|
|
673
863
|
});
|
|
674
864
|
stepDelta += eff.stepDelta;
|
|
675
865
|
if (eff.terminal)
|
|
@@ -679,6 +869,7 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
679
869
|
lastResult = eff.lastResult;
|
|
680
870
|
if (eff.lastVerdict !== undefined)
|
|
681
871
|
lastVerdict = eff.lastVerdict;
|
|
872
|
+
lastProducedOutput = eff.producedOutput ?? lastProducedOutput;
|
|
682
873
|
}
|
|
683
874
|
throw new InterpretError(`fork ${decision.nodeId} branch ${branch.id} did not reach join ${decision.joinId} within ${MAX_STEPS} steps`);
|
|
684
875
|
}
|
|
@@ -691,11 +882,12 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
691
882
|
const stepKey = stepKeyFor(node.id, ordinal);
|
|
692
883
|
const resolved = resolveConsumes(node, ctx.outputsByNode);
|
|
693
884
|
if ('missing' in resolved) {
|
|
885
|
+
const reason = `${REVO_INPUT_MISSING}: required input ${resolved.missing} was not produced`;
|
|
694
886
|
await appendEvent({
|
|
695
887
|
runId, taskId, stepId: '', stepKey, type: 'step_failed',
|
|
696
|
-
payload: { nodeId: node.id, error:
|
|
888
|
+
payload: { nodeId: node.id, error: reason },
|
|
697
889
|
});
|
|
698
|
-
return { lastResult: { outcome: 'failed', errorCode: REVO_INPUT_MISSING }, lastVerdict: 'failed', stepDelta: 1 };
|
|
890
|
+
return { lastResult: { outcome: 'failed', errorCode: REVO_INPUT_MISSING }, lastVerdict: 'failed', failureReason: reason, stepDelta: 1 };
|
|
699
891
|
}
|
|
700
892
|
const result = await invokeRole(runId, decision, node, ctx, resolved.inputs, stepKey);
|
|
701
893
|
if ('blocked' in result) {
|
|
@@ -726,15 +918,16 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
726
918
|
await appendEvent({
|
|
727
919
|
runId, taskId, stepId: '', stepKey, type: 'step_failed',
|
|
728
920
|
idempotencyKey: result.attemptId,
|
|
729
|
-
payload: { nodeId: node.id, error: result.errorCode },
|
|
921
|
+
payload: { nodeId: node.id, error: result.errorCode, reason: result.reason },
|
|
730
922
|
});
|
|
731
923
|
return { lastResult: { outcome: 'failed', errorCode: result.errorCode }, lastVerdict: 'failed', failureReason: result.reason, stepDelta: result.attemptsMade };
|
|
732
924
|
}
|
|
733
|
-
await recordOutput(runId, node, ordinal, result.attemptId, result.output, ctx.outputsByNode);
|
|
925
|
+
const producedOutput = await recordOutput(runId, node, ordinal, result.attemptId, result.output, ctx.outputsByNode);
|
|
734
926
|
const verdict = result.verdict;
|
|
735
927
|
return {
|
|
736
928
|
lastResult: { outcome: 'succeeded', ...(verdict ? { verdict } : {}) },
|
|
737
929
|
...(verdict ? { lastVerdict: verdict } : {}),
|
|
930
|
+
...(producedOutput ? { producedOutput } : {}),
|
|
738
931
|
stepDelta: result.attemptsMade,
|
|
739
932
|
};
|
|
740
933
|
}
|
|
@@ -743,30 +936,54 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
743
936
|
const ordinal = nextOrdinal(ctx.effectOrdinalByNode, node.id);
|
|
744
937
|
const resolved = resolveConsumes(node, ctx.outputsByNode);
|
|
745
938
|
if ('missing' in resolved) {
|
|
939
|
+
const reason = `${REVO_INPUT_MISSING}: required input ${resolved.missing} was not produced`;
|
|
746
940
|
await appendEvent({
|
|
747
941
|
runId, taskId, stepId: '', stepKey: stepKeyFor(node.id, ordinal), type: 'step_failed',
|
|
748
|
-
payload: { nodeId: node.id, error:
|
|
942
|
+
payload: { nodeId: node.id, error: reason },
|
|
749
943
|
});
|
|
750
|
-
return { lastResult: { outcome: 'failed', errorCode: REVO_INPUT_MISSING }, lastVerdict: 'failed', stepDelta: 1 };
|
|
944
|
+
return { lastResult: { outcome: 'failed', errorCode: REVO_INPUT_MISSING }, lastVerdict: 'failed', failureReason: reason, stepDelta: 1 };
|
|
751
945
|
}
|
|
752
|
-
const scriptResult = await invokeScript(runId, decision, { taskId, title, base, issueRef: ctx.issueRef }, bindingByRef, stepKeyFor(node.id, ordinal), resolved.inputs);
|
|
946
|
+
const scriptResult = await invokeScript(runId, decision, { taskId, title, base, issueRef: ctx.issueRef, issueAction: ctx.issueAction }, bindingByRef, stepKeyFor(node.id, ordinal), resolved.inputs);
|
|
753
947
|
if (scriptResult.outcome === 'blocked') {
|
|
754
948
|
return { lastResult: { outcome: 'failed', errorCode: REVO_SCRIPT_BLOCKED }, lastVerdict: 'blocked', stepDelta: 1 };
|
|
755
949
|
}
|
|
756
950
|
if (scriptResult.outcome === 'failed') {
|
|
757
|
-
|
|
951
|
+
const reason = scriptResult.reason ? `${REVO_SCRIPT_FAILED}: ${scriptResult.reason}` : REVO_SCRIPT_FAILED;
|
|
952
|
+
return { lastResult: { outcome: 'failed', errorCode: REVO_SCRIPT_FAILED }, lastVerdict: 'failed', failureReason: reason, stepDelta: 1 };
|
|
758
953
|
}
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
954
|
+
let pointer = scriptResult.pointer;
|
|
955
|
+
let sv = scriptResult.verdict;
|
|
956
|
+
let stateOverride;
|
|
957
|
+
const headMove = approvedHeadMove(decision, ctx.approvedMergeGateHeadSha, pointer, sv);
|
|
958
|
+
if (headMove) {
|
|
959
|
+
pointer = reapprovalRequiredFeedback(pointer, headMove.approvedHeadSha, headMove.reverifyHeadSha);
|
|
960
|
+
sv = 'recheck';
|
|
961
|
+
stateOverride = reopenNodeState(ctx.state, 'mergeGate');
|
|
962
|
+
}
|
|
963
|
+
const producedOutput = await recordOutput(runId, node, ordinal, stepKeyFor(node.id, ordinal), pointer, ctx.outputsByNode);
|
|
964
|
+
return {
|
|
965
|
+
lastResult: stateOverride ? undefined : { outcome: 'succeeded', ...(sv ? { verdict: sv } : {}) },
|
|
966
|
+
...(sv ? { lastVerdict: sv } : {}),
|
|
967
|
+
...(producedOutput ? { producedOutput } : {}),
|
|
968
|
+
...(stateOverride ? { stateOverride } : {}),
|
|
969
|
+
stepDelta: 1,
|
|
970
|
+
};
|
|
762
971
|
}
|
|
763
972
|
case 'awaitGate': {
|
|
764
973
|
const topic = gateTopicFor(decision.reason);
|
|
765
974
|
const ordinal = nextOrdinal(ctx.effectOrdinalByNode, decision.nodeId);
|
|
766
|
-
const
|
|
975
|
+
const summary = buildGateSummary(decision, ctx.outputsByNode, ctx.lastVerdict, ctx.lastProducedOutput);
|
|
976
|
+
const human = await awaitHuman(runId, topic, stepKeyFor(decision.nodeId, ordinal), `${decision.reason} approval`, summary, decision.outcomes);
|
|
767
977
|
const verdict = gateVerdict(human, decision.outcomes);
|
|
768
|
-
|
|
769
|
-
|
|
978
|
+
const approvedHeadSha = approvedMergeGateHeadSha(decision, verdict, summary);
|
|
979
|
+
const producedOutput = await recordOutput(runId, resolveNode(template, decision.nodeId), ordinal, stepKeyFor(decision.nodeId, ordinal), gateResolutionOutput(human, verdict, stepKeyFor(decision.nodeId, ordinal), approvedHeadSha), ctx.outputsByNode);
|
|
980
|
+
return {
|
|
981
|
+
lastResult: verdict ? { verdict } : {},
|
|
982
|
+
...(verdict ? { lastVerdict: verdict } : {}),
|
|
983
|
+
...(producedOutput ? { producedOutput } : {}),
|
|
984
|
+
...(approvedHeadSha !== undefined ? { approvedMergeGateHeadSha: approvedHeadSha } : {}),
|
|
985
|
+
stepDelta: 0,
|
|
986
|
+
};
|
|
770
987
|
}
|
|
771
988
|
case 'fork': {
|
|
772
989
|
await appendEvent({
|
|
@@ -800,7 +1017,8 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
800
1017
|
for (let attemptNo = 1; attemptNo <= ctx.runnerRetryPolicy.maxAttempts; attemptNo++) {
|
|
801
1018
|
const physicalAttempt = physicalAttemptFor(runId, stepKey, attemptNo);
|
|
802
1019
|
attemptIds.push(physicalAttempt.attemptId);
|
|
803
|
-
const
|
|
1020
|
+
const launchOverrides = resolveLaunchOverrides(binding, decision.nodeId, ctx.executionProfile);
|
|
1021
|
+
const result = await runStepFn(runId, binding.rowId, stepKey, stepInputForAttempt(decision.nodeId, inputs, physicalAttempt), binding.resolvedRunnerId, ctx.executionProfile, physicalAttempt, ctx.template.verdicts.domain, launchOverrides);
|
|
804
1022
|
const needsHuman = await maybeHandleNeedsHumanRoleResult({
|
|
805
1023
|
...input,
|
|
806
1024
|
attemptIds,
|
|
@@ -830,6 +1048,7 @@ export function makeDataDrivenTask(runStepFn, deps) {
|
|
|
830
1048
|
nodeId: node.id,
|
|
831
1049
|
attemptId: physicalAttempt.attemptId,
|
|
832
1050
|
...(ctx.issueRef ? { issueRef: ctx.issueRef } : {}),
|
|
1051
|
+
...(ctx.issueAction ? { issueAction: ctx.issueAction } : {}),
|
|
833
1052
|
...(artifactRef ? { artifactRef } : {}),
|
|
834
1053
|
});
|
|
835
1054
|
output = attachProducedChange(output, change);
|