chore(openspec): drop 9 superseded proposals + 11 stub archive files
Drop 9 batch proposals that are superseded by the boocode-lift-analysis (boocontext-audit, conductor upgrades, self-healing/verify-gate skills): add-3tier-memory, import-llm-evaluator, import-pregel-engine, plugin-platform, conductor-evolution, code-intelligence-upgrade, dev-workflow, ui-overhaul, agent-reliability. Delete 11 stub archive files (49-66B each, 'Status: Shipped. Archived.' only) that provide zero documentation value over the existing CHANGELOG.md + git tags.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Workflow listing
|
||||
The CLI SHALL provide a `list` command that displays all discovered workflows and their descriptions.
|
||||
|
||||
#### Scenario: List workflows
|
||||
- **WHEN** `ion list` is run
|
||||
- **THEN** all discovered workflows SHALL be listed with name, description, and source (bundled/project)
|
||||
|
||||
### Requirement: Workflow execution
|
||||
The CLI SHALL provide a `run` command that executes a workflow by name with optional arguments.
|
||||
|
||||
#### Scenario: Run workflow with message
|
||||
- **WHEN** `ion run analyze "analyze the codebase"` is run
|
||||
- **THEN** the `analyze` workflow SHALL execute with the provided user message
|
||||
|
||||
#### Scenario: Run in specific directory
|
||||
- **WHEN** `ion run build --cwd /path/to/project` is run
|
||||
- **THEN** the workflow SHALL use the specified working directory
|
||||
|
||||
#### Scenario: Run with specific store
|
||||
- **WHEN** `ion run deploy --store sqlite --db-path ./ion.db` is run
|
||||
- **THEN** the specified store backend SHALL be used
|
||||
|
||||
### Requirement: Workflow approval commands
|
||||
The CLI SHALL provide `approve` and `reject` commands for responding to approval gates.
|
||||
|
||||
#### Scenario: Approve a paused workflow
|
||||
- **WHEN** `ion approve <run-id>` is run
|
||||
- **THEN** the workflow SHALL resume from the paused approval node
|
||||
|
||||
#### Scenario: Approve with comment
|
||||
- **WHEN** `ion approve <run-id> "looks good"` is run
|
||||
- **THEN** the comment SHALL be recorded and available as `$nodeId.output`
|
||||
|
||||
#### Scenario: Reject with reason
|
||||
- **WHEN** `ion reject <run-id> "needs changes"` is run
|
||||
- **THEN** `$REJECTION_REASON` SHALL be set to "needs changes"
|
||||
- **THEN** if `on_reject` is configured, the handler SHALL execute
|
||||
|
||||
### Requirement: Workflow run management
|
||||
The CLI SHALL provide `status`, `runs`, `resume`, `abandon`, and `cleanup` commands.
|
||||
|
||||
#### Scenario: Show running workflows
|
||||
- **WHEN** `ion status` is run
|
||||
- **THEN** all active (running + paused) workflow runs SHALL be displayed
|
||||
|
||||
#### Scenario: List recent runs
|
||||
- **WHEN** `ion runs` is run
|
||||
- **THEN** recent workflow runs SHALL be listed with status and timestamps
|
||||
|
||||
#### Scenario: Resume failed run
|
||||
- **WHEN** `ion resume <run-id>` is run
|
||||
- **THEN** the failed run SHALL be resumed, skipping completed nodes
|
||||
|
||||
#### Scenario: Abandon run
|
||||
- **WHEN** `ion abandon <run-id>` is run
|
||||
- **THEN** the run SHALL be marked as cancelled
|
||||
|
||||
#### Scenario: Cleanup old runs
|
||||
- **WHEN** `ion cleanup` is run (default 7 days)
|
||||
- **THEN** runs older than the retention period SHALL have their artifacts removed
|
||||
|
||||
### Requirement: SOP-to-YAML conversion
|
||||
The CLI SHALL provide a `convert` command to transpile `.sop.md` files to `.yaml`.
|
||||
|
||||
#### Scenario: Convert SOP to YAML
|
||||
- **WHEN** `ion convert workflow.sop.md` is run
|
||||
- **THEN** a `workflow.yaml` SHALL be written with the equivalent DAG representation
|
||||
|
||||
### Requirement: Machine-readable output
|
||||
Workflow commands SHALL support `--json` flag for machine-readable output.
|
||||
|
||||
#### Scenario: JSON output for automation
|
||||
- **WHEN** `ion list --json` is run
|
||||
- **THEN** output SHALL be valid JSON array of workflow objects
|
||||
@@ -0,0 +1,54 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: DAG topological execution
|
||||
The engine SHALL execute workflow nodes in topological order determined by `depends_on` edges using Kahn's algorithm.
|
||||
|
||||
#### Scenario: Independent nodes run concurrently
|
||||
- **WHEN** a workflow has nodes A and B with no `depends_on`
|
||||
- **THEN** both A and B SHALL execute in the same topological layer, concurrently
|
||||
|
||||
#### Scenario: Dependent nodes run sequentially
|
||||
- **WHEN** node B lists `depends_on: [A]`
|
||||
- **THEN** A SHALL complete before B begins
|
||||
|
||||
#### Scenario: Cycle detection
|
||||
- **WHEN** nodes form a cycle (A → B → C → A)
|
||||
- **THEN** the loader SHALL reject the workflow with a cycle detection error
|
||||
|
||||
### Requirement: Trigger rules
|
||||
The engine SHALL support 4 trigger rules for join semantics.
|
||||
|
||||
#### Scenario: all_success (default)
|
||||
- **WHEN** a node has multiple upstream dependencies and no explicit `trigger_rule`
|
||||
- **THEN** it SHALL only run if ALL upstream nodes completed successfully
|
||||
- **THEN** it SHALL be skipped if any upstream node failed
|
||||
|
||||
#### Scenario: one_success
|
||||
- **WHEN** a node sets `trigger_rule: one_success`
|
||||
- **THEN** it SHALL run if at least one upstream node completed successfully
|
||||
|
||||
#### Scenario: all_done
|
||||
- **WHEN** a node sets `trigger_rule: all_done`
|
||||
- **THEN** it SHALL run when all upstream nodes have finished (any status), regardless of success/failure
|
||||
|
||||
#### Scenario: none_failed_min_one_success
|
||||
- **WHEN** a node sets `trigger_rule: none_failed_min_one_success`
|
||||
- **THEN** it SHALL run only if no upstream node failed AND at least one succeeded
|
||||
|
||||
### Requirement: when conditions
|
||||
Nodes SHALL support a `when:` string that evaluates to a boolean condition.
|
||||
|
||||
#### Scenario: when condition prevents execution
|
||||
- **WHEN** a node has `when: "false"` or any expression that evaluates falsy
|
||||
- **THEN** the node SHALL be skipped as if its trigger_rule prevented execution
|
||||
|
||||
### Requirement: Node retry with configurable policy
|
||||
Nodes SHALL support a `retry` config with `max_attempts`, `delay_ms`, and `on_error` (transient|all).
|
||||
|
||||
#### Scenario: retry on transient error
|
||||
- **WHEN** a node with `retry: { max_attempts: 3 }` fails with a transient error
|
||||
- **THEN** it SHALL retry up to 3 times with configured delay between attempts
|
||||
|
||||
#### Scenario: retry exhausted
|
||||
- **WHEN** all retry attempts fail
|
||||
- **THEN** the node SHALL be marked as failed and trigger_rule evaluation proceeds
|
||||
@@ -0,0 +1,59 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Append-only event log
|
||||
Workflow runs SHALL produce append-only event records. Events SHALL NOT be modified after creation.
|
||||
|
||||
#### Scenario: Events are chronological
|
||||
- **WHEN** a workflow executes
|
||||
- **THEN** events SHALL be stored with monotonically increasing timestamps or sequence numbers
|
||||
- **THEN** event order SHALL match execution order
|
||||
|
||||
#### Scenario: Events are immutable
|
||||
- **WHEN** an event has been persisted
|
||||
- **THEN** it SHALL NOT be updated or deleted
|
||||
|
||||
### Requirement: Event types
|
||||
The event log SHALL support exactly 8 event types: `workflow_started`, `workflow_completed`, `workflow_failed`, `workflow_cancelled`, `node_started`, `node_completed`, `node_failed`, `node_skipped`.
|
||||
|
||||
#### Scenario: Workflow lifecycle events
|
||||
- **WHEN** a workflow run begins
|
||||
- **THEN** a `workflow_started` event SHALL be recorded
|
||||
- **WHEN** a workflow run completes successfully
|
||||
- **THEN** a `workflow_completed` event SHALL be recorded
|
||||
- **WHEN** a workflow run fails
|
||||
- **THEN** a `workflow_failed` event SHALL be recorded
|
||||
|
||||
#### Scenario: Node lifecycle events
|
||||
- **WHEN** a node begins execution
|
||||
- **THEN** a `node_started` event SHALL be recorded
|
||||
- **WHEN** a node completes successfully
|
||||
- **THEN** a `node_completed` event SHALL record the node's output
|
||||
- **WHEN** a node fails
|
||||
- **THEN** a `node_failed` event SHALL record the error
|
||||
- **WHEN** a node is skipped (trigger_rule not met)
|
||||
- **THEN** a `node_skipped` event SHALL be recorded
|
||||
|
||||
### Requirement: Deterministic replay for crash recovery
|
||||
When a workflow run is resumed after an interruption, the engine SHALL load completed node outputs from the event log and skip re-execution of completed nodes.
|
||||
|
||||
#### Scenario: Resume skips completed nodes
|
||||
- **WHEN** a workflow run is resumed after a crash
|
||||
- **THEN** all nodes with a `node_completed` event SHALL be skipped
|
||||
- **THEN** execution SHALL begin from the first node without a completed event
|
||||
|
||||
#### Scenario: Resume after partial execution
|
||||
- **WHEN** a workflow had 5 nodes and the first 3 completed before the crash
|
||||
- **THEN** nodes 1-3 SHALL be skipped (outputs loaded from event log)
|
||||
- **THEN** node 4 SHALL be re-executed
|
||||
|
||||
### Requirement: Event storage via plugable backend
|
||||
Events SHALL be persisted through the `IWorkflowStore` interface, with at least a filesystem backend.
|
||||
|
||||
#### Scenario: Filesystem event store
|
||||
- **WHEN** using the filesystem backend
|
||||
- **THEN** each run SHALL have a JSON file at `{runId}/events.jsonl`
|
||||
- **THEN** events SHALL be appended as newline-delimited JSON
|
||||
|
||||
#### Scenario: SQLite event store
|
||||
- **WHEN** using the SQLite backend
|
||||
- **THEN** events SHALL be stored in a `workflow_events` table with columns for run_id, sequence, event_type, timestamp, and payload
|
||||
@@ -0,0 +1,37 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Approval gate pauses execution
|
||||
An ApprovalNode SHALL pause workflow execution and send a message for human review. Execution SHALL only continue when the user approves or rejects.
|
||||
|
||||
#### Scenario: Approval pauses workflow
|
||||
- **WHEN** an approval node executes
|
||||
- **THEN** the workflow status SHALL transition to `paused`
|
||||
- **THEN** a message SHALL be sent with the approval message text
|
||||
|
||||
#### Scenario: Approve resumes execution
|
||||
- **WHEN** the user approves a paused workflow
|
||||
- **THEN** the workflow SHALL resume with the next node in the DAG
|
||||
|
||||
#### Scenario: Reject fails the node
|
||||
- **WHEN** the user rejects a paused workflow
|
||||
- **THEN** the node SHALL be marked as failed
|
||||
- **THEN** downstream nodes SHALL evaluate their trigger rules
|
||||
|
||||
### Requirement: Capture response from approval
|
||||
An approval node MAY support `capture_response: true` to store the user's comment as `$nodeId.output`.
|
||||
|
||||
#### Scenario: Approval with captured response
|
||||
- **WHEN** an approval node has `capture_response: true` and the user provides a comment during approval
|
||||
- **THEN** the comment SHALL be stored as the node's output, available via `$nodeId.output`
|
||||
|
||||
### Requirement: On-reject retry
|
||||
An approval node MAY specify `on_reject` with a `prompt` and optional `max_attempts` for re-presenting after rejection.
|
||||
|
||||
#### Scenario: Reject with retry prompt
|
||||
- **WHEN** an approval node has `on_reject: { prompt: "..." }` and the user rejects
|
||||
- **THEN** the on_reject prompt SHALL be executed (typically the AI revises based on feedback)
|
||||
- **THEN** the approval gate SHALL be re-presented to the user
|
||||
|
||||
#### Scenario: Max attempts exceeded
|
||||
- **WHEN** the number of rejections exceeds `on_reject.max_attempts`
|
||||
- **THEN** the node SHALL fail permanently
|
||||
@@ -0,0 +1,44 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Programmatic execution
|
||||
The engine SHALL export an `executeWorkflow()` function that accepts a workflow definition, store, and options.
|
||||
|
||||
#### Scenario: Execute workflow from code
|
||||
- **WHEN** a host application calls `executeWorkflow(workflowDef, store, { userMessage: "..." })`
|
||||
- **THEN** the workflow SHALL execute and return a `WorkflowExecutionResult`
|
||||
|
||||
### Requirement: Workflow parsing
|
||||
The engine SHALL export `parseWorkflow(yaml: string): WorkflowDefinition` and `parseWorkflowFile(path: string): WorkflowDefinition` functions.
|
||||
|
||||
#### Scenario: Parse YAML string
|
||||
- **WHEN** a host application calls `parseWorkflow(yamlString)`
|
||||
- **THEN** it SHALL return a validated `WorkflowDefinition`
|
||||
|
||||
#### Scenario: Parse YAML file
|
||||
- **WHEN** a host application calls `parseWorkflowFile("./workflows/my-workflow.yaml")`
|
||||
- **THEN** it SHALL read and parse the file, returning a validated `WorkflowDefinition`
|
||||
|
||||
### Requirement: Workflow discovery
|
||||
The engine SHALL export `discoverWorkflows(cwd: string): WorkflowLoadResult` for finding workflows in the filesystem.
|
||||
|
||||
#### Scenario: Discover workflows
|
||||
- **WHEN** a host application calls `discoverWorkflows(cwd)`
|
||||
- **THEN** it SHALL return all discovered workflows from the project's `.archon/workflows/` directory
|
||||
|
||||
### Requirement: Store constructors
|
||||
The engine SHALL export store constructors for each backend: `createFsStore(path)`, `createSqliteStore(path)`, `createPostgresStore(connectionString)`.
|
||||
|
||||
#### Scenario: Create filesystem store
|
||||
- **WHEN** a host application calls `createFsStore("./data")`
|
||||
- **THEN** it SHALL return an initialized `IWorkflowStore` using the filesystem backend
|
||||
|
||||
#### Scenario: Create SQLite store
|
||||
- **WHEN** a host application calls `createSqliteStore("./ion.db")`
|
||||
- **THEN** it SHALL return an initialized `IWorkflowStore` using SQLite
|
||||
|
||||
### Requirement: TypeScript types
|
||||
All public APIs SHALL export full TypeScript type definitions.
|
||||
|
||||
#### Scenario: Types available
|
||||
- **WHEN** a host application imports from the package
|
||||
- **THEN** `WorkflowDefinition`, `DagNode`, `NodeOutput`, `WorkflowRun`, `WorkflowExecutionResult`, `IWorkflowStore` types SHALL all be exported
|
||||
@@ -0,0 +1,34 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: SOP markdown as secondary format
|
||||
Workflows MAY be defined as `.sop.md` files in addition to YAML. The engine SHALL detect `.sop.md` files during discovery and transpile them to the DAG node representation.
|
||||
|
||||
#### Scenario: SOP file discovered alongside YAML
|
||||
- **WHEN** a `.sop.md` file exists in the workflows directory alongside `.yaml` workflow files
|
||||
- **THEN** both SHALL be discovered and listed as available workflows
|
||||
|
||||
#### Scenario: SOP transpiled to prompt nodes
|
||||
- **WHEN** a `.sop.md` file is loaded
|
||||
- **THEN** each `## Steps` section item SHALL become a `prompt:` node
|
||||
- **THEN** `## Parameters` SHALL be extracted as node metadata
|
||||
|
||||
### Requirement: RFC 2119 constraint extraction
|
||||
The transpiler SHALL extract RFC 2119 constraints from `**Constraints:**` blocks and embed them in the prompt text of the corresponding node.
|
||||
|
||||
#### Scenario: Constraints included in prompt
|
||||
- **WHEN** a step has `**Constraints:** - You MUST do X`
|
||||
- **THEN** the constraint text SHALL be appended to the node's prompt
|
||||
|
||||
### Requirement: Overview as workflow description
|
||||
The `## Overview` section of a `.sop.md` file SHALL become the workflow's `description` field.
|
||||
|
||||
#### Scenario: Overview maps to description
|
||||
- **WHEN** a `.sop.md` has `## Overview\nThis SOP does X`
|
||||
- **THEN** the resulting workflow SHALL have `description: "This SOP does X"`
|
||||
|
||||
### Requirement: Parameter acquisition constraints
|
||||
The transpiler SHALL validate that all required parameters from `## Parameters` are present before execution, using the constraint pattern from the SOP.
|
||||
|
||||
#### Scenario: Missing required parameter
|
||||
- **WHEN** a required parameter has no value provided
|
||||
- **THEN** the workflow SHALL prompt the user for the missing parameter before executing
|
||||
@@ -0,0 +1,44 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Inline script execution
|
||||
Script nodes SHALL execute inline TypeScript (runtime: `bun`) or Python (runtime: `uv`) code and capture stdout as the node output.
|
||||
|
||||
#### Scenario: Bun inline execution
|
||||
- **WHEN** a script node has `runtime: bun` and `script: console.log("hello")`
|
||||
- **THEN** the executor SHALL run the script via `bun -e`
|
||||
- **THEN** stdout SHALL be captured as `$nodeId.output`
|
||||
|
||||
#### Scenario: Python inline execution
|
||||
- **WHEN** a script node has `runtime: uv` and `script: print("hello")`
|
||||
- **THEN** the executor SHALL run the script via `uv run python -c`
|
||||
- **THEN** stdout SHALL be captured as `$nodeId.output`
|
||||
|
||||
### Requirement: Dependency installation
|
||||
Script nodes SHALL support a `deps:` array that installs dependencies before execution.
|
||||
|
||||
#### Scenario: Bun with npm deps
|
||||
- **WHEN** a script node has `runtime: bun` and `deps: ["lodash", "zod"]`
|
||||
- **THEN** the executor SHALL run `bun install lodash zod` before executing
|
||||
|
||||
#### Scenario: Python with pip deps
|
||||
- **WHEN** a script node has `runtime: uv` and `deps: ["requests", "click"]`
|
||||
- **THEN** the executor SHALL run `uv pip install requests click` before executing
|
||||
|
||||
### Requirement: Named script files
|
||||
Script nodes MAY reference named scripts from a `.archon/scripts/` directory by name instead of inline code.
|
||||
|
||||
#### Scenario: Named script discovery
|
||||
- **WHEN** a script node has `script: analyze` and `scripts/analyze.ts` exists
|
||||
- **THEN** the executor SHALL load and execute the file
|
||||
|
||||
#### Scenario: Runtime inferred from extension
|
||||
- **WHEN** a script has `runtime: bun` and the named file has a `.ts` extension
|
||||
- **THEN** the executor SHALL run it via `bun run`
|
||||
|
||||
### Requirement: Script timeout
|
||||
Script nodes SHALL support a `timeout:` field in milliseconds. If execution exceeds the timeout, the process SHALL be killed and the node SHALL fail.
|
||||
|
||||
#### Scenario: Timeout exceeded
|
||||
- **WHEN** a script node sets `timeout: 5000` and the script runs for 10 seconds
|
||||
- **THEN** the process SHALL be killed after 5 seconds
|
||||
- **THEN** the node SHALL be marked as failed with a timeout error
|
||||
@@ -0,0 +1,48 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: IWorkflowStore interface
|
||||
All storage backends SHALL implement the `IWorkflowStore` interface providing run lifecycle, event persistence, and node output retrieval.
|
||||
|
||||
#### Scenario: Store provides run CRUD
|
||||
- **WHEN** a workflow run is created
|
||||
- **THEN** `createWorkflowRun()` SHALL persist the run and return it
|
||||
- **WHEN** a workflow run status is updated
|
||||
- **THEN** `updateWorkflowRun()` SHALL persist the status change
|
||||
|
||||
#### Scenario: Store provides event persistence
|
||||
- **WHEN** a workflow event is created
|
||||
- **THEN** `createWorkflowEvent()` SHALL append it to the event log
|
||||
|
||||
#### Scenario: Store provides completed node outputs
|
||||
- **WHEN** a workflow is resumed
|
||||
- **THEN** `getCompletedDagNodeOutputs()` SHALL return all completed node outputs keyed by node ID
|
||||
|
||||
### Requirement: Filesystem backend
|
||||
The filesystem backend SHALL store each workflow run as files in a directory: `{artifactsDir}/{runId}/`.
|
||||
|
||||
#### Scenario: Filesystem stores events as JSONL
|
||||
- **WHEN** events are created using the filesystem backend
|
||||
- **THEN** each run SHALL have `events.jsonl` with newline-delimited JSON
|
||||
- **THEN** node outputs SHALL be stored as individual JSON files
|
||||
|
||||
#### Scenario: Filesystem stores run metadata
|
||||
- **WHEN** a run is created using the filesystem backend
|
||||
- **THEN** `run.json` SHALL contain the run metadata
|
||||
|
||||
### Requirement: SQLite backend
|
||||
The SQLite backend SHALL store workflow data in a SQLite database with tables for runs, events, and node outputs.
|
||||
|
||||
#### Scenario: SQLite stores runs table
|
||||
- **WHEN** using the SQLite backend
|
||||
- **THEN** a `workflow_runs` table SHALL exist with columns for id, workflow_name, status, user_message, created_at, updated_at
|
||||
|
||||
#### Scenario: SQLite stores events table
|
||||
- **WHEN** using the SQLite backend
|
||||
- **THEN** a `workflow_events` table SHALL exist with columns for run_id, sequence, event_type, timestamp, payload
|
||||
|
||||
### Requirement: Postgres backend
|
||||
The Postgres backend SHALL use a PostgreSQL database with the same schema as SQLite, accessed via the `IWorkflowStore` interface.
|
||||
|
||||
#### Scenario: Postgres uses same interface
|
||||
- **WHEN** switching from SQLite to Postgres
|
||||
- **THEN** no workflow engine code SHALL change — only the store implementation
|
||||
@@ -0,0 +1,57 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Node output references
|
||||
Prompts and commands SHALL support `$nodeId.output` to reference the output text of an upstream node, and `$nodeId.output.field` to reference a specific field from a structured output.
|
||||
|
||||
#### Scenario: Output reference substitution
|
||||
- **WHEN** a prompt contains `$analysis.output`
|
||||
- **THEN** it SHALL be replaced with the full output text of the node with id `analysis`
|
||||
|
||||
#### Scenario: Field reference with structured output
|
||||
- **WHEN** a prompt contains `$analysis.output.summary` and the upstream node declared `output_format: { type: "object", properties: { summary: ... } }`
|
||||
- **THEN** it SHALL be replaced with the value of the `summary` field from the parsed JSON output
|
||||
|
||||
#### Scenario: Missing node reference
|
||||
- **WHEN** a prompt references `$nonexistent.output`
|
||||
- **THEN** the reference SHALL resolve to an empty string with a warning
|
||||
|
||||
#### Scenario: Missing field on schemaless node
|
||||
- **WHEN** a prompt references `$node.output.field` and the upstream node has no `output_format` and its output is not valid JSON
|
||||
- **THEN** the consuming node SHALL fail with an error
|
||||
|
||||
#### Scenario: Strict field access for declared schemas
|
||||
- **WHEN** a prompt references `$node.output.field` and the upstream node's `output_format` declares properties but `field` is not among them
|
||||
- **THEN** the consuming node SHALL fail with a field-not-found error
|
||||
|
||||
### Requirement: Built-in variables
|
||||
The engine SHALL support `$ARGUMENTS`, `$ARTIFACTS_DIR`, `$WORKFLOW_ID`, `$BASE_BRANCH`, `$DOCS_DIR`.
|
||||
|
||||
#### Scenario: $ARGUMENTS substitution
|
||||
- **WHEN** a prompt contains `$ARGUMENTS`
|
||||
- **THEN** it SHALL be replaced with the full user message/arguments string
|
||||
|
||||
#### Scenario: $ARTIFACTS_DIR substitution
|
||||
- **WHEN** a prompt contains `$ARTIFACTS_DIR`
|
||||
- **THEN** it SHALL be replaced with the path to the run's artifact directory
|
||||
|
||||
#### Scenario: $WORKFLOW_ID substitution
|
||||
- **WHEN** a prompt contains `$WORKFLOW_ID`
|
||||
- **THEN** it SHALL be replaced with the workflow run ID
|
||||
|
||||
### Requirement: Loop-specific variables
|
||||
Loop nodes SHALL support `$LOOP_USER_INPUT` (from approve at interactive gates) and `$LOOP_PREV_OUTPUT` (output of the previous iteration).
|
||||
|
||||
#### Scenario: $LOOP_PREV_OUTPUT on first iteration
|
||||
- **WHEN** a loop node is on its first iteration
|
||||
- **THEN** `$LOOP_PREV_OUTPUT` SHALL resolve to an empty string
|
||||
|
||||
#### Scenario: $LOOP_PREV_OUTPUT on subsequent iterations
|
||||
- **WHEN** a loop node is on iteration 2+
|
||||
- **THEN** `$LOOP_PREV_OUTPUT` SHALL contain the cleaned output of the previous iteration
|
||||
|
||||
### Requirement: Approval-specific variables
|
||||
Approval nodes SHALL support `$REJECTION_REASON`.
|
||||
|
||||
#### Scenario: $REJECTION_REASON in on_reject prompt
|
||||
- **WHEN** an approval node is rejected with a reason
|
||||
- **THEN** `$REJECTION_REASON` SHALL contain the reviewer's feedback text
|
||||
@@ -0,0 +1,51 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Run states
|
||||
A workflow run SHALL transition through states: `pending → running → completed | failed | cancelled`. It MAY transition to `paused` for approval gates.
|
||||
|
||||
#### Scenario: Normal completion
|
||||
- **WHEN** all DAG nodes complete successfully
|
||||
- **THEN** the run status SHALL be `completed`
|
||||
|
||||
#### Scenario: Node failure
|
||||
- **WHEN** a node fails and no retry succeeds
|
||||
- **THEN** the run status SHALL be `failed`
|
||||
|
||||
#### Scenario: User cancellation
|
||||
- **WHEN** a user cancels a running workflow
|
||||
- **THEN** the run status SHALL be `cancelled`
|
||||
|
||||
#### Scenario: Approval pause
|
||||
- **WHEN** an approval node is reached
|
||||
- **THEN** the run status SHALL transition to `paused`
|
||||
- **THEN** it SHALL transition back to `running` on approval
|
||||
|
||||
### Requirement: Resume from failure
|
||||
A failed workflow SHALL support resumption, skipping already-completed nodes using stored outputs from the event log.
|
||||
|
||||
#### Scenario: Resume skips completed nodes
|
||||
- **WHEN** a failed workflow has 2 completed nodes out of 5
|
||||
- **THEN** resuming SHALL skip nodes 1-2 and re-execute from node 3
|
||||
|
||||
#### Scenario: Resume with always_run
|
||||
- **WHEN** a node has `always_run: true` and the workflow is resumed
|
||||
- **THEN** the node SHALL re-execute even if it completed previously
|
||||
|
||||
### Requirement: Event-based observability
|
||||
All lifecycle transitions SHALL emit typed events through the event emitter for observability and external subscribers.
|
||||
|
||||
#### Scenario: Events for every state transition
|
||||
- **WHEN** a workflow starts
|
||||
- **THEN** a `workflow_started` event SHALL be emitted
|
||||
- **WHEN** a workflow completes
|
||||
- **THEN** a `workflow_completed` event SHALL be emitted
|
||||
- **WHEN** a node starts/completes/fails/skips
|
||||
- **THEN** corresponding node events SHALL be emitted
|
||||
|
||||
### Requirement: Cleanup
|
||||
The engine SHALL support cleaning up old workflow runs and their artifacts.
|
||||
|
||||
#### Scenario: Cleanup by age
|
||||
- **WHEN** cleanup is invoked with a retention period (default 7 days)
|
||||
- **THEN** runs older than the retention period SHALL have their artifacts removed
|
||||
- **THEN** run records MAY be pruned from the store
|
||||
@@ -0,0 +1,77 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Workflow definition structure
|
||||
A workflow YAML SHALL have a top-level `name`, `description`, and `nodes:` array. It MAY have `provider`, `model`, `interactive`, `mutates_checkout`, `tags`.
|
||||
|
||||
#### Scenario: Minimal valid workflow
|
||||
- **WHEN** a YAML file contains a `name`, `description`, and at least one node
|
||||
- **THEN** the loader SHALL parse it as a valid workflow definition
|
||||
|
||||
#### Scenario: Missing name
|
||||
- **WHEN** a YAML file lacks a `name` field
|
||||
- **THEN** the loader SHALL reject it with a validation error
|
||||
|
||||
### Requirement: Seven node types
|
||||
The engine SHALL support exactly 7 node types, mutually exclusive per node: `command`, `prompt`, `bash`, `script`, `loop`, `approval`, `cancel`.
|
||||
|
||||
#### Scenario: Node with exactly one mode field
|
||||
- **WHEN** a node has `prompt:` but no other mode field
|
||||
- **THEN** it SHALL be classified as a PromptNode
|
||||
|
||||
#### Scenario: Node with multiple mode fields
|
||||
- **WHEN** a node has both `prompt:` and `bash:`
|
||||
- **THEN** the loader SHALL reject it with a mutual-exclusivity error
|
||||
|
||||
#### Scenario: Node with no mode field
|
||||
- **WHEN** a node has none of the 7 mode fields
|
||||
- **THEN** the loader SHALL reject it
|
||||
|
||||
### Requirement: Common node fields
|
||||
All node types SHALL support `id`, `depends_on`, `when`, `trigger_rule`, `retry`, `timeout`, `output_type`, `always_run`.
|
||||
|
||||
#### Scenario: Node id must be unique
|
||||
- **WHEN** two nodes in the same workflow share the same `id`
|
||||
- **THEN** the loader SHALL reject the workflow
|
||||
|
||||
### Requirement: Prompt node
|
||||
A PromptNode SHALL have a `prompt:` string field containing the AI prompt text.
|
||||
|
||||
#### Scenario: Empty prompt rejected
|
||||
- **WHEN** a node has `prompt: ""`
|
||||
- **THEN** the loader SHALL reject it
|
||||
|
||||
### Requirement: Bash node
|
||||
A BashNode SHALL have a `bash:` string field and MAY have `timeout` (ms). AI-specific fields SHALL be ignored with a warning.
|
||||
|
||||
#### Scenario: Bash node with timeout
|
||||
- **WHEN** a bash node includes `timeout: 30000`
|
||||
- **THEN** the executor SHALL kill the subprocess after 30 seconds
|
||||
|
||||
### Requirement: Script node
|
||||
A ScriptNode SHALL have `script:` (inline or named), `runtime:` (`bun` or `uv`), MAY have `deps:` and `timeout:`.
|
||||
|
||||
#### Scenario: Script with deps
|
||||
- **WHEN** a script node has `runtime: bun` and `deps: ["lodash"]`
|
||||
- **THEN** the executor SHALL install dependencies before running the script
|
||||
|
||||
#### Scenario: Named script from disk
|
||||
- **WHEN** `script: analyze` and a file `scripts/analyze.ts` exists
|
||||
- **THEN** the executor SHALL load and run it
|
||||
|
||||
### Requirement: Loop node
|
||||
A LoopNode SHALL have `loop:` with `prompt`, `until`, `max_iterations`, and optional `fresh_context`, `interactive`, `gate_message`, `until_bash`.
|
||||
|
||||
#### Scenario: Loop with completion signal
|
||||
- **WHEN** the AI response contains the `until` string
|
||||
- **THEN** the loop SHALL stop and the node SHALL complete
|
||||
|
||||
#### Scenario: Loop exceeds max_iterations
|
||||
- **WHEN** the loop reaches `max_iterations` without the completion signal
|
||||
- **THEN** the node SHALL fail
|
||||
|
||||
### Requirement: Cancel node
|
||||
A CancelNode SHALL have a `cancel:` string containing a reason. It SHALL terminate the workflow run.
|
||||
|
||||
#### Scenario: Cancel terminates workflow
|
||||
- **WHEN** a cancel node executes
|
||||
- **THEN** the workflow SHALL be marked as cancelled with the cancel reason
|
||||
Reference in New Issue
Block a user