Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Pipeline Plan 305

ezigus edited this page Apr 4, 2026 · 1 revision

Plan is written to .claude/pipeline-artifacts/plan.md.

Summary of the plan:

3 files touched — 1 new module, 1 new test file, 1 modified file:

  1. scripts/lib/ruflo-adapter.sh (new) — Module with guard pattern (_RUFLO_ADAPTER_LOADED), 7 functions: ruflo_detect, ruflo_init, ruflo_cleanup, ruflo_with_timeout, ruflo_available, plus 2 stubs (ruflo_import_memory, ruflo_export_memory) for Issue 2

  2. scripts/sw-ruflo-adapter-test.sh (new) — 11 mock-based unit tests covering detection, init, cleanup, circuit-breaker, export visibility, and pipefail safety

  3. scripts/sw-pipeline.sh (3 edits) — Source line after GitHub API modules (~line 135), ruflo_init in run_pipeline() (~line 1562), ruflo_cleanup in cleanup_on_exit() (~line 675)

Key design decisions:

  • Fast path detection (command -v ruflo) before slow npx fallback
  • Circuit-breaker pattern in ruflo_with_timeout disables ruflo for remainder of pipeline on timeout
  • All integration points use type ... >/dev/null 2>&1 guards + || true — zero breakage when ruflo is absent
  • RUFLO_AVAILABLE is exported for subshell visibility (needed by sw loop iterations) debase conventions

Alternative C: Node.js wrapper for ruflo integration

  • Pros: Better npm/npx integration
  • Cons: Breaks shell-first convention, adds runtime dependency, inconsistent with all other lib/ modules
  • Rejected: Wrong paradigm for this codebase

Component Diagram

┌─────────────────────────────────────────────────┐
│ sw-pipeline.sh │
│ (sources lib modules, runs pipeline stages) │
│ │
│ ┌─ source (optional) ──────────────────────┐ │
│ │ │ │
│ │ scripts/lib/ruflo-adapter.sh │ │
│ │ ┌────────────────────────────────────┐ │ │
│ │ │ ruflo_detect() → sets RUFLO_AVAILABLE│ │
│ │ │ ruflo_init() → detect + start MCP │ │
│ │ │ ruflo_cleanup() → export mem + stop │ │
│ │ │ ruflo_with_timeout() → circuit breaker │ │
│ │ │ ruflo_available() → boolean check │ │
│ │ └────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────┘ │
│ │
│ run_pipeline() ─── ruflo_init() at start │
│ cleanup_on_exit() ─── ruflo_cleanup() at end │
└─────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ scripts/sw-ruflo-adapter-test.sh │
│ (mock-based unit tests, no real ruflo needed) │
└─────────────────────────────────────────────────┘

Data Flow

Pipeline start
 → source ruflo-adapter.sh (sets RUFLO_AVAILABLE=false)
 → run_pipeline()
 → ruflo_init()
 → ruflo_detect()
 → command -v ruflo (fast path)
 → OR npx -y ruflo@latest mcp status (fallback)
 → sets RUFLO_AVAILABLE=true/false
 → if available: start MCP server (background)
 → ruflo_import_memory() [stub for Issue 2]
 → export RUFLO_AVAILABLE
 → [stages run, can check ruflo_available()]
 → cleanup_on_exit()
 → ruflo_cleanup()
 → ruflo_export_memory() [stub for Issue 2]
 → kill MCP server PID

Error Boundaries

