From 8a41477ae0d83e9e379610dc67557a1bb76d1d5b Mon Sep 17 00:00:00 2001 From: Caleb <46907094+rotationalphysics495@users.noreply.github.com> Date: Wed, 3 Jun 2026 05:57:58 -0500 Subject: [PATCH] feat(epic-execute): bound design-phase context and persist plans Design phase improvements #1 and #2: #1 Bounded context: - Pass architecture.md by path instead of embedding full contents (the main unbounded size risk in this prompt) - Cap decision-log context at last 20KB (matches dev phase) - Add log_prompt_size guard, consistent with other phases - Replace hardcoded JS/TS exploration hints with language-agnostic guidance #2 File persistence: - Add DESIGN_DIR config and persist each plan to /-design.md - build_design_context_for_dev falls back to the persisted file when the in-memory plan is empty, so resumed runs keep their design context Story file remains inlined (small, bounded, needed in full by the planner). Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/epic-execute-lib/design-phase.sh | 76 ++++++++++++++++++------ scripts/epic-execute.sh | 2 + 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/scripts/epic-execute-lib/design-phase.sh b/scripts/epic-execute-lib/design-phase.sh index b66717afe..b0de9bdff 100644 --- a/scripts/epic-execute-lib/design-phase.sh +++ b/scripts/epic-execute-lib/design-phase.sh @@ -32,21 +32,30 @@ execute_design_phase() { log ">>> DESIGN PHASE: $story_id" + # Story is inlined (small, bounded, and the planner needs it in full) local story_contents=$(cat "$story_file") - # Load architecture file if available - local arch_contents="" + # Locate the architecture file but pass it by PATH, not embedded contents. + # architecture.md is the main unbounded size risk in this prompt. + local arch_file="" for search_path in "$PROJECT_ROOT/docs/architecture.md" "$PROJECT_ROOT/docs/architecture/architecture.md" "$PROJECT_ROOT/architecture.md"; do if [ -f "$search_path" ]; then - arch_contents=$(cat "$search_path") + arch_file="$search_path" break fi done - # Load previous decisions for context + # Load previous decisions for context, bounded to the last 20KB + # (matches the dev phase; the decision log grows across the epic). local decision_context="" if type get_decision_log_context >/dev/null 2>&1; then decision_context=$(get_decision_log_context) + local dec_size + dec_size=$(get_byte_size "$decision_context") + if [ "$dec_size" -gt 20000 ]; then + decision_context=$(printf '%s' "$decision_context" | tail -c 20000) + [ "$VERBOSE" = true ] && log_warn "Design: decision log truncated to last 20KB" + fi fi local design_prompt="You are a senior developer planning the implementation of a story. @@ -74,9 +83,7 @@ $story_contents ## Architecture Reference - -$arch_contents - +**Read the architecture document at:** ${arch_file:-"(none found)"} ## Previous Decisions in This Epic @@ -84,15 +91,12 @@ $arch_contents $decision_context -## Exploration Commands +## Exploration -First, explore the codebase to understand existing patterns: -\`\`\`bash -# Find similar implementations -find . -type f -name \"*.ts\" -o -name \"*.js\" | head -20 -# Check project structure -ls -la src/ 2>/dev/null || ls -la -\`\`\` +First, explore the codebase to understand existing patterns and conventions +before planning. Use the repository's own structure and language to guide you +(e.g. inspect the relevant source directories, find files similar to what this +story touches, and follow existing patterns rather than introducing new ones). ## Required Output @@ -137,6 +141,9 @@ Be specific and concrete. This plan will guide the implementation phase. After outputting the design block, output exactly: DESIGN COMPLETE: $story_id" + # Log prompt size in verbose mode (consistent with other phases) + log_prompt_size "$design_prompt" "design-phase" + if [ "$DRY_RUN" = true ]; then echo "[DRY RUN] Would execute design phase for $story_id" return 0 @@ -151,6 +158,10 @@ DESIGN COMPLETE: $story_id" LAST_DESIGN=$(echo "$result" | sed -n '/DESIGN START/,/DESIGN END/p') if [ -n "$LAST_DESIGN" ]; then + # Persist the plan to a per-story file so the dev phase can read it + # even after a resume (when the in-memory LAST_DESIGN is empty). + persist_design "$story_id" "$LAST_DESIGN" + # Save to decision log if type append_to_decision_log >/dev/null 2>&1; then append_to_decision_log "DESIGN" "$story_id" "$LAST_DESIGN" @@ -164,6 +175,27 @@ DESIGN COMPLETE: $story_id" fi } +# Persist a design plan to a per-story file under DESIGN_DIR. +# Arguments: +# $1 - story_id +# $2 - design content +persist_design() { + local story_id="$1" + local content="$2" + + if [ -z "${DESIGN_DIR:-}" ]; then + return 0 + fi + + mkdir -p "$DESIGN_DIR" 2>/dev/null || true + local design_file="$DESIGN_DIR/${story_id}-design.md" + if printf '%s\n' "$content" > "$design_file" 2>/dev/null; then + [ "$VERBOSE" = true ] && log "Design plan saved: $design_file" + else + log_warn "Failed to persist design plan: $design_file" + fi +} + # Get the last design for inclusion in dev phase prompt # Returns the design output or empty string if not available get_last_design() { @@ -175,7 +207,17 @@ get_last_design() { build_design_context_for_dev() { local story_id="$1" - if [ -z "$LAST_DESIGN" ]; then + # Prefer the in-memory plan; fall back to the persisted file so a resumed + # run (where LAST_DESIGN is empty) still gets the design context. + local design="$LAST_DESIGN" + if [ -z "$design" ] && [ -n "${DESIGN_DIR:-}" ]; then + local design_file="$DESIGN_DIR/${story_id}-design.md" + if [ -f "$design_file" ]; then + design=$(cat "$design_file") + fi + fi + + if [ -z "$design" ]; then echo "" return fi @@ -186,7 +228,7 @@ build_design_context_for_dev() { The following design was created in the planning phase. Follow this plan: -$LAST_DESIGN +$design ### Implementation Guidelines Based on Design diff --git a/scripts/epic-execute.sh b/scripts/epic-execute.sh index de799472f..a52a4f8f3 100755 --- a/scripts/epic-execute.sh +++ b/scripts/epic-execute.sh @@ -139,6 +139,8 @@ SPRINTS_DIR="$PROJECT_ROOT/docs/sprints" EPICS_DIR="$PROJECT_ROOT/docs/epics" UAT_DIR="$PROJECT_ROOT/docs/uat" LOGS_DIR="$SPRINT_ARTIFACTS_DIR/logs" +# Per-story design plans (persisted so dev phase can read them after resume) +DESIGN_DIR="$SPRINT_ARTIFACTS_DIR/design" # Temporary log file during execution - will be copied to LOGS_DIR on completion LOG_FILE="/tmp/bmad-epic-execute-$$.log"