@revisium/orchestrator 0.1.0-alpha.9 → 0.2.0-alpha.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 +210 -146
- package/control-plane/bootstrap.config.json +43 -1
- package/control-plane/default-playbook/catalog/pipelines.json +1157 -10
- package/control-plane/default-playbook/catalog/roles.json +54 -0
- package/control-plane/default-playbook/package.json +1 -1
- package/control-plane/default-playbook/prompts/developer.md +1 -0
- package/control-plane/default-playbook/prompts/triager.md +3 -0
- package/dist/api/graphql-api/graphql-ws/pubsub.module.js +0 -1
- package/dist/api/graphql-api/graphql-ws/pubsub.module.js.map +1 -1
- package/dist/api/graphql-api/graphql-ws/run-progress-subscription-poller.service.js +0 -1
- package/dist/api/graphql-api/graphql-ws/run-progress-subscription-poller.service.js.map +1 -1
- package/dist/api/graphql-api/graphql-ws/subscription-bridge.service.js +0 -1
- 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 -0
- 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/pr/model/pr-readiness.model.js +26 -0
- package/dist/api/graphql-api/pr/model/pr-readiness.model.js.map +1 -1
- package/dist/api/graphql-api/runs/inputs/create-run.input.js +6 -0
- package/dist/api/graphql-api/runs/inputs/create-run.input.js.map +1 -1
- package/dist/api/graphql-api/runs/model/run.model.js +6 -0
- package/dist/api/graphql-api/runs/model/run.model.js.map +1 -1
- package/dist/api/graphql-api/share/model/issue-ref.model.js +53 -0
- package/dist/api/graphql-api/share/model/issue-ref.model.js.map +1 -0
- package/dist/cli/commands/doctor-report.js +0 -18
- package/dist/cli/commands/doctor-report.js.map +1 -1
- package/dist/cli/commands/lifecycle.js +3 -71
- package/dist/cli/commands/lifecycle.js.map +1 -1
- package/dist/cli/commands/mcp.js +0 -14
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/process-tree.js +4 -26
- package/dist/cli/commands/process-tree.js.map +1 -1
- package/dist/cli/commands/revisium-helpers.js +0 -6
- package/dist/cli/commands/revisium-helpers.js.map +1 -1
- package/dist/cli/commands/rogue-reaper.js +0 -34
- package/dist/cli/commands/rogue-reaper.js.map +1 -1
- package/dist/cli/index.js +0 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/program.js +0 -5
- package/dist/cli/program.js.map +1 -1
- package/dist/config.js +0 -25
- package/dist/config.js.map +1 -1
- package/dist/control-plane/bootstrap.js +12 -27
- package/dist/control-plane/bootstrap.js.map +1 -1
- package/dist/control-plane/change-notifications.js +0 -1
- package/dist/control-plane/change-notifications.js.map +1 -1
- package/dist/control-plane/client-transport.js +1 -12
- package/dist/control-plane/client-transport.js.map +1 -1
- package/dist/control-plane/default-playbook-policy.js +593 -0
- package/dist/control-plane/default-playbook-policy.js.map +1 -0
- package/dist/control-plane/definitions.js +8 -17
- package/dist/control-plane/definitions.js.map +1 -1
- package/dist/control-plane/inbox.js +2 -120
- package/dist/control-plane/inbox.js.map +1 -1
- package/dist/control-plane/resolve-cwd.js +0 -61
- package/dist/control-plane/resolve-cwd.js.map +1 -1
- package/dist/control-plane/schema-migration.js +0 -9
- package/dist/control-plane/schema-migration.js.map +1 -1
- package/dist/control-plane/seed-default-playbook.js +50 -46
- package/dist/control-plane/seed-default-playbook.js.map +1 -1
- package/dist/control-plane/steps.js +0 -15
- package/dist/control-plane/steps.js.map +1 -1
- package/dist/e2e/kit/agents.js +15 -21
- package/dist/e2e/kit/agents.js.map +1 -1
- package/dist/e2e/kit/assertions.js +12 -8
- package/dist/e2e/kit/assertions.js.map +1 -1
- package/dist/e2e/kit/fake-integrator.js +11 -2
- package/dist/e2e/kit/fake-integrator.js.map +1 -1
- package/dist/e2e/kit/git-target-repo.js +1 -1
- package/dist/engine/dbos.service.js +12 -179
- package/dist/engine/dbos.service.js.map +1 -1
- package/dist/engine/ensure-postgres.js +0 -48
- package/dist/engine/ensure-postgres.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/features/runs/queries/handlers/runs-query.handlers.js +1 -0
- package/dist/features/runs/queries/handlers/runs-query.handlers.js.map +1 -1
- package/dist/host/daemon.js +2 -21
- package/dist/host/daemon.js.map +1 -1
- package/dist/host/dbos-identity.js +0 -31
- package/dist/host/dbos-identity.js.map +1 -1
- package/dist/host/ensure-host.js +1 -37
- package/dist/host/ensure-host.js.map +1 -1
- package/dist/host/ensure-revisium.js +1 -135
- package/dist/host/ensure-revisium.js.map +1 -1
- package/dist/host/host-runtime.js +0 -28
- package/dist/host/host-runtime.js.map +1 -1
- package/dist/host/host.lifecycle.js +0 -27
- package/dist/host/host.lifecycle.js.map +1 -1
- package/dist/host/queue-ownership.js +0 -42
- package/dist/host/queue-ownership.js.map +1 -1
- package/dist/host/queue-poller-census.js +1 -28
- package/dist/host/queue-poller-census.js.map +1 -1
- package/dist/http/graphql-host.module.js +0 -3
- package/dist/http/graphql-host.module.js.map +1 -1
- package/dist/mcp/mcp-capabilities.js +23 -5
- package/dist/mcp/mcp-capabilities.js.map +1 -1
- package/dist/mcp/mcp-facade.service.js +335 -22
- package/dist/mcp/mcp-facade.service.js.map +1 -1
- package/dist/mcp/mcp-http.service.js +0 -18
- package/dist/mcp/mcp-http.service.js.map +1 -1
- package/dist/mcp/mcp-tools.js +41 -36
- package/dist/mcp/mcp-tools.js.map +1 -1
- package/dist/observability/activity-signal.js +103 -0
- package/dist/observability/activity-signal.js.map +1 -0
- package/dist/observability/agent-activity-reporter.js +0 -4
- package/dist/observability/agent-activity-reporter.js.map +1 -1
- package/dist/observability/index.js +1 -0
- package/dist/observability/index.js.map +1 -1
- package/dist/pipeline/await-human.js +0 -40
- package/dist/pipeline/await-human.js.map +1 -1
- package/dist/pipeline/data-driven-task.workflow.js +563 -251
- package/dist/pipeline/data-driven-task.workflow.js.map +1 -1
- package/dist/pipeline/data-driven-template.js +0 -25
- package/dist/pipeline/data-driven-template.js.map +1 -1
- package/dist/pipeline/pipeline.module.js +0 -12
- package/dist/pipeline/pipeline.module.js.map +1 -1
- package/dist/pipeline/pipeline.service.js +194 -189
- package/dist/pipeline/pipeline.service.js.map +1 -1
- package/dist/pipeline/route-contract.js +4 -3
- package/dist/pipeline/route-contract.js.map +1 -1
- package/dist/pipeline-core/index.js +1 -13
- package/dist/pipeline-core/index.js.map +1 -1
- package/dist/pipeline-core/interpret.js +21 -94
- package/dist/pipeline-core/interpret.js.map +1 -1
- package/dist/pipeline-core/kit/assertions.js +0 -19
- package/dist/pipeline-core/kit/assertions.js.map +1 -1
- package/dist/pipeline-core/kit/builders.js +1 -21
- package/dist/pipeline-core/kit/builders.js.map +1 -1
- package/dist/pipeline-core/kit/drive.js +1 -31
- package/dist/pipeline-core/kit/drive.js.map +1 -1
- package/dist/pipeline-core/kit/fixtures.js +78 -101
- package/dist/pipeline-core/kit/fixtures.js.map +1 -1
- package/dist/pipeline-core/kit/index.js +0 -8
- package/dist/pipeline-core/kit/index.js.map +1 -1
- package/dist/pipeline-core/types.js +13 -52
- package/dist/pipeline-core/types.js.map +1 -1
- package/dist/pipeline-core/validate-capability.js +0 -3
- package/dist/pipeline-core/validate-capability.js.map +1 -1
- package/dist/pipeline-core/validate-conflicts.js +0 -9
- package/dist/pipeline-core/validate-conflicts.js.map +1 -1
- package/dist/pipeline-core/validate-dataflow.js +0 -17
- package/dist/pipeline-core/validate-dataflow.js.map +1 -1
- package/dist/pipeline-core/validate-diff.js +3 -36
- package/dist/pipeline-core/validate-diff.js.map +1 -1
- package/dist/pipeline-core/validate-edges.js +0 -6
- package/dist/pipeline-core/validate-edges.js.map +1 -1
- package/dist/pipeline-core/validate-graph.js +0 -11
- package/dist/pipeline-core/validate-graph.js.map +1 -1
- package/dist/pipeline-core/validate-loops.js +37 -44
- package/dist/pipeline-core/validate-loops.js.map +1 -1
- package/dist/pipeline-core/validate-parallel.js +9 -15
- package/dist/pipeline-core/validate-parallel.js.map +1 -1
- package/dist/pipeline-core/validate-sink.js +0 -7
- package/dist/pipeline-core/validate-sink.js.map +1 -1
- package/dist/pipeline-core/validate-topology.js +1 -20
- package/dist/pipeline-core/validate-topology.js.map +1 -1
- package/dist/pipeline-core/validate-verdict.js +52 -7
- package/dist/pipeline-core/validate-verdict.js.map +1 -1
- package/dist/pipeline-core/validate.js +5 -29
- package/dist/pipeline-core/validate.js.map +1 -1
- package/dist/playbook/catalog-loader.js +8 -3
- package/dist/playbook/catalog-loader.js.map +1 -1
- package/dist/playbook/import-mapper.js +4 -5
- package/dist/playbook/import-mapper.js.map +1 -1
- package/dist/poller/pr-readiness-core.js +226 -29
- package/dist/poller/pr-readiness-core.js.map +1 -1
- package/dist/revisium/inbox.service.js +0 -24
- package/dist/revisium/inbox.service.js.map +1 -1
- package/dist/revisium/playbooks.service.js +15 -2
- package/dist/revisium/playbooks.service.js.map +1 -1
- package/dist/revisium/revisium.module.js +0 -12
- package/dist/revisium/revisium.module.js.map +1 -1
- package/dist/revisium/roles.service.js +0 -6
- package/dist/revisium/roles.service.js.map +1 -1
- package/dist/revisium/run.service.js +2 -75
- package/dist/revisium/run.service.js.map +1 -1
- package/dist/revisium/tokens.js +0 -4
- package/dist/revisium/tokens.js.map +1 -1
- package/dist/run/append-event.js +6 -37
- package/dist/run/append-event.js.map +1 -1
- package/dist/run/block-run.js.map +1 -1
- package/dist/run/cancel-run.js +0 -33
- package/dist/run/cancel-run.js.map +1 -1
- package/dist/run/complete-run.js.map +1 -1
- package/dist/run/create-run.js +5 -8
- package/dist/run/create-run.js.map +1 -1
- package/dist/run/fail-run.js +0 -3
- package/dist/run/fail-run.js.map +1 -1
- package/dist/run/inspect-run.js +10 -29
- package/dist/run/inspect-run.js.map +1 -1
- package/dist/run/issue-ref.js +88 -0
- package/dist/run/issue-ref.js.map +1 -0
- package/dist/run/run-outputs.js +0 -19
- package/dist/run/run-outputs.js.map +1 -1
- package/dist/run/terminal-run-status.js +0 -12
- package/dist/run/terminal-run-status.js.map +1 -1
- package/dist/runners/claude-code.service.js +2 -13
- package/dist/runners/claude-code.service.js.map +1 -1
- package/dist/runners/codex.service.js +2 -11
- package/dist/runners/codex.service.js.map +1 -1
- package/dist/runners/gh-identity.js +0 -52
- package/dist/runners/gh-identity.js.map +1 -1
- package/dist/runners/integrator-branch-naming.js +16 -19
- package/dist/runners/integrator-branch-naming.js.map +1 -1
- package/dist/runners/integrator-git.js +0 -25
- package/dist/runners/integrator-git.js.map +1 -1
- package/dist/runners/integrator-remote.js +0 -2
- package/dist/runners/integrator-remote.js.map +1 -1
- package/dist/runners/integrator-types.js +0 -7
- package/dist/runners/integrator-types.js.map +1 -1
- package/dist/runners/integrator.js +231 -230
- package/dist/runners/integrator.js.map +1 -1
- package/dist/runners/runner.module.js +0 -6
- package/dist/runners/runner.module.js.map +1 -1
- package/dist/runners/tokens.js +0 -4
- package/dist/runners/tokens.js.map +1 -1
- package/dist/runners/worktree.service.js +3 -19
- package/dist/runners/worktree.service.js.map +1 -1
- package/dist/task-control-plane/pr-readiness.service.js +15 -13
- package/dist/task-control-plane/pr-readiness.service.js.map +1 -1
- package/dist/task-control-plane/run-watch.service.js +170 -63
- package/dist/task-control-plane/run-watch.service.js.map +1 -1
- package/dist/task-control-plane/task-control-plane-api.service.js +285 -40
- package/dist/task-control-plane/task-control-plane-api.service.js.map +1 -1
- package/dist/worker/artifact-store.js +21 -3
- package/dist/worker/artifact-store.js.map +1 -1
- package/dist/worker/build-context.js +10 -10
- package/dist/worker/build-context.js.map +1 -1
- package/dist/worker/claude-code-runner.js +76 -48
- package/dist/worker/claude-code-runner.js.map +1 -1
- package/dist/worker/codex-runner.js +128 -35
- package/dist/worker/codex-runner.js.map +1 -1
- package/dist/worker/git-worktree-manager.js +20 -67
- package/dist/worker/git-worktree-manager.js.map +1 -1
- package/dist/worker/process-executor.js +144 -27
- package/dist/worker/process-executor.js.map +1 -1
- package/dist/worker/result-envelope.js +33 -49
- package/dist/worker/result-envelope.js.map +1 -1
- package/dist/worker/runner-common.js +29 -0
- package/dist/worker/runner-common.js.map +1 -1
- package/dist/worker/runner-dispatch.js +0 -3
- package/dist/worker/runner-dispatch.js.map +1 -1
- package/dist/worker/runner.js +16 -1
- package/dist/worker/runner.js.map +1 -1
- package/dist/worker/stub-runner.js +0 -7
- package/dist/worker/stub-runner.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/pipeline-core/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/pipeline-core/types.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAU,CAAC;AAItF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAU,CAAC;AAc7E,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,aAAa;IACb,KAAK;IACL,KAAK;IACL,KAAK;CACG,CAAC;AASX,MAAM,UAAU,eAAe,CAAC,CAAS;IACvC,OAAO,SAAS,IAAI,CAAC,CAAC;AACxB,CAAC;AACD,MAAM,UAAU,eAAe,CAAC,CAAS;IACvC,OAAO,MAAM,IAAI,CAAC,CAAC;AACrB,CAAC;AAMD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAU,CAAC;AAMxE,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO;IACP,QAAQ;IACR,WAAW;IACX,QAAQ;IACR,UAAU;IACV,MAAM;IACN,MAAM;IACN,UAAU;CACF,CAAC;AA8EX,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAU,CAAC;AAGjE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,WAAW,EAAE,qBAAqB,CAAU,CAAC;AAQ5E,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,OAAO,CAAU,CAAC;AAgD7D,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACpD,CAAC;AAkED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,eAAe;IACf,kBAAkB;IAClB,gBAAgB;IAChB,qBAAqB;IACrB,mBAAmB;IACnB,qBAAqB;IACrB,oBAAoB;IACpB,6BAA6B;IAC7B,0BAA0B;IAC1B,kBAAkB;IAClB,gBAAgB;IAChB,kBAAkB;IAClB,yBAAyB;IACzB,aAAa;IACb,2BAA2B;IAC3B,sBAAsB;IACtB,0BAA0B;IAC1B,oBAAoB;IACpB,yBAAyB;IACzB,mBAAmB;IACnB,mBAAmB;IACnB,6BAA6B;IAC7B,yBAAyB;IACzB,eAAe;IACf,eAAe;IACf,0BAA0B;IAC1B,oBAAoB;IACpB,uBAAuB;IACvB,6BAA6B;IAC7B,yBAAyB;IACzB,0BAA0B;IAC1B,2BAA2B;IAC3B,yBAAyB;IACzB,qBAAqB;IACrB,sBAAsB;IACtB,cAAc;IACd,gBAAgB;IAChB,4BAA4B;IAC5B,sBAAsB;IACtB,wBAAwB;IACxB,4BAA4B;IAC5B,gBAAgB;IAChB,kBAAkB;IAClB,qBAAqB;IACrB,0BAA0B;IAC1B,2BAA2B;IAC3B,wBAAwB;IACxB,qBAAqB;IACrB,gCAAgC;IAChC,iBAAiB;IACjB,mBAAmB;IACnB,qBAAqB;IACrB,2BAA2B;IAC3B,mBAAmB;IACnB,mBAAmB;IACnB,wBAAwB;IACxB,4BAA4B;IAC5B,6BAA6B;CACrB,CAAC"}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* validate-capability — §12 rule 12 (agent/script capability-ref shape). Lifted from validate.ts.
|
|
3
|
-
*/
|
|
4
1
|
const CAPABILITY_REF_PATTERN = /^(role|script):[A-Za-z][A-Za-z0-9_-]*$/;
|
|
5
2
|
export function ruleCapabilityRefs(template, d) {
|
|
6
3
|
for (const node of Object.values(template.nodes)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-capability.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-capability.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate-capability.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-capability.ts"],"names":[],"mappings":"AAKA,MAAM,sBAAsB,GAAG,wCAAwC,CAAC;AAExE,MAAM,UAAU,kBAAkB,CAAC,QAAkB,EAAE,CAAW;IAChE,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpF,CAAC,CAAC,KAAK,CAAC,sBAAsB,EAAE,SAAS,IAAI,CAAC,EAAE,aAAa,IAAI,CAAC,OAAO,gBAAgB,EAAE;oBACzF,MAAM,EAAE,IAAI,CAAC,EAAE;iBAChB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1F,CAAC,CAAC,KAAK,CAAC,sBAAsB,EAAE,UAAU,IAAI,CAAC,EAAE,eAAe,IAAI,CAAC,SAAS,gBAAgB,EAAE;oBAC9F,MAAM,EAAE,IAAI,CAAC,EAAE;iBAChB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* validate-conflicts — §12 rule 10 (policy.conflicts well-formedness). Lifted from validate.ts.
|
|
3
|
-
*/
|
|
4
1
|
export function ruleConflictMatrix(template, d) {
|
|
5
2
|
const conflicts = template.policy?.conflicts ?? [];
|
|
6
3
|
if (conflicts.length === 0)
|
|
7
4
|
return;
|
|
8
|
-
// Map each role to the node ids that bind it (agent.roleRef = "role:<name>").
|
|
9
5
|
const roleNodes = new Map();
|
|
10
6
|
for (const node of Object.values(template.nodes)) {
|
|
11
7
|
if (node.kind === 'agent') {
|
|
@@ -20,14 +16,9 @@ export function ruleConflictMatrix(template, d) {
|
|
|
20
16
|
continue;
|
|
21
17
|
}
|
|
22
18
|
const [a, b] = pair;
|
|
23
|
-
// A conflict is well-formed only if both roles are actually bound by some node.
|
|
24
19
|
if (!roleNodes.has(a) || !roleNodes.has(b)) {
|
|
25
20
|
d.warn('CONFLICT_REF_INVALID', `policy.conflicts [${a}, ${b}] references a role no node binds`);
|
|
26
21
|
}
|
|
27
|
-
// v1 binds a role to a node, not to a concrete actor; a path where ONE actor fills both roles
|
|
28
|
-
// is detectable only with actor assignment (out of v1 template data). We surface the *structural*
|
|
29
|
-
// hazard: the same node is bound to both conflicting roles (impossible via roleRef, but a future
|
|
30
|
-
// multi-role node would trip it) — kept as a placeholder check so the rule has a code + a test.
|
|
31
22
|
}
|
|
32
23
|
}
|
|
33
24
|
function roleName(roleRef) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-conflicts.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-conflicts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate-conflicts.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-conflicts.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,kBAAkB,CAAC,QAAkB,EAAE,CAAW;IAChE,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC;IACnD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEnC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpC,IAAI,IAAI;gBAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;YACzF,CAAC,CAAC,KAAK,CAAC,sBAAsB,EAAE,0BAA0B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YAC/G,SAAS;QACX,CAAC;QACD,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,CAAC,CAAC,IAAI,CAAC,sBAAsB,EAAE,qBAAqB,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAClG,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9B,CAAC"}
|
|
@@ -9,12 +9,6 @@ export function ruleDataflow(template, ids, d) {
|
|
|
9
9
|
checkGateRefs(node, ctx, d);
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
/**
|
|
13
|
-
* D3 — a humanGate's informational `gatedArtifact`/`verdictFrom` refs must point at real nodes (catch
|
|
14
|
-
* typos at seed/validate time); a gatedArtifact node must declare `produces` (else it yields nothing).
|
|
15
|
-
* Resolution at runtime is best-effort (a missing artifact just omits it), so dominance is NOT required —
|
|
16
|
-
* unlike a consumer's required input. Routing is unaffected (the gate still routes on its verdict).
|
|
17
|
-
*/
|
|
18
12
|
function checkGateRefs(node, ctx, d) {
|
|
19
13
|
const { gatedArtifact, verdictFrom } = node;
|
|
20
14
|
if (gatedArtifact) {
|
|
@@ -49,7 +43,6 @@ function analyse(template, ids) {
|
|
|
49
43
|
cyclesByNode: consumerStaleCycles(template),
|
|
50
44
|
};
|
|
51
45
|
}
|
|
52
|
-
/** PRODUCES_NAME_DUP — a clarity guard: the grammar keys consumes by NODE, so a duplicate name isn't a resolution bug. */
|
|
53
46
|
function flagDuplicateProduces(template, d) {
|
|
54
47
|
const producedNames = new Map();
|
|
55
48
|
for (const node of Object.values(template.nodes)) {
|
|
@@ -100,7 +93,6 @@ function checkConsumeRef(node, ref, path, seenAs, ctx, d) {
|
|
|
100
93
|
function isEffectProducer(node) {
|
|
101
94
|
return (node.kind === 'agent' || node.kind === 'script') && !!node.produces;
|
|
102
95
|
}
|
|
103
|
-
/** Dominance: the producer must run before the consumer on EVERY path (entry can never be dominated → a consuming entry node is always flagged). */
|
|
104
96
|
function checkDominance(node, ref, path, ctx, d) {
|
|
105
97
|
const dominated = ctx.hasEntry && ref.node !== node.id && ctx.dom.get(node.id)?.has(ref.node) === true;
|
|
106
98
|
if (dominated)
|
|
@@ -111,7 +103,6 @@ function checkDominance(node, ref, path, ctx, d) {
|
|
|
111
103
|
else
|
|
112
104
|
d.error('CONSUMES_NOT_DOMINATED', msg, { nodeId: node.id, path });
|
|
113
105
|
}
|
|
114
|
-
/** Freshness: a consumer inside a loop the producer is NOT on can silently reuse a stale output. */
|
|
115
106
|
function checkFreshness(node, ref, path, ctx, d) {
|
|
116
107
|
const iteration = ref.iteration ?? 'latest';
|
|
117
108
|
if (iteration !== 'latest' || ref.staleOk === true)
|
|
@@ -121,7 +112,6 @@ function checkFreshness(node, ref, path, ctx, d) {
|
|
|
121
112
|
d.warn('CONSUMES_STALE_RISK', `node "${node.id}" can re-enter a loop without re-running producer "${ref.node}" (iteration:'latest') — set staleOk or use iteration:'all'/N`, { nodeId: node.id, path });
|
|
122
113
|
}
|
|
123
114
|
}
|
|
124
|
-
/** Cross-parallel: consuming a sibling branch's output is unsafe (the branch may be cancelled). */
|
|
125
115
|
function checkCrossParallel(node, ref, path, ctx, d) {
|
|
126
116
|
const consumerBranches = ctx.membership.get(node.id) ?? [];
|
|
127
117
|
const producerBranches = ctx.membership.get(ref.node) ?? [];
|
|
@@ -133,11 +123,6 @@ function checkCrossParallel(node, ref, path, ctx, d) {
|
|
|
133
123
|
});
|
|
134
124
|
}
|
|
135
125
|
}
|
|
136
|
-
/**
|
|
137
|
-
* Standard iterative dominator sets over STRUCTURAL edges from `entry` (dom(entry) = {entry}). Both the node-set
|
|
138
|
-
* and the predecessor graph use the structural edge model — a catch/escalate route is a failure path where the
|
|
139
|
-
* producer did not successfully run, so it is excluded from "ran before the consumer on every path".
|
|
140
|
-
*/
|
|
141
126
|
function dominators(template, entry) {
|
|
142
127
|
const reachable = [...forwardReach(template, entry)].filter((id) => template.nodes[id]);
|
|
143
128
|
const preds = new Map();
|
|
@@ -182,7 +167,6 @@ function dominators(template, entry) {
|
|
|
182
167
|
}
|
|
183
168
|
return dom;
|
|
184
169
|
}
|
|
185
|
-
/** For each node, the cycles (node-sets) it sits on — feeds the loop-freshness check (CONSUMES_STALE_RISK). */
|
|
186
170
|
function consumerStaleCycles(template) {
|
|
187
171
|
const out = new Map();
|
|
188
172
|
for (const { from, to } of findBackEdges(template)) {
|
|
@@ -195,7 +179,6 @@ function consumerStaleCycles(template) {
|
|
|
195
179
|
}
|
|
196
180
|
return out;
|
|
197
181
|
}
|
|
198
|
-
/** Map each node to ALL its (parallel, branch) memberships — a node in nested parallels belongs to each. */
|
|
199
182
|
function branchMembership(template) {
|
|
200
183
|
const out = new Map();
|
|
201
184
|
for (const par of Object.values(template.nodes)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-dataflow.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-dataflow.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EACd,UAAU,EACV,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"validate-dataflow.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-dataflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,25 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* validate-diff — §12 rule 13, the template diff classifier. Classifies the change from one template
|
|
3
|
-
* to another (it does not validate a single template — that is validateTemplate's job). Lifted from
|
|
4
|
-
* validate.ts as a separate public-API surface; validate.ts re-exports it so callers are unaffected.
|
|
5
|
-
*/
|
|
6
1
|
import { outgoingEdges } from './validate-edges.js';
|
|
7
|
-
/**
|
|
8
|
-
* Classify the change from `old` → `next` (§12.13). The enabler for a FUTURE in-flight migration; v1
|
|
9
|
-
* only reports.
|
|
10
|
-
* - node-id delete / rename / kind-change → breaking
|
|
11
|
-
* - changing the outgoing topology of an existing node → breaking
|
|
12
|
-
* - reusing a deleted id with a different kind/resultSchema → invalid
|
|
13
|
-
* - displayName / prompt / payload changes → safe
|
|
14
|
-
* - ANY field/path not explicitly classified → breaking (conservative) + DIFF_UNCLASSIFIED
|
|
15
|
-
*/
|
|
16
2
|
export function classifyTemplateDiff(old, next) {
|
|
17
3
|
const acc = newDiffAccumulator();
|
|
18
4
|
const oldNodes = old.nodes ?? {};
|
|
19
5
|
const nextNodes = next.nodes ?? {};
|
|
20
6
|
const oldIds = new Set(Object.keys(oldNodes));
|
|
21
7
|
const nextIds = new Set(Object.keys(nextNodes));
|
|
22
|
-
// Deleted ids → breaking.
|
|
23
8
|
for (const id of oldIds) {
|
|
24
9
|
if (!nextIds.has(id)) {
|
|
25
10
|
acc.escalate('breaking');
|
|
@@ -28,8 +13,6 @@ export function classifyTemplateDiff(old, next) {
|
|
|
28
13
|
}
|
|
29
14
|
for (const id of nextIds) {
|
|
30
15
|
const before = oldNodes[id];
|
|
31
|
-
// A brand-new node id is additive → safe (a new branch/path); reusing a PREVIOUSLY-deleted id is
|
|
32
|
-
// not observable here (single old/next pair). Adding a node is classified safe.
|
|
33
16
|
if (before)
|
|
34
17
|
classifyExistingNodeChange(id, before, nextNodes[id], acc);
|
|
35
18
|
}
|
|
@@ -49,11 +32,9 @@ function newDiffAccumulator() {
|
|
|
49
32
|
};
|
|
50
33
|
return acc;
|
|
51
34
|
}
|
|
52
|
-
/** Classify the change of a node id present in BOTH templates (kind / schema / topology / fields). */
|
|
53
35
|
function classifyExistingNodeChange(id, before, after, acc) {
|
|
54
|
-
// kind change → breaking; an incompatible kind/resultSchema reuse → invalid.
|
|
55
36
|
if (before.kind !== after.kind) {
|
|
56
|
-
acc.escalate('invalid');
|
|
37
|
+
acc.escalate('invalid');
|
|
57
38
|
acc.diagnostics.push({
|
|
58
39
|
code: 'DIFF_ID_REUSED_INCOMPATIBLE',
|
|
59
40
|
severity: 'error',
|
|
@@ -62,7 +43,6 @@ function classifyExistingNodeChange(id, before, after, acc) {
|
|
|
62
43
|
});
|
|
63
44
|
return;
|
|
64
45
|
}
|
|
65
|
-
// resultSchema change on a same-kind effect node → invalid (id reuse with different contract).
|
|
66
46
|
const beforeSchema = before.resultSchema;
|
|
67
47
|
const afterSchema = after.resultSchema;
|
|
68
48
|
if (beforeSchema !== afterSchema) {
|
|
@@ -74,7 +54,6 @@ function classifyExistingNodeChange(id, before, after, acc) {
|
|
|
74
54
|
nodeId: id,
|
|
75
55
|
});
|
|
76
56
|
}
|
|
77
|
-
// Outgoing topology change → breaking.
|
|
78
57
|
if (!sameTopology(before, after)) {
|
|
79
58
|
acc.escalate('breaking');
|
|
80
59
|
acc.diagnostics.push({
|
|
@@ -84,7 +63,6 @@ function classifyExistingNodeChange(id, before, after, acc) {
|
|
|
84
63
|
nodeId: id,
|
|
85
64
|
});
|
|
86
65
|
}
|
|
87
|
-
// Any non-safe-classified, non-topology field change defaults to breaking + DIFF_UNCLASSIFIED.
|
|
88
66
|
const unclassified = unclassifiedFieldChange(before, after);
|
|
89
67
|
if (unclassified) {
|
|
90
68
|
acc.escalate('breaking');
|
|
@@ -96,7 +74,6 @@ function classifyExistingNodeChange(id, before, after, acc) {
|
|
|
96
74
|
});
|
|
97
75
|
}
|
|
98
76
|
}
|
|
99
|
-
/** Top-level structural changes (entry / scopes) default to breaking if changed. */
|
|
100
77
|
function classifyTopLevelDiff(old, next, acc) {
|
|
101
78
|
if (old.entry !== next.entry) {
|
|
102
79
|
acc.escalate('breaking');
|
|
@@ -107,7 +84,6 @@ function classifyTopLevelDiff(old, next, acc) {
|
|
|
107
84
|
acc.diagnostics.push({ code: 'DIFF_UNCLASSIFIED', severity: 'error', message: `scopes changed (defaulting to breaking)` });
|
|
108
85
|
}
|
|
109
86
|
}
|
|
110
|
-
/** Two nodes have the same outgoing topology iff their ordered edge `[path,target]` sets match. */
|
|
111
87
|
function sameTopology(a, b) {
|
|
112
88
|
const ea = JSON.stringify(orderedEdges(a));
|
|
113
89
|
const eb = JSON.stringify(orderedEdges(b));
|
|
@@ -118,7 +94,6 @@ function orderedEdges(node) {
|
|
|
118
94
|
.slice()
|
|
119
95
|
.sort((x, y) => comparePath(x[0], y[0]));
|
|
120
96
|
}
|
|
121
|
-
/** Stable lexical comparison of two edge paths (sort comparator: -1 / 0 / 1). */
|
|
122
97
|
function comparePath(a, b) {
|
|
123
98
|
if (a < b)
|
|
124
99
|
return -1;
|
|
@@ -126,15 +101,7 @@ function comparePath(a, b) {
|
|
|
126
101
|
return 1;
|
|
127
102
|
return 0;
|
|
128
103
|
}
|
|
129
|
-
/**
|
|
130
|
-
* Detect a field change that is NOT one of the explicitly-SAFE fields (displayName, reason/prompt-like
|
|
131
|
-
* text, payload `input`) and NOT topology (handled separately). Returns a comma-list of changed
|
|
132
|
-
* unclassified keys, or '' if every change is safe. Guards (`branches.when`, `joinMode`, `merge`,
|
|
133
|
-
* `onFailure`, `incrementCounters`, `outcomes`, `timeout.after`) are NOT in the safe set → breaking.
|
|
134
|
-
*/
|
|
135
104
|
function unclassifiedFieldChange(before, after) {
|
|
136
|
-
// `input` is listed for parity with the doc above; it is a Decision field, not a Node key, so it never
|
|
137
|
-
// reaches this loop — harmless, and keeps the code aligned with its documented safe-set.
|
|
138
105
|
const SAFE_KEYS = new Set(['id', 'displayName', 'reason', 'input']);
|
|
139
106
|
const changed = [];
|
|
140
107
|
const keys = new Set([...Object.keys(before), ...Object.keys(after)]);
|
|
@@ -142,9 +109,9 @@ function unclassifiedFieldChange(before, after) {
|
|
|
142
109
|
if (SAFE_KEYS.has(key))
|
|
143
110
|
continue;
|
|
144
111
|
if (isTopologyKey(key))
|
|
145
|
-
continue;
|
|
112
|
+
continue;
|
|
146
113
|
if (key === 'resultSchema')
|
|
147
|
-
continue;
|
|
114
|
+
continue;
|
|
148
115
|
const bv = JSON.stringify(before[key]);
|
|
149
116
|
const av = JSON.stringify(after[key]);
|
|
150
117
|
if (bv !== av)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-diff.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-diff.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate-diff.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* validate-edges — the single model of a node's outgoing edges, shared by the refs (rule 2), topology
|
|
3
|
-
* (rule 3), reachability (rule 5), loop (rule 6), and diff (rule 13) rules. One edge model so those
|
|
4
|
-
* rules cannot disagree about what a node points at.
|
|
5
|
-
*/
|
|
6
1
|
import { isDefaultBranch } from './types.js';
|
|
7
|
-
/** Every outgoing edge of a node as `[path, targetId]` pairs. */
|
|
8
2
|
export function outgoingEdges(node) {
|
|
9
3
|
const edges = [];
|
|
10
4
|
switch (node.kind) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-edges.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-edges.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate-edges.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-edges.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAI7C,MAAM,UAAU,aAAa,CAAC,IAAU;IACtC,MAAM,KAAK,GAA4B,EAAE,CAAC;IAC1C,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ;YACX,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAChC,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/E,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YAC/E,MAAM;QACR,KAAK,MAAM;YACT,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAChC,MAAM;QACR,KAAK,MAAM;YACT,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAChC,MAAM;QACR,KAAK,WAAW;YACd,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACnF,IAAI,IAAI,CAAC,OAAO;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YAClE,MAAM;QACR,KAAK,QAAQ;YACX,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACnF,MAAM;QACR,KAAK,UAAU;YACb,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC/E,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAChC,MAAM;QACR,KAAK,UAAU;YACb,MAAM;IACV,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,QAAkB;IACvC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAoB,EAAE,CAC7C,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAC7E,CAAC;AACJ,CAAC"}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { isGuardedBranch } from './types.js';
|
|
2
2
|
import { outgoingEdges } from './validate-edges.js';
|
|
3
|
-
/** Forward (non-catch, non-escalate) edges — `catch`/`escalateTo` are failure routes, not loop edges. */
|
|
4
3
|
export function structuralEdges(node) {
|
|
5
4
|
return outgoingEdges(node).filter(([p]) => !p.startsWith('catch') && p !== 'escalateTo');
|
|
6
5
|
}
|
|
7
|
-
/** Nodes reachable from `entry` over EVERY outgoing edge (catch/escalate included). */
|
|
8
6
|
export function reachableFrom(template, entry) {
|
|
9
7
|
const seen = new Set();
|
|
10
8
|
const stack = [entry];
|
|
@@ -22,7 +20,6 @@ export function reachableFrom(template, entry) {
|
|
|
22
20
|
}
|
|
23
21
|
return seen;
|
|
24
22
|
}
|
|
25
|
-
/** Nodes structurally reachable from `start` (catch/escalate excluded — failure routes are not flow). */
|
|
26
23
|
export function forwardReach(template, start) {
|
|
27
24
|
const seen = new Set();
|
|
28
25
|
const stack = [start];
|
|
@@ -39,7 +36,6 @@ export function forwardReach(template, start) {
|
|
|
39
36
|
}
|
|
40
37
|
return seen;
|
|
41
38
|
}
|
|
42
|
-
/** Nodes that can structurally reach `target` (predecessor walk over structural edges). */
|
|
43
39
|
export function backwardReach(template, target) {
|
|
44
40
|
const preds = new Map();
|
|
45
41
|
for (const node of Object.values(template.nodes)) {
|
|
@@ -59,7 +55,6 @@ export function backwardReach(template, target) {
|
|
|
59
55
|
}
|
|
60
56
|
return seen;
|
|
61
57
|
}
|
|
62
|
-
/** Back-edges = forward edges whose target is an ancestor on the DFS stack (a cycle re-entry). */
|
|
63
58
|
export function findBackEdges(template) {
|
|
64
59
|
const back = [];
|
|
65
60
|
const onStack = new Set();
|
|
@@ -82,11 +77,7 @@ export function findBackEdges(template) {
|
|
|
82
77
|
dfs(template.entry);
|
|
83
78
|
return back;
|
|
84
79
|
}
|
|
85
|
-
/** Nodes on a cycle that re-enters `to` via the back-edge from `from` (path to→…→from + from). */
|
|
86
80
|
export function cycleNodes(template, to, from) {
|
|
87
|
-
// Forward-reachable from `to` (staying inside the SCC reaching `from`) — a simple over-approx is the
|
|
88
|
-
// set of nodes on some path to→…→from. We collect nodes that can both reach `from` and are reached
|
|
89
|
-
// from `to`, which is exactly the cycle's SCC member set for these structural edges.
|
|
90
81
|
const fromTo = forwardReach(template, to);
|
|
91
82
|
const canReachFrom = backwardReach(template, from);
|
|
92
83
|
const cycle = new Set();
|
|
@@ -97,7 +88,6 @@ export function cycleNodes(template, to, from) {
|
|
|
97
88
|
cycle.add(from);
|
|
98
89
|
return cycle;
|
|
99
90
|
}
|
|
100
|
-
/** Nodes reachable from a branch `entry`, stopping AT the join (the join itself is not a member). */
|
|
101
91
|
export function branchSubgraph(template, entry, joinId) {
|
|
102
92
|
const seen = new Set();
|
|
103
93
|
const stack = [entry];
|
|
@@ -114,7 +104,6 @@ export function branchSubgraph(template, entry, joinId) {
|
|
|
114
104
|
}
|
|
115
105
|
return seen;
|
|
116
106
|
}
|
|
117
|
-
/** Every guard Condition on a node (choice/humanGate branches that carry a `when`). */
|
|
118
107
|
export function guardConditionsOf(node) {
|
|
119
108
|
if (node.kind !== 'choice' && node.kind !== 'humanGate')
|
|
120
109
|
return [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-graph.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"validate-graph.js","sourceRoot":"","sources":["../../src/pipeline-core/validate-graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
import { isGuardedBranch } from './types.js';
|
|
2
|
-
import { backwardReach, cycleNodes, findBackEdges, forwardReach, guardConditionsOf } from './validate-graph.js';
|
|
3
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
-
// Rule 6b — loop-cap presence.
|
|
5
|
-
//
|
|
6
|
-
// Spec note (two ambiguities resolved against the canonical §13 example, which §13 declares
|
|
7
|
-
// internally-consistent and the task names as THE fixture):
|
|
8
|
-
// 1. §12.6 says "a terminating cap-guard (counter.gte)", but §13 expresses the SAME bound as
|
|
9
|
-
// `counter.lt K` on the CONTINUE edge with the default routing OUT (once the counter reaches K the
|
|
10
|
-
// guard fails and control falls through to blockedEnd). Both make the loop finite, so we accept
|
|
11
|
-
// EITHER: a cycle is counter-bounded iff some `choice` on it has a guard referencing a `counter.*`
|
|
12
|
-
// over a scope INCREMENTED on the cycle.
|
|
13
|
-
// 2. §13's analyst↔planGate `changes_requested` loop carries NO counter — it is bounded only by human
|
|
14
|
-
// judgment. §6 makes a human-driven loop legitimately unbounded ("durable wait is free … for
|
|
15
|
-
// human-driven runs"). So a cycle that passes through a `humanGate` is also accepted.
|
|
16
|
-
// An AUTOMATED loop (agents/scripts/choices only) with no counter is rejected (LOOP_UNBOUNDED).
|
|
17
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
import { backwardReach, branchSubgraph, cycleNodes, findBackEdges, forwardReach, guardConditionsOf } from './validate-graph.js';
|
|
18
3
|
export function ruleLoopCap(template, d) {
|
|
19
4
|
if (!template.entry || !template.nodes[template.entry])
|
|
20
5
|
return;
|
|
@@ -30,7 +15,6 @@ export function ruleLoopCap(template, d) {
|
|
|
30
15
|
}
|
|
31
16
|
}
|
|
32
17
|
}
|
|
33
|
-
/** Scope ids incremented by any node on the cycle (the loop's bound must count one of these). */
|
|
34
18
|
function scopesIncrementedOnCycle(template, cycle) {
|
|
35
19
|
const out = new Set();
|
|
36
20
|
for (const id of cycle) {
|
|
@@ -41,14 +25,12 @@ function scopesIncrementedOnCycle(template, cycle) {
|
|
|
41
25
|
}
|
|
42
26
|
return out;
|
|
43
27
|
}
|
|
44
|
-
/** A choice with a guard that references a `counter.*` over a scope incremented on the cycle. */
|
|
45
28
|
function choiceGatesCycleByCounter(template, id, incrementedOnCycle) {
|
|
46
29
|
const node = template.nodes[id];
|
|
47
30
|
if (node?.kind !== 'choice')
|
|
48
31
|
return false;
|
|
49
32
|
return node.branches.filter(isGuardedBranch).some((b) => conditionGatesOnScopes(b.when, incrementedOnCycle));
|
|
50
33
|
}
|
|
51
|
-
/** True when `cond` compares a `counter.*` against one of `scopes`. */
|
|
52
34
|
function conditionGatesOnScopes(cond, scopes) {
|
|
53
35
|
switch (cond.op) {
|
|
54
36
|
case 'counter.lt':
|
|
@@ -63,20 +45,16 @@ function conditionGatesOnScopes(cond, scopes) {
|
|
|
63
45
|
return false;
|
|
64
46
|
}
|
|
65
47
|
}
|
|
66
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
67
|
-
// Rule 7 — counter-scope well-formedness.
|
|
68
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
69
48
|
export function ruleCounterScopes(template, d) {
|
|
70
49
|
const scopes = template.scopes ?? {};
|
|
71
50
|
const scopeIds = new Set(Object.keys(scopes));
|
|
72
|
-
checkScopeParentsAndCycles(scopes, scopeIds, d);
|
|
73
|
-
checkScopesDeclared(template, scopeIds, d);
|
|
51
|
+
checkScopeParentsAndCycles(scopes, scopeIds, d);
|
|
52
|
+
checkScopesDeclared(template, scopeIds, d);
|
|
74
53
|
for (const scopeId of scopeIds)
|
|
75
|
-
checkScopeStrictAncestry(template, scopeId, d);
|
|
54
|
+
checkScopeStrictAncestry(template, scopeId, d);
|
|
76
55
|
for (const scopeId of Object.keys(scopes))
|
|
77
|
-
checkScopeDoesNotSpanParallel(template, scopeId, d);
|
|
56
|
+
checkScopeDoesNotSpanParallel(template, scopeId, d);
|
|
78
57
|
}
|
|
79
|
-
/** 7a — every scope's parent resolves to a declared scope and the parent chain has no cycle. */
|
|
80
58
|
function checkScopeParentsAndCycles(scopes, scopeIds, d) {
|
|
81
59
|
for (const [scopeId, scope] of Object.entries(scopes)) {
|
|
82
60
|
if (scope.parent !== null && !scopeIds.has(scope.parent)) {
|
|
@@ -91,7 +69,6 @@ function checkScopeParentsAndCycles(scopes, scopeIds, d) {
|
|
|
91
69
|
}
|
|
92
70
|
}
|
|
93
71
|
}
|
|
94
|
-
/** 7b — every scope referenced by a node (increment or guard) is declared. */
|
|
95
72
|
function checkScopesDeclared(template, scopeIds, d) {
|
|
96
73
|
for (const node of Object.values(template.nodes)) {
|
|
97
74
|
for (const scopeRef of referencedScopes(node)) {
|
|
@@ -104,14 +81,6 @@ function checkScopesDeclared(template, scopeIds, d) {
|
|
|
104
81
|
}
|
|
105
82
|
}
|
|
106
83
|
}
|
|
107
|
-
/**
|
|
108
|
-
* 7c — a reset scope is a STRICT ancestor of every node that reads/increments it (§7/§12.7). The scope's
|
|
109
|
-
* region is its loop sub-graph: the node(s) that increment it + the guard node(s) that read it. A
|
|
110
|
-
* well-formed reader sits inside that loop — i.e. it shares a cycle with an increment site, or is
|
|
111
|
-
* forward-reachable from one (the cap-guard reads after a rework hop). A reader disconnected from
|
|
112
|
-
* every increment site is a cross-scope/out-of-scope reference; a scope read but never incremented
|
|
113
|
-
* can never advance (its cap is dead). Both are SCOPE_NOT_STRICT_ANCESTOR.
|
|
114
|
-
*/
|
|
115
84
|
function checkScopeStrictAncestry(template, scopeId, d) {
|
|
116
85
|
const incrementSites = nodesIncrementing(template, scopeId);
|
|
117
86
|
const readers = nodesReadingScope(template, scopeId);
|
|
@@ -134,24 +103,48 @@ function checkScopeStrictAncestry(template, scopeId, d) {
|
|
|
134
103
|
}
|
|
135
104
|
}
|
|
136
105
|
}
|
|
137
|
-
/**
|
|
138
|
-
* 7d — a counter scope may not span a parallel/join boundary (v1). The region is the increment/read endpoints
|
|
139
|
-
* PLUS every node on a structural path between them: a counter incremented before a fan-out and read after the
|
|
140
|
-
* join (or whose endpoints sit in different branches) crosses the boundary and is unsafe in v1.
|
|
141
|
-
*/
|
|
142
106
|
function checkScopeDoesNotSpanParallel(template, scopeId, d) {
|
|
143
|
-
const
|
|
107
|
+
const incrementSites = nodesIncrementing(template, scopeId);
|
|
108
|
+
const readers = nodesReadingScope(template, scopeId);
|
|
109
|
+
const region = scopeRegionBetween(template, incrementSites, readers);
|
|
110
|
+
const endpoints = new Set([...incrementSites, ...readers]);
|
|
144
111
|
for (const id of region) {
|
|
145
112
|
const node = template.nodes[id];
|
|
146
|
-
if (node
|
|
113
|
+
if (node?.kind === 'parallel' && parallelBranchTouchesScope(template, node, endpoints)) {
|
|
147
114
|
d.error('SCOPE_SPANS_PARALLEL', `scope "${scopeId}" spans a ${node.kind} boundary (${id})`, {
|
|
148
115
|
nodeId: id,
|
|
149
116
|
scope: scopeId,
|
|
150
117
|
});
|
|
151
118
|
}
|
|
119
|
+
else if (node?.kind === 'join') {
|
|
120
|
+
const owners = Object.values(template.nodes).filter((candidate) => candidate.kind === 'parallel' && candidate.join === id && region.has(candidate.id));
|
|
121
|
+
const safeJoin = owners.length > 0 &&
|
|
122
|
+
owners.every((owner) => owner.kind === 'parallel' && !parallelBranchTouchesScope(template, owner, endpoints));
|
|
123
|
+
if (!safeJoin) {
|
|
124
|
+
d.error('SCOPE_SPANS_PARALLEL', `scope "${scopeId}" spans a ${node.kind} boundary (${id})`, {
|
|
125
|
+
nodeId: id,
|
|
126
|
+
scope: scopeId,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function parallelBranchTouchesScope(template, parallelNode, endpoints) {
|
|
133
|
+
const interior = parallelBranchInterior(template, parallelNode);
|
|
134
|
+
for (const endpoint of endpoints) {
|
|
135
|
+
if (interior.has(endpoint))
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
function parallelBranchInterior(template, parallelNode) {
|
|
141
|
+
const seen = new Set();
|
|
142
|
+
for (const branch of parallelNode.branches) {
|
|
143
|
+
for (const id of branchSubgraph(template, branch.entry, parallelNode.join))
|
|
144
|
+
seen.add(id);
|
|
152
145
|
}
|
|
146
|
+
return seen;
|
|
153
147
|
}
|
|
154
|
-
/** Endpoints plus every node on some structural path from an increment site to a reader (forwardReach ∩ backwardReach). */
|
|
155
148
|
function scopeRegionBetween(template, incrementSites, readers) {
|
|
156
149
|
const region = new Set([...incrementSites, ...readers]);
|
|
157
150
|
for (const inc of incrementSites) {
|