Component Error Handling Propagation
ruflo_detect() All calls use &>/dev/null, returns 1 on failure Caller gets RUFLO_AVAILABLE=false, pipeline continues
ruflo_init() Calls `ruflo_detect
ruflo_cleanup() Early-exit guard if not available, `kill ...
ruflo_with_timeout() timeout wrapper, sets RUFLO_AVAILABLE=false on failure Circuit-breaks: disables ruflo for remainder
Source line in sw-pipeline.sh `-f ... && source ... 2>/dev/null

Interface Contracts

# Detection — returns 0 if ruflo available, 1 if not. Sets RUFLO_AVAILABLE.
ruflo_detect() -> exit_code: 0|1, side_effect: RUFLO_AVAILABLE=true|false
# Initialization — call once at pipeline start. No-op if ruflo unavailable.
ruflo_init() -> exit_code: always 0, side_effects: RUFLO_AVAILABLE exported, RUFLO_MCP_PID set
# Cleanup — call in exit trap. No-op if ruflo wasn't active.
ruflo_cleanup() -> exit_code: always 0, side_effects: MCP process killed
# Timeout wrapper — runs command with timeout, circuit-breaks on failure.
# 1ドル: timeout in seconds (default 30), $@: command to run
ruflo_with_timeout(timeout_s, ...cmd) -> exit_code: 0|1, side_effect: RUFLO_AVAILABLE=false on timeout
# Boolean check — use in conditionals
ruflo_available() -> exit_code: 0 (true) | 1 (false)
# Stubs for Issue 2 (memory bridge)
ruflo_import_memory() -> exit_code: always 0 (no-op stub)
ruflo_export_memory() -> exit_code: always 0 (no-op stub)

Risk Analysis

Risk Impact Mitigation
npx detection is slow (~5-10s) Slows pipeline startup Fast path: check command -v ruflo first; npx only as fallback
MCP server fails to start Could block pipeline Background start with &, sleep 2 for readiness, all subsequent calls use ruflo_available() guard
Stale MCP PID after crash Orphaned process PID-based cleanup in exit trap; `kill ... 2>/dev/null
timeout not available on macOS ruflo_with_timeout fails Use Shipwright's existing _timeout helper from helpers.sh if available, fall back to direct timeout command
set -euo pipefail incompatibility Module source could crash pipeline All functions use `
Breaking existing pipeline behavior Regression for all users Zero functional change when ruflo absent — adapter only sets variables and defines functions

Files to Create

1. scripts/lib/ruflo-adapter.sh (new)

Ruflo adapter module — detection, MCP lifecycle, circuit-breaker.

2. scripts/sw-ruflo-adapter-test.sh (new)

Unit tests using mock binaries — no real ruflo needed.

Files to Modify

3. scripts/sw-pipeline.sh

  • Add source line after existing lib modules (~line 135)
  • Add ruflo_init call inside run_pipeline() (~line 1562)
  • Add ruflo_cleanup call inside cleanup_on_exit() (~line 675)

Implementation Steps

Step 1: Create scripts/lib/ruflo-adapter.sh

The module follows Shipwright's standard lib pattern:

  • _RUFLO_ADAPTER_LOADED guard sentinel
  • Fallback helper definitions (warn, info, emit_event)
  • RUFLO_AVAILABLE=false default
  • Core functions: ruflo_detect, ruflo_init, ruflo_cleanup, ruflo_with_timeout, ruflo_available
  • Stub functions: ruflo_import_memory, ruflo_export_memory (for Issue 2)

Key implementation details:

  • ruflo_detect(): Fast path via command -v ruflo, fallback via npx -y ruflo@latest mcp status
  • ruflo_init(): Calls detect, starts MCP server in background, exports RUFLO_AVAILABLE
  • ruflo_cleanup(): Exports memory (stub), kills MCP PID, safe with || true guards
  • ruflo_with_timeout(): Uses _timeout if available (from helpers.sh), falls back to timeout command
  • All stderr suppressed with &>/dev/null or 2>/dev/null

Step 2: Source adapter in sw-pipeline.sh

Add after line 134 (after GitHub API modules section):

# --- Ruflo Adapter (optional) ---
# shellcheck source=lib/ruflo-adapter.sh
[[ -f "$SCRIPT_DIR/lib/ruflo-adapter.sh" ]] && source "$SCRIPT_DIR/lib/ruflo-adapter.sh" 2>/dev/null || true

Step 3: Add ruflo_init to run_pipeline()

Add after audit_init (~line 1562) using the existing type-check pattern:

 # Initialize ruflo adapter (no-op if unavailable)
 if type ruflo_init >/dev/null 2>&1; then
 ruflo_init || true
 fi

Step 4: Add ruflo_cleanup to cleanup_on_exit()

Add early in cleanup_on_exit() after the guard (~line 675), before heartbeat stop:

 # Cleanup ruflo MCP server
 if type ruflo_cleanup >/dev/null 2>&1; then
 ruflo_cleanup || true
 fi

Step 5: Create test file

Create scripts/sw-ruflo-adapter-test.sh with these test cases:

  1. Module guard prevents double-sourcing
  2. ruflo_detect with mock ruflo binary -> RUFLO_AVAILABLE=true
  3. ruflo_detect with no ruflo binary -> RUFLO_AVAILABLE=false
  4. ruflo_init with mock ruflo -> exports RUFLO_AVAILABLE
  5. ruflo_init without ruflo -> no-op
  6. ruflo_cleanup kills MCP PID
  7. ruflo_cleanup no-op when unavailable
  8. ruflo_with_timeout circuit-breaks
  9. ruflo_available exit codes
  10. RUFLO_AVAILABLE visible in subshell after export
  11. Safe under set -euo pipefail

Step 6: Verify and run tests

  • Make test executable
  • Run scripts/sw-ruflo-adapter-test.sh
  • Run npm test for regression check

Task Checklist

  • Task 1: Create scripts/lib/ruflo-adapter.sh with module guard, detection, init, cleanup, timeout, and available functions
  • Task 2: Add source line in sw-pipeline.sh after GitHub API modules section (~line 135)
  • Task 3: Add ruflo_init call in run_pipeline() function (~line 1562)
  • Task 4: Add ruflo_cleanup call in cleanup_on_exit() function (~line 675)
  • Task 5: Create scripts/sw-ruflo-adapter-test.sh with mock-based unit tests
  • Task 6: Make test file executable
  • Task 7: Verify test registration in npm test / vitest config
  • Task 8: Run sw-ruflo-adapter-test.sh -- all tests pass
  • Task 9: Run full npm test -- no regressions
  • Task 10: Verify pipeline runs identically without ruflo installed (RUFLO_AVAILABLE=false path)

Testing Approach

Test Pyramid Breakdown

  • Unit tests (11 tests): Mock-based tests in sw-ruflo-adapter-test.sh covering all exported functions, edge cases, and set -euo pipefail safety
  • Integration tests (1 test): Verify sw-pipeline.sh sources the adapter without error and pipeline runs cleanly with adapter present but ruflo absent
  • E2E (0): Not needed -- this is a no-op adapter when ruflo is absent, and ruflo won't be installed in CI

Coverage Targets

  • 100% of exported functions tested
  • Both available and unavailable code paths exercised
  • Circuit-breaker (timeout) path tested

Critical Paths to Test

  • Happy path: Mock ruflo binary present -> detect succeeds -> init starts MCP -> cleanup kills it
  • Error case 1: No ruflo binary -> detect fails -> init is no-op -> pipeline unaffected
  • Error case 2: ruflo_with_timeout exceeds limit -> RUFLO_AVAILABLE set to false -> circuit broken
  • Edge case 1: Double-source guard prevents re-initialization
  • Edge case 2: cleanup called when RUFLO_MCP_PID is empty -> no error
  • Edge case 3: RUFLO_AVAILABLE exported and visible in subshell

Definition of Done

  • source scripts/lib/ruflo-adapter.sh && ruflo_init && echo $RUFLO_AVAILABLE correctly detects installation
  • MCP server starts and stops cleanly with pipeline lifecycle
  • ruflo_with_timeout circuit breaker sets RUFLO_AVAILABLE=false on timeout
  • RUFLO_AVAILABLE is exported and visible in subshells
  • All new functions use || true guards -- compatible with set -euo pipefail
  • Full pipeline run is identical when ruflo is not installed
  • Follows Shipwright's module guard pattern (_RUFLO_ADAPTER_LOADED sentinel)
  • All unit tests pass
  • npm test passes with no regressions

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /