stageflow 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -3
- package/dist/a2a/contracts.d.ts +1 -0
- package/dist/a2a/contracts.js +1 -0
- package/dist/a2a/registry.d.ts +2 -0
- package/dist/a2a/registry.js +20 -1
- package/dist/a2a/server.d.ts +7 -0
- package/dist/a2a/server.js +5 -2
- package/dist/a2a/service.d.ts +1 -1
- package/dist/a2a/service.js +57 -8
- package/dist/a2a/store.d.ts +8 -5
- package/dist/a2a/store.js +24 -67
- package/dist/agent/activity.d.ts +3 -0
- package/dist/agent/bootProviderConfig.d.ts +21 -0
- package/dist/agent/bootProviderConfig.js +74 -0
- package/dist/agent/piAdapter.d.ts +9 -1
- package/dist/agent/piAdapter.js +58 -3
- package/dist/agent/piIsolatedMcp.d.ts +2 -0
- package/dist/agent/piIsolatedMcp.js +10 -2
- package/dist/agent/port.d.ts +6 -0
- package/dist/agent/streamLogRedact.d.ts +1 -1
- package/dist/agent/streamLogRedact.js +4 -11
- package/dist/cli/artifactCommand.js +9 -16
- package/dist/cli/backupCommand.d.ts +9 -0
- package/dist/cli/backupCommand.js +111 -0
- package/dist/cli/debugRunCommand.d.ts +10 -0
- package/dist/cli/debugRunCommand.js +109 -0
- package/dist/cli/doctorCommand.d.ts +32 -0
- package/dist/cli/doctorCommand.js +453 -0
- package/dist/cli/envelopeCommand.js +9 -2
- package/dist/cli/exportAllCommand.d.ts +55 -0
- package/dist/cli/exportAllCommand.js +218 -0
- package/dist/cli/exportRunCommand.js +23 -21
- package/dist/cli/hostClient.d.ts +21 -3
- package/dist/cli/hostClient.js +93 -12
- package/dist/cli/initTemplates.d.ts +1 -1
- package/dist/cli/initTemplates.js +8 -1
- package/dist/cli/resolveSafeOutPath.d.ts +2 -0
- package/dist/cli/resolveSafeOutPath.js +40 -0
- package/dist/cli/restoreCommand.d.ts +10 -0
- package/dist/cli/restoreCommand.js +90 -0
- package/dist/cli/runCommand.d.ts +3 -2
- package/dist/cli/runCommand.js +93 -11
- package/dist/cli/runOutput.d.ts +4 -0
- package/dist/cli/runOutput.js +33 -7
- package/dist/cli/runStageCommand.d.ts +1 -0
- package/dist/cli/runStageCommand.js +44 -25
- package/dist/cli/runsCommand.d.ts +1 -1
- package/dist/cli/runsCommand.js +162 -8
- package/dist/cli.js +171 -30
- package/dist/config/catalogRelativePath.d.ts +62 -0
- package/dist/config/catalogRelativePath.js +118 -0
- package/dist/config/configOrigin.d.ts +27 -0
- package/dist/config/configOrigin.js +59 -0
- package/dist/config/hostConfig.d.ts +55 -0
- package/dist/config/hostConfig.js +333 -0
- package/dist/config/listSkills.d.ts +26 -0
- package/dist/config/listSkills.js +190 -3
- package/dist/config/loadOutcome.d.ts +1 -1
- package/dist/config/loadPipeline.js +23 -2
- package/dist/config/loadStage.js +18 -0
- package/dist/config/loadTask.d.ts +2 -0
- package/dist/config/loadTask.js +57 -18
- package/dist/config/materializeStageModels.js +5 -1
- package/dist/config/mergePipelineIncludes.d.ts +3 -0
- package/dist/config/mergePipelineIncludes.js +19 -0
- package/dist/config/migrateYaml.js +6 -11
- package/dist/config/multiProjectCatalog.d.ts +30 -0
- package/dist/config/multiProjectCatalog.js +142 -0
- package/dist/config/normalizePipelineStageEntry.js +20 -1
- package/dist/config/pipelineStageKeys.js +2 -0
- package/dist/config/resolveCatalogRoots.d.ts +27 -0
- package/dist/config/resolveCatalogRoots.js +76 -0
- package/dist/config/resolveModel.d.ts +7 -1
- package/dist/config/resolveModel.js +11 -1
- package/dist/config/resolveStageMcpServers.d.ts +9 -1
- package/dist/config/resolveStageMcpServers.js +36 -9
- package/dist/config/secretFromEnvOrFile.d.ts +9 -0
- package/dist/config/secretFromEnvOrFile.js +34 -0
- package/dist/config/seededCatalog.d.ts +11 -0
- package/dist/config/seededCatalog.js +29 -0
- package/dist/config/toolRequires.d.ts +24 -0
- package/dist/config/toolRequires.js +115 -0
- package/dist/config/validateCatalog.d.ts +5 -1
- package/dist/config/validateCatalog.js +140 -1
- package/dist/diagnostics/checks.d.ts +39 -0
- package/dist/diagnostics/checks.js +135 -0
- package/dist/errors/codes.d.ts +14 -0
- package/dist/errors/codes.js +59 -0
- package/dist/git/cache.d.ts +14 -0
- package/dist/git/cache.js +150 -0
- package/dist/git/credentials.d.ts +9 -0
- package/dist/git/credentials.js +88 -0
- package/dist/git/errors.d.ts +20 -0
- package/dist/git/errors.js +94 -0
- package/dist/git/exec.d.ts +16 -0
- package/dist/git/exec.js +135 -0
- package/dist/git/operations.d.ts +29 -0
- package/dist/git/operations.js +153 -0
- package/dist/git/version.d.ts +1 -0
- package/dist/git/version.js +10 -0
- package/dist/logging/audit.d.ts +16 -0
- package/dist/logging/audit.js +19 -0
- package/dist/logging/commonWords.d.ts +2 -0
- package/dist/logging/commonWords.js +13 -0
- package/dist/logging/logger.d.ts +49 -0
- package/dist/logging/logger.js +193 -0
- package/dist/logging/namedSecrets.d.ts +6 -0
- package/dist/logging/namedSecrets.js +58 -0
- package/dist/logging/redact.d.ts +13 -0
- package/dist/logging/redact.js +88 -0
- package/dist/mcp/catalogTools.js +456 -80
- package/dist/mcp/checkoutTools.d.ts +52 -0
- package/dist/mcp/checkoutTools.js +332 -0
- package/dist/mcp/controlTools.js +179 -5
- package/dist/mcp/deps.d.ts +1 -0
- package/dist/mcp/getStartedTool.d.ts +3 -0
- package/dist/mcp/getStartedTool.js +62 -0
- package/dist/mcp/readArtifact.d.ts +11 -0
- package/dist/mcp/readArtifact.js +46 -30
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/tools.js +4 -0
- package/dist/net/proxy.d.ts +14 -0
- package/dist/net/proxy.js +78 -0
- package/dist/package-meta.d.ts +2 -1
- package/dist/package-meta.js +2 -1
- package/dist/preflight/bash.d.ts +8 -0
- package/dist/preflight/bash.js +34 -0
- package/dist/preflight/claudeRoot.d.ts +11 -0
- package/dist/preflight/claudeRoot.js +23 -0
- package/dist/preflight/mcpCommands.d.ts +8 -0
- package/dist/preflight/mcpCommands.js +36 -0
- package/dist/preflight/pipelinePreflight.d.ts +40 -0
- package/dist/preflight/pipelinePreflight.js +192 -0
- package/dist/preflight/tls.d.ts +6 -0
- package/dist/preflight/tls.js +18 -0
- package/dist/preflight/toolchain.d.ts +45 -0
- package/dist/preflight/toolchain.js +219 -0
- package/dist/project/findProjectRoot.js +3 -4
- package/dist/project/globalHome.d.ts +7 -0
- package/dist/project/globalHome.js +63 -2
- package/dist/project/resolveProjectContext.js +2 -2
- package/dist/project/resolveStageflowContext.js +2 -2
- package/dist/projection/projectRun.d.ts +2 -1
- package/dist/projection/projectRun.js +1 -0
- package/dist/runstore/assertTmpdir.d.ts +1 -0
- package/dist/runstore/assertTmpdir.js +21 -0
- package/dist/runstore/backup.d.ts +52 -0
- package/dist/runstore/backup.js +292 -0
- package/dist/runstore/createStore.d.ts +18 -1
- package/dist/runstore/createStore.js +64 -5
- package/dist/runstore/debugBundle.d.ts +60 -0
- package/dist/runstore/debugBundle.js +143 -0
- package/dist/runstore/diskUsage.d.ts +50 -0
- package/dist/runstore/diskUsage.js +214 -0
- package/dist/runstore/exportRunPayload.d.ts +8 -0
- package/dist/runstore/exportRunPayload.js +23 -0
- package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
- package/dist/runstore/normalizeCatalogPath.js +10 -0
- package/dist/runstore/paths.d.ts +5 -0
- package/dist/runstore/paths.js +145 -1
- package/dist/runstore/port.d.ts +111 -13
- package/dist/runstore/port.js +8 -1
- package/dist/runstore/restore.d.ts +81 -0
- package/dist/runstore/restore.js +355 -0
- package/dist/runstore/retention.d.ts +27 -0
- package/dist/runstore/retention.js +74 -0
- package/dist/runstore/runManifest.d.ts +146 -0
- package/dist/runstore/runManifest.js +288 -0
- package/dist/runstore/runProjection.d.ts +3 -1
- package/dist/runstore/runProjection.js +63 -1
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +28 -3
- package/dist/runstore/sqlite/SqliteRunStore.js +352 -219
- package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
- package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
- package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
- package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
- package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
- package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
- package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
- package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
- package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
- package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
- package/dist/runstore/sqlite/migrations/index.js +72 -0
- package/dist/runstore/sqlite/schema.d.ts +20 -1
- package/dist/runstore/sqlite/schema.js +277 -1
- package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
- package/dist/runstore/sqlite/storeOpenError.js +11 -0
- package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
- package/dist/runstore/sqlite/storeSchemaError.js +8 -0
- package/dist/runstore/stageExecution.js +3 -0
- package/dist/runstore/storeFilesystem.d.ts +32 -0
- package/dist/runstore/storeFilesystem.js +148 -0
- package/dist/runstore/trackProjection.js +2 -0
- package/dist/runstore/workspaceLayout.d.ts +13 -0
- package/dist/runstore/workspaceLayout.js +76 -0
- package/dist/runtime/completionCheckRunner.d.ts +3 -0
- package/dist/runtime/completionCheckRunner.js +45 -7
- package/dist/runtime/containerLimits.d.ts +16 -0
- package/dist/runtime/containerLimits.js +84 -0
- package/dist/runtime/credentialMaterialisation.d.ts +28 -0
- package/dist/runtime/credentialMaterialisation.js +128 -0
- package/dist/runtime/gitCheckoutCapability.js +7 -13
- package/dist/runtime/pipelineRunner.d.ts +36 -1
- package/dist/runtime/pipelineRunner.js +178 -17
- package/dist/runtime/pipelineScheduler.d.ts +15 -0
- package/dist/runtime/pipelineScheduler.js +135 -27
- package/dist/runtime/reloadRunCatalog.js +6 -1
- package/dist/runtime/repositoryMaterialize.d.ts +47 -0
- package/dist/runtime/repositoryMaterialize.js +235 -0
- package/dist/runtime/resumeTimedOut.d.ts +1 -1
- package/dist/runtime/resumeTimedOut.js +5 -2
- package/dist/runtime/runChangeBus.js +9 -0
- package/dist/runtime/runDeletion.d.ts +7 -0
- package/dist/runtime/runDeletion.js +37 -0
- package/dist/runtime/runManager.d.ts +158 -4
- package/dist/runtime/runManager.js +1596 -79
- package/dist/runtime/runRetentionSweep.d.ts +31 -0
- package/dist/runtime/runRetentionSweep.js +328 -0
- package/dist/runtime/runRetryCoordinator.d.ts +2 -0
- package/dist/runtime/runRetryCoordinator.js +19 -2
- package/dist/runtime/runSkills.d.ts +40 -0
- package/dist/runtime/runSkills.js +173 -0
- package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
- package/dist/runtime/stageAttemptBootstrap.js +195 -24
- package/dist/runtime/stageCacheEnv.d.ts +6 -0
- package/dist/runtime/stageCacheEnv.js +34 -0
- package/dist/runtime/stageConcurrency.d.ts +2 -1
- package/dist/runtime/stageConcurrency.js +4 -2
- package/dist/runtime/stageEnvironment.d.ts +38 -0
- package/dist/runtime/stageEnvironment.js +193 -0
- package/dist/runtime/stageProcessLauncher.d.ts +18 -0
- package/dist/runtime/stageProcessLauncher.js +194 -38
- package/dist/runtime/stageRecovery.d.ts +3 -1
- package/dist/runtime/stageRecovery.js +19 -4
- package/dist/runtime/stageRoots.d.ts +38 -1
- package/dist/runtime/stageRoots.js +118 -0
- package/dist/runtime/stageRunner.d.ts +1 -0
- package/dist/runtime/stageRunner.js +3 -1
- package/dist/runtime/stageSecretDecl.d.ts +9 -0
- package/dist/runtime/stageSecretDecl.js +102 -0
- package/dist/runtime/stageSecrets.d.ts +40 -0
- package/dist/runtime/stageSecrets.js +181 -0
- package/dist/runtime/stageWorker.d.ts +3 -2
- package/dist/runtime/stageWorker.js +58 -10
- package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
- package/dist/runtime/stageWorkerProtocol.js +8 -0
- package/dist/runtime/startPayload.d.ts +32 -0
- package/dist/runtime/startPayload.js +59 -0
- package/dist/runtime/taskInput.js +14 -5
- package/dist/runtime/verifiedStageExecution.d.ts +1 -0
- package/dist/runtime/verifiedStageExecution.js +2 -1
- package/dist/runtime/workspaceBinding.d.ts +20 -0
- package/dist/runtime/workspaceBinding.js +60 -0
- package/dist/server/allowedHosts.d.ts +19 -0
- package/dist/server/allowedHosts.js +179 -0
- package/dist/server/bootstrap.d.ts +36 -2
- package/dist/server/bootstrap.js +209 -5
- package/dist/server/controlToken.d.ts +47 -0
- package/dist/server/controlToken.js +241 -0
- package/dist/server/createHttpHost.d.ts +11 -2
- package/dist/server/createHttpHost.js +103 -10
- package/dist/server/ensureGlobalService.d.ts +5 -1
- package/dist/server/ensureGlobalService.js +35 -1
- package/dist/server/healthSurfaces.d.ts +6 -0
- package/dist/server/healthSurfaces.js +98 -0
- package/dist/server/http.d.ts +12 -1
- package/dist/server/http.js +1085 -485
- package/dist/server/listenHost.d.ts +5 -0
- package/dist/server/listenHost.js +56 -0
- package/dist/server/mcpHost.d.ts +10 -1
- package/dist/server/mcpHost.js +36 -6
- package/dist/server/operatorResults.d.ts +2 -2
- package/dist/server/operatorResults.js +40 -29
- package/dist/server/requestAuthContext.d.ts +12 -0
- package/dist/server/requestAuthContext.js +21 -0
- package/dist/server/shutdown.d.ts +69 -0
- package/dist/server/shutdown.js +219 -0
- package/dist/types/pipeline.d.ts +7 -0
- package/dist/types/stage.d.ts +8 -0
- package/dist/types/task.d.ts +8 -0
- package/dist/ui/assets/index-B6hlSXXn.js +120 -0
- package/dist/ui/index.html +1 -1
- package/examples/README.md +98 -0
- package/examples/archify-on-pr/README.md +213 -0
- package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
- package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
- package/examples/archify-on-pr/author-diagrams.yaml +106 -0
- package/examples/archify-on-pr/detect-changes.yaml +89 -0
- package/examples/ci-validate/README.md +35 -0
- package/examples/ci-validate/check.yaml +13 -0
- package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
- package/examples/ci-validate/validate.sh +5 -0
- package/examples/compliance-review-demo/README.md +125 -0
- package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
- package/examples/compliance-review-demo/connect-account.yaml +47 -0
- package/examples/compliance-review-demo/map-to-control.yaml +123 -0
- package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
- package/examples/compliance-review-demo/publish-report.yaml +79 -0
- package/examples/compliance-review-demo/review-verdict.yaml +122 -0
- package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
- package/examples/compliance-review-demo/store-evidence.yaml +143 -0
- package/examples/conditional-fork/README.md +89 -0
- package/examples/conditional-fork/branch-a.yaml +13 -0
- package/examples/conditional-fork/branch-b.yaml +13 -0
- package/examples/conditional-fork/decide.yaml +35 -0
- package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
- package/examples/conditional-fork/fork-demo.task.yaml +8 -0
- package/examples/context7-mcp/README.md +42 -0
- package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
- package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
- package/examples/context7-mcp/fetch-docs.yaml +52 -0
- package/examples/context7-mcp/resolve-library.yaml +31 -0
- package/examples/context7-mcp/write-brief.yaml +52 -0
- package/examples/feature-loop/README.md +104 -0
- package/examples/feature-loop/address-feedback.yaml +148 -0
- package/examples/feature-loop/align.yaml +116 -0
- package/examples/feature-loop/decompose.yaml +86 -0
- package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
- package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
- package/examples/feature-loop/feature-loop.task.yaml +25 -0
- package/examples/feature-loop/implement.yaml +128 -0
- package/examples/feature-loop/plan.yaml +111 -0
- package/examples/feature-loop/publish.yaml +167 -0
- package/examples/feature-loop/review.yaml +146 -0
- package/examples/feature-loop/verify.yaml +106 -0
- package/examples/feedback-loop/README.md +72 -0
- package/examples/feedback-loop/VERIFY.md +208 -0
- package/examples/feedback-loop/continue-only.task.yaml +4 -0
- package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
- package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
- package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
- package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
- package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
- package/examples/feedback-loop/implement.yaml +14 -0
- package/examples/feedback-loop/plan.yaml +14 -0
- package/examples/feedback-loop/review.yaml +15 -0
- package/examples/feedback-loop/send-back-once.task.yaml +6 -0
- package/examples/feedback-loop/submit.yaml +12 -0
- package/examples/generic-fan-in/README.md +151 -0
- package/examples/generic-fan-in/clarify.yaml +18 -0
- package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
- package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
- package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
- package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
- package/examples/generic-fan-in/research.yaml +45 -0
- package/examples/generic-fan-in/synthesize.yaml +66 -0
- package/examples/generic-fan-in/validation.yaml +45 -0
- package/examples/github-release/README.md +78 -0
- package/examples/github-release/draft-release-notes.yaml +64 -0
- package/examples/github-release/github-release.pipeline.yaml +11 -0
- package/examples/github-release/github-release.task.yaml +13 -0
- package/examples/github-release/publish-github-release.yaml +64 -0
- package/examples/hello-world/README.md +28 -0
- package/examples/hello-world/hello.pipeline.yaml +4 -0
- package/examples/hello-world/my-task.task.yaml +6 -0
- package/examples/hello-world/research.yaml +18 -0
- package/examples/mcp-hitl-tour/README.md +113 -0
- package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
- package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
- package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
- package/examples/mcp-hitl-tour/gather.yaml +31 -0
- package/examples/mcp-hitl-tour/intake.yaml +62 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
- package/examples/mcp-hitl-tour/polish.yaml +33 -0
- package/examples/mcp-hitl-tour/review.yaml +17 -0
- package/examples/mcp-hitl-tour/ship.yaml +25 -0
- package/examples/oss-issue-contribution/README.md +218 -0
- package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
- package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
- package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
- package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
- package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
- package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
- package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
- package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
- package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
- package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
- package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
- package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
- package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
- package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
- package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
- package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
- package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
- package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
- package/examples/oss-quick-fix/README.md +65 -0
- package/examples/oss-quick-fix/implement-fix.yaml +84 -0
- package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
- package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
- package/examples/oss-quick-fix/ship-fix.yaml +81 -0
- package/examples/oss-quick-fix/understand-issue.yaml +67 -0
- package/examples/oss-quick-fix/verify-fix.yaml +73 -0
- package/examples/plan-review/README.md +37 -0
- package/examples/plan-review/plan-review-followup.yaml +13 -0
- package/examples/plan-review/plan-review.pipeline.yaml +9 -0
- package/examples/plan-review/plan-review.task.yaml +9 -0
- package/examples/plan-review/plan-review.yaml +25 -0
- package/examples/playwright-mcp/README.md +39 -0
- package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
- package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
- package/examples/playwright-mcp/screenshot.yaml +40 -0
- package/examples/retry-tour/README.md +75 -0
- package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
- package/examples/retry-tour/retry-tour.task.yaml +9 -0
- package/examples/route-if-tour/README.md +202 -0
- package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
- package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
- package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
- package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
- package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
- package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
- package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
- package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
- package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
- package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
- package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
- package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
- package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
- package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
- package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
- package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
- package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
- package/examples/route-wiring-smoke-test/README.md +377 -0
- package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
- package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
- package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
- package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
- package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
- package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
- package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
- package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
- package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
- package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
- package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
- package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
- package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
- package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
- package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
- package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
- package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
- package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
- package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
- package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
- package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
- package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
- package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
- package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
- package/examples/ship-feature/README.md +190 -0
- package/examples/ship-feature/feat-address-feedback.yaml +119 -0
- package/examples/ship-feature/feat-implement.yaml +180 -0
- package/examples/ship-feature/feat-plan.yaml +120 -0
- package/examples/ship-feature/feat-review.yaml +109 -0
- package/examples/ship-feature/feat-ship.yaml +203 -0
- package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
- package/examples/ship-feature/ship-feature.task.yaml +78 -0
- package/examples/stage-mcp/README.md +144 -0
- package/examples/stage-mcp/echo-mcp.mjs +20 -0
- package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
- package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
- package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
- package/examples/stage-mcp/use-echo.yaml +20 -0
- package/examples/verify-tour/README.md +80 -0
- package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
- package/examples/verify-tour/verify-tour.task.yaml +11 -0
- package/package.json +5 -1
- package/skills/stageflow/SKILL.md +6 -6
- package/skills/stageflow/references/control-surface.md +11 -5
- package/skills/stageflow/scripts/detect-host.mjs +14 -1
- package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
- package/skills/stageflow-author/SKILL.md +4 -3
- package/skills/stageflow-author/references/catalog-mapping.md +16 -0
- package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
- package/skills/stageflow-run/SKILL.md +20 -12
- package/skills/stageflow-run/references/mcp-call.md +9 -1
- package/skills/stageflow-run/references/task-and-pipeline-selection.md +16 -5
- package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
- package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
- package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
- package/skills/stageflow-setup/SKILL.md +40 -8
- package/dist/ui/assets/index-Da5EHU6M.js +0 -119
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Retry tour
|
|
2
|
+
|
|
3
|
+
One short spine that walks Stageflow’s **retry surfaces**. Each stage does one job. First passes are supposed to fail; later attempts (or a second emit in the same session) pass.
|
|
4
|
+
|
|
5
|
+
This catalog is a **deep spine**: ungated `to:` is the next stop. Open the stage after each stop and inspect **attempts** — automatic repair is a second attempt on the same node, not a new stage.
|
|
6
|
+
|
|
7
|
+
Two stops need you: **Retry with guidance** on `manual-recover`, then **Retry** on `ordinary-retry`.
|
|
8
|
+
|
|
9
|
+
## Run
|
|
10
|
+
|
|
11
|
+
From the repo git root, after `sf ui` is up, pick pipeline `retry-tour` and task `retry-tour`.
|
|
12
|
+
|
|
13
|
+
Or:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx tsx src/cli.ts validate --pipeline examples/retry-tour/retry-tour.pipeline.yaml
|
|
17
|
+
npx tsx src/cli.ts run \
|
|
18
|
+
--pipeline examples/retry-tour/retry-tour.pipeline.yaml \
|
|
19
|
+
--task examples/retry-tour/retry-tour.task.yaml
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Validate should succeed (`ok: true`). You may see `pipeline.model_applies` because `model` is set on the pipeline, not on each stage.
|
|
23
|
+
|
|
24
|
+
The run should **succeed** after the two operator actions below. If a model writes `proof.md` on attempt 1, that stop is not covered — rerun.
|
|
25
|
+
|
|
26
|
+
## Walk (follow-along order)
|
|
27
|
+
|
|
28
|
+
| Level | Stage | Retry surface | What you do |
|
|
29
|
+
|-------|-------|---------------|-------------|
|
|
30
|
+
| 1 | `kickoff` | none | Watch it succeed |
|
|
31
|
+
| 2 | `emit-retry` | Emit-phase verify soft reject | Same attempt: first emit is rejected (`note.md` missing), second emit succeeds. Attempt stays **1** |
|
|
32
|
+
| 3 | `auto-repair` | `on_verify_fail.mode: repair` | Attempt 1 omits `proof.md` → after-verify fails → Stageflow starts attempt 2 by itself. Attempt 2 writes `proof.md`. No click |
|
|
33
|
+
| 4 | `manual-recover` | `on_verify_fail.mode: manual` | Attempt 1 fails after-verify. Stage stays **failed**. Select it → type guidance (for example `Write proof.md this time`) → **Retry with guidance**. Do **not** use **Retry**. Do **not** **Stop recovery** |
|
|
34
|
+
| 5 | `ordinary-retry` | Ordinary **Retry** (no `on_verify_fail`) | Attempt 1 emits `status: failure`. Select it → **Retry**. Attempt 2 emits success |
|
|
35
|
+
| 6 | `done` | none | Runs only after `ordinary-retry` succeeds — proof that Retry unblocked the successor |
|
|
36
|
+
|
|
37
|
+
## Scenario table
|
|
38
|
+
|
|
39
|
+
| Scenario | How this pipeline covers it | Evidence |
|
|
40
|
+
|----------|------------------------------|----------|
|
|
41
|
+
| Emit-phase verify rejects in-session | `emit-retry` `type: artifact` `when: [emit]` | First `emit_stage_envelope` is `isError`; second emit is accepted; still attempt 1 |
|
|
42
|
+
| Emit reject does not fail the stage | same | Stage succeeds; no `on_verify_fail` |
|
|
43
|
+
| Automatic repair after after-phase fail | `auto-repair` `mode: repair` `max_attempts: 2` | Attempt 1 verification **failed**; attempt 2 **passed**; stage succeeded with no click |
|
|
44
|
+
| `max_attempts: 2` means 1 initial + 1 repair | same | Exactly two attempts on `auto-repair` |
|
|
45
|
+
| Failed-check capsule on repair | `include_failed_checks: true` | Attempt 2 prompt contains failed-check evidence for `proof-on-disk` |
|
|
46
|
+
| Repair is a fresh attempt | same | Attempt 2 has its own artifacts dir |
|
|
47
|
+
| Manual recovery (not auto) | `manual-recover` `mode: manual` `retry_safety: side_effecting` | After attempt 1 fail, stage stays failed until Recover |
|
|
48
|
+
| Ordinary **Retry** is refused here | same | Map/workspace **Retry** should 409; use **Retry with guidance** |
|
|
49
|
+
| Recover with guidance | operator types guidance | Attempt 2 prompt includes operator instructions + failed-check capsule |
|
|
50
|
+
| Ordinary Retry after agent failure | `ordinary-retry` emits `status: failure` | No after-verify; **Retry** is offered |
|
|
51
|
+
| Retry unblocks the successor | `done` | `done` does not start while `ordinary-retry` is failed; it runs after Retry succeeds |
|
|
52
|
+
|
|
53
|
+
## Expected stage status (after the full walk)
|
|
54
|
+
|
|
55
|
+
| Stage | Attempts | Final status | Why |
|
|
56
|
+
|-------|----------|--------------|-----|
|
|
57
|
+
| `kickoff` | 1 | succeeded | entry |
|
|
58
|
+
| `emit-retry` | 1 | succeeded | two emits, one attempt |
|
|
59
|
+
| `auto-repair` | 2 | succeeded | automatic repair |
|
|
60
|
+
| `manual-recover` | 2 | succeeded | you Recovered |
|
|
61
|
+
| `ordinary-retry` | 2 | succeeded | you Retried |
|
|
62
|
+
| `done` | 1 | succeeded | ungated after ordinary-retry success |
|
|
63
|
+
|
|
64
|
+
Mid-walk: after `auto-repair` succeeds, `manual-recover` is **failed** and the run looks failed until Recover. Then `ordinary-retry` is **failed** until Retry.
|
|
65
|
+
|
|
66
|
+
## Not in this pipeline
|
|
67
|
+
|
|
68
|
+
| Scenario | Why it is absent | Where to see it |
|
|
69
|
+
|---------|------------------|-----------------|
|
|
70
|
+
| Repair budget exhausted | would fail the stage after attempt 2 | `max_attempts: 2` with another miss; then ordinary Retry |
|
|
71
|
+
| **Stop recovery** | terminal fail for that stage this run | click it on `manual-recover` instead of Recover |
|
|
72
|
+
| Loop `send_back` / `max_replays` | different product (route loop) | [`examples/route-if-tour/`](../route-if-tour/), [`examples/feedback-loop/`](../feedback-loop/) |
|
|
73
|
+
| `on_verify_fail` with emit-only verify | illegal (`pipeline.invalid_recovery`) | yaml-catalog |
|
|
74
|
+
| `mode: repair` + `retry_safety: side_effecting` | illegal | yaml-catalog |
|
|
75
|
+
| Agent never emits (timeout / hang) | flaky | ordinary Retry after a real hang |
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
id: retry-tour
|
|
2
|
+
model: cursor/auto
|
|
3
|
+
schemas:
|
|
4
|
+
empty:
|
|
5
|
+
type: object
|
|
6
|
+
stages:
|
|
7
|
+
- id: kickoff
|
|
8
|
+
entry: true
|
|
9
|
+
route:
|
|
10
|
+
- to: emit-retry
|
|
11
|
+
system_prompt: |
|
|
12
|
+
Start the retry tour in one sentence.
|
|
13
|
+
Then emit a success envelope via emit_stage_envelope with status: success, a short summary, artifacts: [], and payload: {}.
|
|
14
|
+
io:
|
|
15
|
+
input:
|
|
16
|
+
schema:
|
|
17
|
+
$ref: "#/schemas/empty"
|
|
18
|
+
output:
|
|
19
|
+
schema:
|
|
20
|
+
$ref: "#/schemas/empty"
|
|
21
|
+
|
|
22
|
+
- id: emit-retry
|
|
23
|
+
route:
|
|
24
|
+
- to: auto-repair
|
|
25
|
+
system_prompt: |
|
|
26
|
+
Cover emit-phase verify soft reject (same attempt, not a new attempt).
|
|
27
|
+
You MUST call emit_stage_envelope twice:
|
|
28
|
+
1. First call: status: success, a one-sentence summary, artifacts: [], payload: {}. Do not write any artifact yet. This emit is rejected because note.md is missing — that is the scenario.
|
|
29
|
+
2. After that tool error: call write_stage_artifact with path note.md and a short nonempty markdown body. Then emit_stage_envelope again with status: success, a one-sentence summary, artifacts listing the path returned by write_stage_artifact, and payload: {}.
|
|
30
|
+
Do not skip the failing first emit. Do not call ask_operator.
|
|
31
|
+
io:
|
|
32
|
+
input:
|
|
33
|
+
schema:
|
|
34
|
+
$ref: "#/schemas/empty"
|
|
35
|
+
output:
|
|
36
|
+
schema:
|
|
37
|
+
$ref: "#/schemas/empty"
|
|
38
|
+
verify:
|
|
39
|
+
- id: note-declared
|
|
40
|
+
type: artifact
|
|
41
|
+
basename: note.md
|
|
42
|
+
when: [emit]
|
|
43
|
+
|
|
44
|
+
- id: auto-repair
|
|
45
|
+
route:
|
|
46
|
+
- to: manual-recover
|
|
47
|
+
system_prompt: |
|
|
48
|
+
Cover on_verify_fail.mode: repair. Look at the artifacts path in this prompt (stages/auto-repair/attempts/N/artifacts/).
|
|
49
|
+
If N is 1: call emit_stage_envelope with status: success, a one-sentence summary, artifacts: [], and payload: {}. Do not write proof.md. After-phase verify will fail and Stageflow will start attempt 2 by itself.
|
|
50
|
+
If N is 2 or greater, or the user message contains "This is recovery attempt": call write_stage_artifact with path proof.md and a short nonempty body, then emit_stage_envelope with status: success, a one-sentence summary, artifacts listing that path, and payload: {}.
|
|
51
|
+
Do not call ask_operator. Do not "helpfully" write proof.md on attempt 1.
|
|
52
|
+
io:
|
|
53
|
+
input:
|
|
54
|
+
schema:
|
|
55
|
+
$ref: "#/schemas/empty"
|
|
56
|
+
output:
|
|
57
|
+
schema:
|
|
58
|
+
$ref: "#/schemas/empty"
|
|
59
|
+
verify:
|
|
60
|
+
- id: proof-on-disk
|
|
61
|
+
type: artifact
|
|
62
|
+
path: proof.md
|
|
63
|
+
nonempty: true
|
|
64
|
+
when: [after]
|
|
65
|
+
on_verify_fail:
|
|
66
|
+
mode: repair
|
|
67
|
+
max_attempts: 2
|
|
68
|
+
retry_safety: idempotent
|
|
69
|
+
include_failed_checks: true
|
|
70
|
+
|
|
71
|
+
- id: manual-recover
|
|
72
|
+
route:
|
|
73
|
+
- to: ordinary-retry
|
|
74
|
+
system_prompt: |
|
|
75
|
+
Cover on_verify_fail.mode: manual. Look at the artifacts path in this prompt (stages/manual-recover/attempts/N/artifacts/).
|
|
76
|
+
If N is 1: call emit_stage_envelope with status: success, a one-sentence summary, artifacts: [], and payload: {}. Do not write proof.md. After-phase verify will fail and this stage stays failed until the operator uses Retry with guidance.
|
|
77
|
+
If N is 2 or greater, or the user message contains "This is recovery attempt": call write_stage_artifact with path proof.md and a short nonempty body, then emit_stage_envelope with status: success, a one-sentence summary, artifacts listing that path, and payload: {}.
|
|
78
|
+
Do not call ask_operator. Do not "helpfully" write proof.md on attempt 1.
|
|
79
|
+
io:
|
|
80
|
+
input:
|
|
81
|
+
schema:
|
|
82
|
+
$ref: "#/schemas/empty"
|
|
83
|
+
output:
|
|
84
|
+
schema:
|
|
85
|
+
$ref: "#/schemas/empty"
|
|
86
|
+
verify:
|
|
87
|
+
- id: proof-on-disk
|
|
88
|
+
type: artifact
|
|
89
|
+
path: proof.md
|
|
90
|
+
nonempty: true
|
|
91
|
+
when: [after]
|
|
92
|
+
on_verify_fail:
|
|
93
|
+
mode: manual
|
|
94
|
+
retry_safety: side_effecting
|
|
95
|
+
include_failed_checks: true
|
|
96
|
+
|
|
97
|
+
- id: ordinary-retry
|
|
98
|
+
route:
|
|
99
|
+
- to: done
|
|
100
|
+
system_prompt: |
|
|
101
|
+
Cover ordinary Retry (no on_verify_fail). Look at the artifacts path in this prompt (stages/ordinary-retry/attempts/N/artifacts/).
|
|
102
|
+
If N is 1: call emit_stage_envelope with status: failure, a one-sentence summary that you failed on purpose, artifacts: [], and payload: {}. Do not emit success.
|
|
103
|
+
If N is 2 or greater: call emit_stage_envelope with status: success, a one-sentence summary, artifacts: [], and payload: {}.
|
|
104
|
+
Do not call ask_operator.
|
|
105
|
+
io:
|
|
106
|
+
input:
|
|
107
|
+
schema:
|
|
108
|
+
$ref: "#/schemas/empty"
|
|
109
|
+
output:
|
|
110
|
+
schema:
|
|
111
|
+
$ref: "#/schemas/empty"
|
|
112
|
+
|
|
113
|
+
- id: done
|
|
114
|
+
system_prompt: |
|
|
115
|
+
The retry tour finished. Emit a success envelope via emit_stage_envelope with status: success, a short summary, artifacts: [], and payload: {}.
|
|
116
|
+
io:
|
|
117
|
+
input:
|
|
118
|
+
schema:
|
|
119
|
+
$ref: "#/schemas/empty"
|
|
120
|
+
output:
|
|
121
|
+
schema:
|
|
122
|
+
$ref: "#/schemas/empty"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
id: retry-tour
|
|
2
|
+
goal: Walk emit soft-reject, automatic repair, manual recover, and ordinary Retry.
|
|
3
|
+
context: |
|
|
4
|
+
Retry tour — each stage covers one retry surface. First attempts are
|
|
5
|
+
supposed to fail the check or the stage; later attempts pass. Follow each
|
|
6
|
+
stage prompt, including intentional failing emits.
|
|
7
|
+
constraints: |
|
|
8
|
+
Docs only; no checkout edits. One-sentence summaries.
|
|
9
|
+
Never emit fork_choice. Do not skip the failing first pass on a stage.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Route `if` tour
|
|
2
|
+
|
|
3
|
+
One pipeline that walks every **runtime** deterministic-`if` case that can succeed in a single run. Each stage does one job. Payloads are baked into prompts so the gates that we claim to cover actually fire.
|
|
4
|
+
|
|
5
|
+
This catalog is a **deep spine**. In the operator console you walk **top to bottom**: ungated `to:` continues the story. Gated `if`s are local side branches that mostly leaf. Fan-out exists only where the scenario needs it (several matching `if`s, a join with two parents, skip-cascade, or the two-way split that keeps `quiet` all-gated).
|
|
6
|
+
|
|
7
|
+
A condition that stays false does **not** count as covering that operator. Misses exist only where skip / quiet-end / join-skip **is** the scenario.
|
|
8
|
+
|
|
9
|
+
Illegal catalogs (`if` on a loop, optional field, empty `all`, …) cannot live in this file — validate would reject the whole pipeline. Those stay under [`../route-wiring-smoke-test/rejected/`](../route-wiring-smoke-test/).
|
|
10
|
+
|
|
11
|
+
## Run
|
|
12
|
+
|
|
13
|
+
From the repo git root, after `sf ui` is up, pick pipeline `route-if-tour` and task `route-if-tour`.
|
|
14
|
+
|
|
15
|
+
Or:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx tsx src/cli.ts validate --pipeline examples/route-if-tour/route-if-tour.pipeline.yaml
|
|
19
|
+
npx tsx src/cli.ts run \
|
|
20
|
+
--pipeline examples/route-if-tour/route-if-tour.pipeline.yaml \
|
|
21
|
+
--task examples/route-if-tour/route-if-tour.task.yaml
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Validate should succeed (`ok: true`) with warning `pipeline.route_all_gated` on `gated-only`, `quiet`, and `loop-check` (every **forward** `to:` has `if`; the loop on `loop-check` does not count as an ungated sibling). `--strict` does not promote that warning. You may also see `pipeline.model_applies` because `model` is set on the pipeline, not on each stage.
|
|
25
|
+
|
|
26
|
+
The run should **succeed**. Skipped stages: `skipped-page`, `skipped-page-child`, `skipped-quiet`, `assemble-miss`, `assemble-mix-miss`, `skipped-coerced`. Every other stage should **succeed**. `loop-check` should `send_back` once (replay `loop-draft`) then `continue` so `loop-done` runs.
|
|
27
|
+
|
|
28
|
+
Joins still wait even though their parents sit on the spine in sequence: `assemble-ok` does not start until both `write` and `draw` are terminal.
|
|
29
|
+
|
|
30
|
+
## Walk (follow-along order)
|
|
31
|
+
|
|
32
|
+
Ungated `to:` is the next spine stage. Gated `if`s are local.
|
|
33
|
+
|
|
34
|
+
| Level | Spine stage | Always continues | Local branches |
|
|
35
|
+
|-------|-------------|------------------|----------------|
|
|
36
|
+
| 1 | `kickoff` | `classify` | — |
|
|
37
|
+
| 2 | `classify` | `score` | `ran-eq-string`, `ran-eq-int`, `ran-eq-num`, `ran-eq-bool`, `ran-ne`, `ran-in`, `ran-not-in`, `ran-gt-num` (`if`) |
|
|
38
|
+
| 3 | `score` | `account` | `ran-gt`, `ran-gte`, `ran-lt`, `ran-lte` (`if`) |
|
|
39
|
+
| 4 | `account` | `verdict` | `ran-nested` (`if`) |
|
|
40
|
+
| 5 | `verdict` | `compose` | `ran-ref` (`if`) |
|
|
41
|
+
| 6 | `compose` | `triage` | `ran-all`, `ran-any`, `ran-not`, `ran-nested-compose`, `ran-any-of-alls` (`if`) |
|
|
42
|
+
| 7 | `triage` | `ran-notify` | `skipped-page` (`if` miss: `severity eq high`, emit `low`) |
|
|
43
|
+
| 8 | `skipped-page` | — | `skipped-page-child` (skip-cascade) |
|
|
44
|
+
| 9 | `ran-notify` | `gated-only` | — |
|
|
45
|
+
| 10 | `gated-only` | — (all-gated fire) | `ran-all-gated` only (`if go eq true`; emit `go true`) |
|
|
46
|
+
| 11 | `ran-all-gated` | `quiet` **and** `write` (two ungated) | required 2-way fan-out so `quiet` can stay all-gated |
|
|
47
|
+
| 12 | `quiet` | — (dead-end all-gated miss) | `skipped-quiet` only (`if go eq true`; emit `go false`) |
|
|
48
|
+
| 13 | `write` | `draw` | `assemble-ok` (`if ready eq true`; emit `true`) |
|
|
49
|
+
| 14 | `draw` | `write-miss` | `assemble-ok` (`if complete eq true`; emit `true`) |
|
|
50
|
+
| 15 | `write-miss` | `draw-miss` | `assemble-miss` (`if ready eq true`; emit `true`) |
|
|
51
|
+
| 16 | `draw-miss` | `mix-open` | `assemble-miss` (`if complete eq true`; emit `false` so MISS) |
|
|
52
|
+
| 17 | `mix-open` | `mix-gated` | `assemble-mix-ok` (no `if`) |
|
|
53
|
+
| 18 | `mix-gated` | `mix-open-miss` | `assemble-mix-ok` (`if ready eq true`; emit `true`) |
|
|
54
|
+
| 19 | `mix-open-miss` | `mix-gated-miss` | `assemble-mix-miss` (no `if`) |
|
|
55
|
+
| 20 | `mix-gated-miss` | `strict-num` | `assemble-mix-miss` (`if ready eq true`; emit `false` so MISS) |
|
|
56
|
+
| 21 | `strict-num` | `loop-draft` | `ran-int-one` (`if n eq 1`); `skipped-coerced` (`if n eq "1"` string). Emit `{"n":1}` integer |
|
|
57
|
+
| 22 | `loop-draft` | `loop-check` | — |
|
|
58
|
+
| 23 | `loop-check` | — | `loop-done` (`if pass eq true`); `{ type: loop }` to `loop-draft` (`max_replays: 1`, `on_max_replays: require_continue`, `replay_session: resume`). First attempt `send_back`, second `continue`. Payload `{"pass":true}`. `loop-done` has `replay_safe: false` |
|
|
59
|
+
|
|
60
|
+
## Lanes
|
|
61
|
+
|
|
62
|
+
Each scenario is a stop on the spine (plus its local `if` leaves), not a parallel lane from `kickoff`.
|
|
63
|
+
|
|
64
|
+
| Stop | Source payload | What you should see |
|
|
65
|
+
|------|----------------|---------------------|
|
|
66
|
+
| Classify | `kind=ok`, `count=3`, `ratio=1.5`, `flag=true`, `tag=gold` | Eight gated handlers run; spine continues to `score` |
|
|
67
|
+
| Score | `score=10` | `gt` / `gte` / `lt` / `lte` all fire; spine continues to `account` |
|
|
68
|
+
| Account | `customer.tier=gold` | Nested path fires; sequential `io` on `ran-nested` |
|
|
69
|
+
| Verdict | `ok=true` via `$ref` `#/schemas/flag` | `$ref` path check fires |
|
|
70
|
+
| Compose | `severity=high`, `channel=web`, `customer.tier=gold` | `all`, `any`, `not`, nested `not(all)`, `any` of `all`s all fire |
|
|
71
|
+
| Triage | `severity=low` | `skipped-page` skips; skip-cascade skips `skipped-page-child`; `ran-notify` still runs |
|
|
72
|
+
| All-gated fire | `go=true` | Validate warns; `ran-all-gated` still runs |
|
|
73
|
+
| Quiet miss | `go=false` | `skipped-quiet` skips; the run still succeeds |
|
|
74
|
+
| Join fire | write `ready=true`, draw `complete=true` | `assemble-ok` runs with both envelopes after both parents are terminal |
|
|
75
|
+
| Join miss | write-miss `ready=true`, draw-miss `complete=false` | `assemble-miss` skips (not pending, not partial) |
|
|
76
|
+
| Mixed join fire | `mix-open` ungated, `mix-gated` `ready=true` | `assemble-mix-ok` runs |
|
|
77
|
+
| Mixed join miss | `mix-open-miss` ungated, `mix-gated-miss` `ready=false` | `assemble-mix-miss` skips |
|
|
78
|
+
| Type-strict | integer `n=1` | `ran-int-one` runs (`eq 1`); `skipped-coerced` skips (`eq "1"`) |
|
|
79
|
+
| Loop | `pass=true`; first attempt `send_back`, second `continue` | `loop-draft` replays once; `loop-done` runs after continue; `if` on the forward, not on the loop |
|
|
80
|
+
|
|
81
|
+
## Scenario table
|
|
82
|
+
|
|
83
|
+
| Scenario | How this pipeline covers it | Evidence |
|
|
84
|
+
|----------|------------------------------|----------|
|
|
85
|
+
| `if` on a forward Route Entry | Every gated `to:` below | Child runs or (for skip rows) is skipped |
|
|
86
|
+
| Evaluated only against the source payload | Prompts emit payload only; no status/timestamp fields in `if` | Gates match those JSON fields |
|
|
87
|
+
| No `if` → edge always fires | Spine `to:` with no `if` (`kickoff` → `classify`, `classify` → `score`, …, `ran-notify` → `gated-only`, `ran-all-gated` → `quiet` and `write`) | Those stages succeed |
|
|
88
|
+
| Mix always-run + gated siblings | `triage` → `skipped-page` (`if`) + `ran-notify` (no `if`) | `ran-notify` succeeds while `skipped-page` skips |
|
|
89
|
+
| Two (or more) matching `if`s both fire | `classify` and `score` each have several true `if`s | All `ran-eq-*` / `ran-gt` / `ran-gte` / `ran-lt` / `ran-lte` succeed |
|
|
90
|
+
| `eq` string | `kind eq ok` | `ran-eq-string` succeeded |
|
|
91
|
+
| `eq` integer | `count eq 3` | `ran-eq-int` succeeded |
|
|
92
|
+
| `eq` number | `ratio eq 1.5` | `ran-eq-num` succeeded |
|
|
93
|
+
| `eq` boolean | `flag eq true` | `ran-eq-bool` succeeded |
|
|
94
|
+
| `ne` | `kind ne fail` | `ran-ne` succeeded |
|
|
95
|
+
| `gt` integer | `score gt 5` (10 > 5) | `ran-gt` succeeded |
|
|
96
|
+
| `gt` number | `ratio gt 1.0` | `ran-gt-num` succeeded |
|
|
97
|
+
| `gte` (equal bound) | `score gte 10` | `ran-gte` succeeded |
|
|
98
|
+
| `lt` | `score lt 20` | `ran-lt` succeeded |
|
|
99
|
+
| `lte` (equal bound) | `score lte 10` | `ran-lte` succeeded |
|
|
100
|
+
| `in` | `tag in [gold, silver]` | `ran-in` succeeded |
|
|
101
|
+
| `not_in` | `tag not_in [bronze]` | `ran-not-in` succeeded |
|
|
102
|
+
| Nested object path | `customer.tier eq gold` | `ran-nested` succeeded |
|
|
103
|
+
| `$ref` / `schemas:` after expansion | `verdict` output `$ref: "#/schemas/flag"`, `ok eq true` | `ran-ref` succeeded |
|
|
104
|
+
| Sequential `io` still applies on a fired gated edge | `ran-nested` / `ran-ref` / `ran-all` require a subset of the parent output | Those stages start with that input |
|
|
105
|
+
| `all` (AND) true | both leaves true | `ran-all` succeeded |
|
|
106
|
+
| `any` (OR) true | `channel eq web` true; the `severity eq low` arm is **not** a covered `eq` | `ran-any` succeeded |
|
|
107
|
+
| `not` true | `not (severity eq low)` | `ran-not` succeeded |
|
|
108
|
+
| Nested `not` around `all` | `not (severity low AND channel phone)` | `ran-nested-compose` succeeded |
|
|
109
|
+
| Nested `any` of `all`s | first `all` true (high+web); second `all` is not a covered `all` | `ran-any-of-alls` succeeded |
|
|
110
|
+
| Independent evaluation (not first-match) | compose's five `if`s all true | five compose handlers succeed |
|
|
111
|
+
| Single-parent miss → skip, run still succeeds | `triage` `severity eq high` is **false** on purpose | `skipped-page` skipped; run succeeded |
|
|
112
|
+
| Skip-cascade | `skipped-page` routes to `skipped-page-child` with no `if` | `skipped-page-child` skipped too |
|
|
113
|
+
| Always-run sibling still runs after a miss | `ran-notify` | succeeded |
|
|
114
|
+
| Nothing matches and nothing else pending | `quiet` only forward `if` misses | `skipped-quiet` skipped; run succeeded |
|
|
115
|
+
| `pipeline.route_all_gated` warning | `gated-only`, `quiet`, and `loop-check` have only gated **forwards** | validate warning, `ok: true` |
|
|
116
|
+
| All-gated `if` that **does** match | `gated-only` `go eq true` | `ran-all-gated` succeeded |
|
|
117
|
+
| Loop does not count as an ungated sibling | `loop-check` has gated `to: loop-done` plus `{ type: loop }` | `pipeline.route_all_gated` on `loop-check` |
|
|
118
|
+
| Join waits for every parent | `write` and `draw` both route to `assemble-ok` (parents run in sequence on the spine) | `assemble-ok` does not start until both succeeded |
|
|
119
|
+
| Join runs only when every inbound `if` fired | both `ready` and `complete` true | `assemble-ok` succeeded |
|
|
120
|
+
| Each parent's `if` reads that parent only | `write.ready` vs `draw.complete` | `assemble-ok` sees both envelopes |
|
|
121
|
+
| Join skip when any inbound `if` missed | `draw-miss` emits `complete: false` | `assemble-miss` skipped |
|
|
122
|
+
| Missed join `if` does not skip while the other parent runs | `write-miss` fires; `draw-miss` misses | child waits, then skips |
|
|
123
|
+
| Mixed join (ungated + gated fire) | `mix-open` has no `if`; `mix-gated` `ready eq true` | `assemble-mix-ok` succeeded |
|
|
124
|
+
| Mixed join (ungated + gated miss) | `mix-open-miss` ungated; `mix-gated-miss` `ready eq true` misses | `assemble-mix-miss` skipped |
|
|
125
|
+
| DAG still lists skipped `to:` | skipped stages still appear on the map | visible as skipped, not missing |
|
|
126
|
+
| Type-strict comparison | `strict-num` emits integer `1` | `ran-int-one` succeeded; `skipped-coerced` skipped (`eq "1"` did not coerce) |
|
|
127
|
+
| Loop still works next to `if` | `loop-check` has `{ type: loop }` to `loop-draft` and a gated forward `to: loop-done` | DAG shows the loop; `loop-done` succeeded after continue |
|
|
128
|
+
| `send_back` then `continue` | first `loop-check` attempt sends back; second continues | `loop-draft` runs twice; then `loop-done` |
|
|
129
|
+
| `if` stays off the loop entry | `if` is only on the forward to `loop-done` | validate still `ok` |
|
|
130
|
+
|
|
131
|
+
## Expected stage status
|
|
132
|
+
|
|
133
|
+
| Stage | Status | Why |
|
|
134
|
+
|-------|--------|-----|
|
|
135
|
+
| `kickoff` | succeeded | entry |
|
|
136
|
+
| `classify` | succeeded | ungated from kickoff |
|
|
137
|
+
| `ran-eq-string` | succeeded | `if` met |
|
|
138
|
+
| `ran-eq-int` | succeeded | `if` met |
|
|
139
|
+
| `ran-eq-num` | succeeded | `if` met |
|
|
140
|
+
| `ran-eq-bool` | succeeded | `if` met |
|
|
141
|
+
| `ran-ne` | succeeded | `if` met |
|
|
142
|
+
| `ran-in` | succeeded | `if` met |
|
|
143
|
+
| `ran-not-in` | succeeded | `if` met |
|
|
144
|
+
| `ran-gt-num` | succeeded | `if` met |
|
|
145
|
+
| `score` | succeeded | ungated from classify |
|
|
146
|
+
| `ran-gt` | succeeded | `if` met |
|
|
147
|
+
| `ran-gte` | succeeded | `if` met |
|
|
148
|
+
| `ran-lt` | succeeded | `if` met |
|
|
149
|
+
| `ran-lte` | succeeded | `if` met |
|
|
150
|
+
| `account` | succeeded | ungated from score |
|
|
151
|
+
| `ran-nested` | succeeded | `if` met |
|
|
152
|
+
| `verdict` | succeeded | ungated from account |
|
|
153
|
+
| `ran-ref` | succeeded | `if` met |
|
|
154
|
+
| `compose` | succeeded | ungated from verdict |
|
|
155
|
+
| `ran-all` | succeeded | `if` met |
|
|
156
|
+
| `ran-any` | succeeded | `if` met |
|
|
157
|
+
| `ran-not` | succeeded | `if` met |
|
|
158
|
+
| `ran-nested-compose` | succeeded | `if` met |
|
|
159
|
+
| `ran-any-of-alls` | succeeded | `if` met |
|
|
160
|
+
| `triage` | succeeded | ungated from compose |
|
|
161
|
+
| `skipped-page` | **skipped** | `severity` is `low`, not `high` |
|
|
162
|
+
| `skipped-page-child` | **skipped** | skip-cascade from `skipped-page` |
|
|
163
|
+
| `ran-notify` | succeeded | ungated from triage |
|
|
164
|
+
| `gated-only` | succeeded | ungated from ran-notify |
|
|
165
|
+
| `ran-all-gated` | succeeded | `if` met |
|
|
166
|
+
| `quiet` | succeeded | ungated from ran-all-gated |
|
|
167
|
+
| `skipped-quiet` | **skipped** | `go` is `false` |
|
|
168
|
+
| `write` | succeeded | ungated from ran-all-gated |
|
|
169
|
+
| `draw` | succeeded | ungated from write |
|
|
170
|
+
| `assemble-ok` | succeeded | both inbound `if`s met (write then draw, then join) |
|
|
171
|
+
| `write-miss` | succeeded | ungated from draw |
|
|
172
|
+
| `draw-miss` | succeeded | ungated from write-miss |
|
|
173
|
+
| `assemble-miss` | **skipped** | `draw-miss` inbound `if` missed |
|
|
174
|
+
| `mix-open` | succeeded | ungated from draw-miss |
|
|
175
|
+
| `mix-gated` | succeeded | ungated from mix-open |
|
|
176
|
+
| `assemble-mix-ok` | succeeded | ungated inbound fired and gated inbound matched |
|
|
177
|
+
| `mix-open-miss` | succeeded | ungated from mix-gated |
|
|
178
|
+
| `mix-gated-miss` | succeeded | ungated from mix-open-miss |
|
|
179
|
+
| `assemble-mix-miss` | **skipped** | gated inbound missed |
|
|
180
|
+
| `strict-num` | succeeded | ungated from mix-gated-miss |
|
|
181
|
+
| `ran-int-one` | succeeded | integer `1 eq 1` |
|
|
182
|
+
| `skipped-coerced` | **skipped** | integer `1` is not string `"1"` |
|
|
183
|
+
| `loop-draft` | succeeded | ungated from strict-num; replayed once after `send_back` |
|
|
184
|
+
| `loop-check` | succeeded | `send_back` then `continue`; forward `if` met on continue |
|
|
185
|
+
| `loop-done` | succeeded | gated forward from `loop-check` after continue |
|
|
186
|
+
|
|
187
|
+
## Not in this pipeline
|
|
188
|
+
|
|
189
|
+
These are real cases, but putting them here would either fail validate or fail the run, so they are **not** claimed as covered by this example.
|
|
190
|
+
|
|
191
|
+
| Scenario | Why it is absent | Where to see it |
|
|
192
|
+
|---------|------------------|-----------------|
|
|
193
|
+
| `if` field not in schema | `pipeline.route_if_invalid` | `examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml` |
|
|
194
|
+
| `if` field optional / not `required` | same | `rejected/23-reject-if-optional-field.pipeline.yaml` |
|
|
195
|
+
| Empty `all` / `any` / `in` | same | `rejected/24-reject-if-empty-all.pipeline.yaml` |
|
|
196
|
+
| `gt` on a string | same | `rejected/25-reject-if-gt-on-string.pipeline.yaml` |
|
|
197
|
+
| Nested optional path | same | `rejected/26-reject-if-optional-nested.pipeline.yaml` |
|
|
198
|
+
| `if` on `{ type: loop }` | same | `rejected/27-reject-if-on-loop.pipeline.yaml` |
|
|
199
|
+
| `if` + `on: [failed]` | same | `rejected/29-reject-if-on-failed.pipeline.yaml` |
|
|
200
|
+
| Failed parent blocks a Join | a failed parent fails/blocks the run | runtime tests / yaml-catalog Generic fan-in |
|
|
201
|
+
| Payload-gated loops (`if` on `{ type: loop }`) | out of scope; would fail validate | `rejected/27-reject-if-on-loop.pipeline.yaml` |
|
|
202
|
+
| `exists` / array paths / fallback / first-match-wins | out of scope | spec |
|