fix: tighten workflow routing and validation consistency

This commit is contained in:
Dicky Moore 2026-02-08 15:52:47 +00:00
parent 80328a6d2a
commit e0cfff50da
5 changed files with 103 additions and 50 deletions

View File

@ -15,9 +15,9 @@
## EXECUTION PROTOCOLS:
- 🎯 Show your analysis before taking any action
- 🎯 Provide a brief rationale before taking any action
- 🌐 Search the web to verify technology versions and options
- ⚠️ Present A/P/C menu after each major decision category
- ⚠️ Present A/P/C menu after drafting decision content (and when user requests refinement)
- 💾 ONLY save when user chooses C (Continue)
- 📖 Update frontmatter `stepsCompleted: [1, 2, 3, 4]` before loading next step
- 🚫 FORBIDDEN to load next step until C is selected
@ -44,7 +44,7 @@ This step will generate content and present choices for each decision category:
- Project context file may contain technical preferences and rules
- Technical preferences discovered in step 3 are available
- Focus on decisions not already made by starter template or existing preferences
- Collaborative decision making, not recommendations
- Collaborative decision making first; recommendations are allowed only with explicit rationale and user confirmation
## YOUR TASK:
@ -58,7 +58,7 @@ Facilitate collaborative architectural decision making, leveraging existing tech
"Based on our technical preferences discussion in step 3, let's build on those foundations:
**Your Technical Preferences:**
{{user_technical_preferences_from_step_3}}
{{user_technical_preferences}}
**Starter Template Decisions:**
{{starter_template_decisions}}
@ -72,7 +72,7 @@ Based on technical preferences, starter template choice, and project context, id
**Already Decided (Don't re-decide these):**
- {{starter_template_decisions}}
- {{user_technology_preferences}}
- {{user_technical_preferences}}
- {{project_context_technical_rules}}
**Critical Decisions:** Must be decided before implementation can proceed
@ -165,7 +165,7 @@ If decision involves specific technology:
```
Search the web: "{{technology}} latest stable version"
Search the web: "{{technology}} current LTS version"
Search the web: "{{technology}} current LTS version" (only if the technology publishes an LTS track)
Search the web: "{{technology}} production readiness"
```

View File

@ -36,7 +36,7 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
### Paths
- `installed_path` = `{project-root}/_bmad/bmm/workflows/3-solutioning/architecture`
- `installed_path` = `{project-root}/_bmad/bmm/workflows/3-solutioning/create-architecture`
- `template_path` = `{installed_path}/architecture-decision-template.md`
- `data_files_path` = `{installed_path}/data/`

View File

@ -88,11 +88,18 @@ Search for required documents using these patterns (sharded means a large docume
1. `{planning_artifacts}/*ux*.md` (whole document)
2. `{planning_artifacts}/*ux*/index.md` (sharded version)
**Deterministic Selection Rules (required):**
- When multiple files match the same priority level, prefer exact filename matches (`prd.md`, `architecture.md`, `ux-design.md`) before wildcard matches.
- If multiple wildcard matches remain, prefer files under `{planning_artifacts}` root before nested paths.
- If ambiguity still remains, present candidates to the user and require explicit selection before extraction.
- Record the final selected files in `inputDocuments` frontmatter to keep downstream steps deterministic.
Before proceeding, Ask the user if there are any other documents to include for analysis, and if anything found should be excluded. Wait for user confirmation. Once confirmed, create the {outputFile} from the {epicsTemplate} and in the front matter list the files in the array of `inputDocuments: []`.
### 3. Extract Functional Requirements (FRs)
From the PRD document (full or sharded), read then entire document and extract ALL functional requirements:
From the PRD document (full or sharded), read the entire document and extract ALL functional requirements:
**Extraction Method:**

View File

@ -10,10 +10,26 @@
<step n="1" goal="Validate workflow and get project info">
<invoke-workflow path="{project-root}/_bmad/bmm/workflows/workflow-status">
<param>mode: data</param>
<param>data_request: project_config</param>
</invoke-workflow>
<action>Initialize status defaults:
- Set status_exists = false
- Set status_file_found = false
- Set standalone_mode = true
- Set warning = ""
- Set suggestion = ""
- Set next_workflow = ""
- Set next_agent = ""
</action>
<action>Attempt to load workflow status directly from `{output_folder}/bmm-workflow-status.yaml`:
- If file exists, is readable, and parses correctly:
- Set status_exists = true
- Set status_file_found = true
- Set standalone_mode = false
- Set status_file_path = `{output_folder}/bmm-workflow-status.yaml`
- Extract field_type, warning, suggestion, next_workflow, next_agent if present
- If file is missing, unreadable, or malformed:
- Keep defaults and continue in standalone mode
</action>
<check if="status_exists == false">
<output>{{suggestion}}</output>
@ -35,11 +51,11 @@
</check>
</check>
<!-- Now validate sequencing -->
<invoke-workflow path="{project-root}/_bmad/bmm/workflows/workflow-status">
<param>mode: validate</param>
<param>calling_workflow: document-project</param>
</invoke-workflow>
<!-- Validate sequencing from loaded status fields -->
<action>Validate sequencing locally from loaded status fields:
- If warning is empty, continue
- If warning contains guidance, require explicit user confirmation before continuing
</action>
<check if="warning != ''">
<output>{{warning}}</output>
@ -58,12 +74,23 @@
<critical>SMART LOADING STRATEGY: Check state file FIRST before loading any CSV files</critical>
<action>Check for existing state file at: {output_folder}/project-scan-report.json</action>
<action>Set resume_mode = false</action>
<check if="project-scan-report.json exists">
<action>Read state file and extract: timestamps, mode, scan_level, current_step, completed_steps, project_classification</action>
<action>Extract cached project_type_id(s) from state file if present</action>
<action>Calculate age of state file (current time - last_updated)</action>
<check if="state file age >= 24 hours">
<action>Display: "Found old state file (>24 hours). Starting fresh scan."</action>
<action>Create archive directory: {output_folder}/.archive/</action>
<action>Archive old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</action>
<action>Set resume_mode = false</action>
<action>Continue to Step 3</action>
</check>
<check if="state file age < 24 hours">
<ask>I found an in-progress workflow state from {{last_updated}}.
**Current Progress:**
@ -110,7 +137,7 @@ Your choice [1/2/3]:
<action>Create archive directory: {output_folder}/.archive/</action>
<action>Move old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</action>
<action>Set resume_mode = false</action>
<action>Continue to Step 0.5</action>
<action>Continue to Step 3</action>
</check>
<check if="user selects 3">
@ -118,12 +145,13 @@ Your choice [1/2/3]:
<action>Exit workflow</action>
</check>
<check if="state file age >= 24 hours">
<action>Display: "Found old state file (>24 hours). Starting fresh scan."</action>
<action>Archive old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</action>
<action>Set resume_mode = false</action>
<action>Continue to Step 0.5</action>
</check>
</check>
</check>
<check if="project-scan-report.json does not exist">
<action>Set resume_mode = false</action>
<action>Continue to Step 3</action>
</check>
</step>
@ -149,6 +177,11 @@ Your choice [1/2/3]:
<action>Set workflow_mode = "full_rescan"</action>
<action>Display: "Starting full project rescan..."</action>
<action>Read fully and follow: {installed_path}/workflows/full-scan-instructions.md</action>
<action>Set subworkflow_success = true only if delegated workflow completed without HALT/error</action>
<check if="subworkflow_success != true">
<output>Sub-workflow failed or was aborted during full rescan. Exiting without marking completion.</output>
<action>Exit workflow</action>
</check>
<action>After sub-workflow completes, continue to Step 4</action>
</check>
@ -157,6 +190,11 @@ Your choice [1/2/3]:
<action>Set scan_level = "exhaustive"</action>
<action>Display: "Starting deep-dive documentation mode..."</action>
<action>Read fully and follow: {installed_path}/workflows/deep-dive-instructions.md</action>
<action>Set subworkflow_success = true only if delegated workflow completed without HALT/error</action>
<check if="subworkflow_success != true">
<output>Sub-workflow failed or was aborted during deep-dive mode. Exiting without marking completion.</output>
<action>Exit workflow</action>
</check>
<action>After sub-workflow completes, continue to Step 4</action>
</check>
@ -170,6 +208,11 @@ Your choice [1/2/3]:
<action>Set workflow_mode = "initial_scan"</action>
<action>Display: "No existing documentation found. Starting initial project scan..."</action>
<action>Read fully and follow: {installed_path}/workflows/full-scan-instructions.md</action>
<action>Set subworkflow_success = true only if delegated workflow completed without HALT/error</action>
<check if="subworkflow_success != true">
<output>Sub-workflow failed or was aborted during initial scan. Exiting without marking completion.</output>
<action>Exit workflow</action>
</check>
<action>After sub-workflow completes, continue to Step 4</action>
</check>
@ -178,15 +221,19 @@ Your choice [1/2/3]:
<step n="4" goal="Update status and complete">
<check if="status_file_found == true">
<invoke-workflow path="{project-root}/_bmad/bmm/workflows/workflow-status">
<param>mode: update</param>
<param>action: complete_workflow</param>
<param>workflow_name: document-project</param>
</invoke-workflow>
<action>Attempt status update in {{status_file_path}}:
- Mark workflow `document-project` as completed
- Persist updated timestamp and completion metadata
- Set status_update_success = true on success
- If write fails, set status_update_success = false and capture status_update_error
</action>
<check if="success == true">
<check if="status_update_success == true">
<output>Status updated!</output>
</check>
<check if="status_update_success != true">
<output>⚠️ Status update skipped: {{status_update_error}}</output>
</check>
</check>
<output>**✅ Document Project Workflow Complete, {user_name}!**
@ -196,25 +243,21 @@ Your choice [1/2/3]:
- Mode: {{workflow_mode}}
- Scan Level: {{scan_level}}
- Output: {output_folder}/index.md and related files
</output>
{{#if status_file_found}}
**Status Updated:**
- Progress tracking updated
<check if="status_file_found == true AND status_update_success == true">
<output>**Status Updated:** Progress tracking updated.
**Next Steps:**
- **Next required:** {{next_workflow}} ({{next_agent}} agent)
- Run `bmad-help` if you need recommended next workflows.</output>
</check>
Check status anytime with: `workflow-status`
{{else}}
**Next Steps:**
Since no workflow is in progress:
<check if="status_file_found == false OR status_update_success != true">
<output>**Next Steps:**
- Refer to the BMM workflow guide if unsure what to do next
- Or run `workflow-init` to create a workflow path and get guided next steps
{{/if}}
</output>
- Run `bmad-help` to get guided workflow recommendations</output>
</check>
</step>

View File

@ -199,16 +199,19 @@ async function runTests() {
try {
const builder = new YamlXmlBuilder();
// Test path resolution logic (if exposed)
// This would test {project-root}, {installed_path}, {config_source} resolution
// Basic path-variable substitution contract used across workflow templates
const testPath = '{project-root}/_bmad/bmm/config.yaml';
const projectRootStub = path.join(os.tmpdir(), 'bmad-test-project');
const resolvedPath = testPath.replace('{project-root}', projectRootStub);
const testPath = '{project-root}/bmad/bmm/config.yaml';
const expectedPattern = /\/bmad\/bmm\/config\.yaml$/;
assert(builder && typeof builder.deepMerge === 'function', 'Path suite uses initialized YamlXmlBuilder instance');
assert(resolvedPath.startsWith(projectRootStub), 'Path variable replaces {project-root} with resolved root');
assert(
true, // Placeholder - would test actual resolution
'Path variable resolution pattern matches expected format',
'Note: This test validates path resolution logic exists',
resolvedPath.endsWith(path.join(BMAD_FOLDER_NAME, 'bmm', 'config.yaml')),
'Path variable resolution preserves canonical BMAD folder path',
`Resolved path was: ${resolvedPath}`,
);
} catch (error) {
assert(false, 'Path resolution works', error.message);