Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ For detailed task breakdowns, see the per-package ROADMAPs:

- [`packages/pipeline/ROADMAP.md`](packages/pipeline/ROADMAP.md) — Phases 0–3 complete, 4–12 remaining
- [`packages/mcp/ROADMAP.md`](packages/mcp/ROADMAP.md) — Phases 0–9 complete, Phase 10 optional
- [`packages/telemetry/ROADMAP.md`](packages/telemetry/ROADMAP.md) — Phase 0 complete, 1–5 remaining
- [`packages/telemetry/ROADMAP.md`](packages/telemetry/ROADMAP.md) — Phases 0–1 complete, 2–5 remaining
- [`packages/evaluations/ROADMAP.md`](packages/evaluations/ROADMAP.md) — Phase 0 complete, 1–7 remaining

---
Expand All @@ -27,7 +27,7 @@ Within each wave, the listed package phases reference the detailed tasks in the

| Package | Phase | Work | Status |
| ----------- | ------------------------ | ----------------------------------------------------------- | ----------- |
| `telemetry` | Phase 1: Storage | Pluggable storage backends (memory, file) | Not started |
| `telemetry` | Phase 1: Storage | Pluggable storage backends (memory, file) | Complete |
| `telemetry` | Phase 2: Telemetry Core | `emit()`, `query()`, `getPipelineSummary()` | Not started |
| `telemetry` | Phase 3: Constraints | Constraint evaluator, default constraints, builder utils | Not started |
| `telemetry` | Phase 4: Integration API | `createTelemetry()`, `onStageEvent()`, `serializeContext()` | Not started |
Expand Down Expand Up @@ -194,9 +194,9 @@ Wave 1: Telemetry Implementation
| ------------- | --------------------------------------------- | ------------------------------------------------------------------- |
| `mcp` | Phases 0–9 (functional) | Phase 10 extensions (optional, unblocked) |
| `pipeline` | Phases 0–3 (types, roadmap, handoff, helpers) | Phase 4 (orchestrator) — **blocked on Wave 1** for telemetry wiring |
| `telemetry` | Phase 0 (types only) | Phase 1 (storage) — **ready to start** |
| `telemetry` | Phase 0–1 (types, storage layer) | Phase 2 (telemetry core) — **ready to start** |
| `evaluations` | Phase 0 (types only) | Phase 1 (datasets) — **ready to start** |

**Immediate priority**: Telemetry Phases 1–4 (Wave 1). This is the critical path — everything else is blocked on or benefits from working telemetry.
**Immediate priority**: Telemetry Phases 2–4 (remainder of Wave 1). This is the critical path — everything else is blocked on or benefits from working telemetry.

**Maximum parallelism opportunity**: After Wave 1 completes, Wave 2 offers the most parallelism — pipeline Phase 4 and evaluations Phases 1–4 can all run simultaneously.
10 changes: 5 additions & 5 deletions packages/telemetry/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ This roadmap breaks down the [telemetry REQUIREMENTS](../../docs/open-forge-tele

---

## Phase 1: Storage Layer
## Phase 1: Storage Layer (COMPLETE)

**Goal**: Implement pluggable storage backends starting with the zero-config default.

### Tasks

- [ ] 1.1 Define storage interface [deps: 0.2] [deliverable: `src/storage/StorageBackend.ts` — StorageBackend with append(), query(), count()]
- [ ] 1.2 Implement in-memory storage [deps: 1.1] [deliverable: `src/storage/MemoryStorageBackend.ts` — for testing and lightweight use]
- [ ] 1.3 Implement file-based storage [deps: 1.1] [deliverable: `src/storage/FileStorageBackend.ts` — JSONL append-only file, default zero-config backend]
- [ ] 1.4 Write storage tests [deps: 1.2, 1.3] [deliverable: `tests/storage.test.ts`]
- [x] 1.1 Define storage interface [deps: 0.2] [deliverable: `src/storage/StorageBackend.ts` — StorageBackend with append(), query(), count()]
- [x] 1.2 Implement in-memory storage [deps: 1.1] [deliverable: `src/storage/MemoryStorageBackend.ts` — for testing and lightweight use]
- [x] 1.3 Implement file-based storage [deps: 1.1] [deliverable: `src/storage/FileStorageBackend.ts` — JSONL append-only file, default zero-config backend]
- [x] 1.4 Write storage tests [deps: 1.2, 1.3] [deliverable: `tests/storage.test.ts`]

**Parallel Groups**:

Expand Down
209 changes: 205 additions & 4 deletions scripts/forge-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ set -euo pipefail
# clear-drift-sentinel <phase> [--package <name>]
# check-drift-sentinel <phase> [--package <name>]
#
# Subcommands (validation):
# validate-roadmap [--package <name>]
#
# Subcommands (general):
# status [--phase N] [--package <name>]
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -627,6 +630,107 @@ cmd_phase_update_docs() {
# Session handoff
# ---------------------------------------------------------------------------

# Detect which wave a package+phase belongs to by scanning root ROADMAP.md
_detect_wave_for_package() {
local pkg="$1" phase="$2"
local root_roadmap="ROADMAP.md"
[[ -f "$root_roadmap" ]] || { echo "--"; return; }

local current_wave="" saw_wave=false
while IFS= read -r line; do
if echo "$line" | grep -qE '^## Wave [0-9]+:'; then
current_wave=$(echo "$line" | sed -E 's/^## (Wave [0-9]+):.*/\1/')
saw_wave=true
continue
fi
if [[ "$saw_wave" == true ]] && echo "$line" | grep -qE '^## ' && ! echo "$line" | grep -qE '^## Wave'; then
break
fi
[[ -n "$current_wave" ]] || continue
if echo "$line" | grep -qE "^\|.*\`${pkg}\`.*Phase ${phase}([^0-9]|$)"; then
echo "$current_wave"
return
fi
done < "$root_roadmap"
echo "--"
}

# Rewrite the "## Next Phase Context" section with the next incomplete phase
_advance_next_phase_context() {
local handoff_file="$1" pkg_label="$2"

local next_info
if [[ "$pkg_label" == "root" ]]; then
next_info=$(_next_phase_for "ROADMAP.md")
else
local pkg_roadmap="packages/${pkg_label}/ROADMAP.md"
[[ -f "$pkg_roadmap" ]] || return 0
next_info=$(_next_phase_for "$pkg_roadmap")
fi

[[ -n "$next_info" ]] || return 0

local npc_start npc_end
npc_start=$(grep -n '^## Next Phase Context' "$handoff_file" | head -1 | cut -d: -f1)
[[ -n "$npc_start" ]] || return 0
npc_end=$(tail -n +"$npc_start" "$handoff_file" | grep -n '^---$' | head -1 | cut -d: -f1)
[[ -n "$npc_end" ]] || return 0
npc_end=$(( npc_start + npc_end - 1 ))

if [[ "$next_info" == "ROADMAP_COMPLETE" ]]; then
local replacement
replacement="## Next Phase Context

### Target

All phases complete for @open-forge/${pkg_label}.

### Goal

Package roadmap is complete. Proceed to the next package via \`next-work\`.

### Critical Context

- Run \`bash scripts/forge-helper.sh next-work\` to find the next actionable item across all packages."
else
local next_phase next_title next_pending next_total
next_phase=$(echo "$next_info" | cut -d'|' -f1)
next_title=$(echo "$next_info" | cut -d'|' -f2)
next_pending=$(echo "$next_info" | cut -d'|' -f3)
next_total=$(echo "$next_info" | cut -d'|' -f4)

local replacement
replacement="## Next Phase Context

### Target

Wave: @open-forge/${pkg_label} ${next_title}

### Goal

${next_pending} of ${next_total} tasks remaining.

### Critical Context

- Run \`bash scripts/forge-helper.sh phase-tasks --phase ${next_phase} --package ${pkg_label}\` to see pending tasks
- Follow TDD: TYPES → RED → GREEN → REFACTOR → GATES → COMMIT"
fi

sed -i '' "${npc_start},${npc_end}d" "$handoff_file"
local insert_line=$(( npc_start - 1 ))

local tmpfile
tmpfile=$(mktemp)
{
head -n "$insert_line" "$handoff_file"
echo "$replacement"
echo ""
echo "---"
tail -n +"$(( insert_line + 1 ))" "$handoff_file"
} > "$tmpfile"
mv "$tmpfile" "$handoff_file"
}

cmd_init_handoff() {
assert_feature_branch
local handoff_file="HANDOFF.md"
Expand Down Expand Up @@ -672,20 +776,55 @@ cmd_update_handoff() {
date_stamp="$(date +%Y-%m-%d)"
local pkg_label="${PACKAGE:-root}"

# Update Current State table in-place (sed -i '' for macOS compat, # delimiter)
# -----------------------------------------------------------------------
# 1. Update Current State table
# -----------------------------------------------------------------------
sed -i '' "s#Last Completed Phase.*#Last Completed Phase** | ${pkg_label} phase ${phase} |#" "$handoff_file"
sed -i '' "s#Last Session.*#Last Session** | ${date_stamp} |#" "$handoff_file"
sed -i '' "s#Active Package.*#Active Package** | ${pkg_label} |#" "$handoff_file"

# Update ROADMAP Status based on whether there are remaining tasks
if [[ "$completed" == "$total" && "$total" -gt 0 ]]; then
sed -i '' "s#ROADMAP Status.*#ROADMAP Status** | Phase ${phase} complete |#" "$handoff_file"
else
sed -i '' "s#ROADMAP Status.*#ROADMAP Status** | In progress |#" "$handoff_file"
fi

# Append changelog entry
local entry="| ${date_stamp} | -- | ${pkg_label} | ${phase} | ${phase_title} -- ${completed}/${total} tasks |"
# -----------------------------------------------------------------------
# 2. Populate Completed Work table
# -----------------------------------------------------------------------
local wave_label
wave_label="$(_detect_wave_for_package "$pkg_label" "$phase")"

sed -i '' '/^| (none yet)/d' "$handoff_file"

local cw_row="| ${wave_label} | ${pkg_label} | Phase ${phase} | ${phase_title} |"

if grep -qF "| ${pkg_label} | Phase ${phase} |" "$handoff_file"; then
log "Completed Work already contains ${pkg_label} Phase ${phase}, skipping duplicate"
else
awk -v row="$cw_row" '
/^## Completed Work/ { in_cw=1 }
in_cw && /^\|/ { last_table_line=NR }
in_cw && /^---$/ { in_cw=0 }
{ lines[NR]=$0 }
END {
for (i=1; i<=NR; i++) {
print lines[i]
if (i == last_table_line) print row
}
}
' "$handoff_file" > "${handoff_file}.tmp" && mv "${handoff_file}.tmp" "$handoff_file"
fi

# -----------------------------------------------------------------------
# 3. Auto-advance Next Phase Context
# -----------------------------------------------------------------------
_advance_next_phase_context "$handoff_file" "$pkg_label"

# -----------------------------------------------------------------------
# 4. Append changelog entry
# -----------------------------------------------------------------------
local entry="| ${date_stamp} | ${wave_label} | ${pkg_label} | ${phase} | ${phase_title} -- ${completed}/${total} tasks |"
echo "$entry" >> "$handoff_file"

log "Updated HANDOFF.md with ${pkg_label} phase ${phase} completion"
Expand Down Expand Up @@ -802,6 +941,64 @@ cmd_check_drift_sentinel() {
fi
}

# ---------------------------------------------------------------------------
# Validation
# ---------------------------------------------------------------------------

cmd_validate_roadmap() {
parse_package_flag "$@"
set -- "${REMAINING_ARGS[@]+"${REMAINING_ARGS[@]}"}"

local roadmap pkg_dir
roadmap="$(resolve_roadmap "$PACKAGE")"
[[ -f "$roadmap" ]] || fail "Roadmap file not found: $roadmap"

if [[ -n "$PACKAGE" ]]; then
pkg_dir="packages/${PACKAGE}"
else
pkg_dir="."
fi

local errors=0 checked=0 skipped=0
while IFS= read -r line; do
if echo "$line" | grep -qE '^\s*-\s*\[x\]' && echo "$line" | grep -qE '\[deliverable:'; then
if ! echo "$line" | grep -qE '\[deliverable:[[:space:]]*`'; then
skipped=$((skipped + 1))
continue
fi

local task_id
task_id=$(echo "$line" | sed -E 's/^[[:space:]]*-[[:space:]]*\[x\][[:space:]]*([0-9]+\.[0-9]+).*/\1/')

local paths
paths=$(echo "$line" | grep -oE '\[deliverable:[^]]*\]' | grep -oE '`[^`]+`' | tr -d '`')
[[ -n "$paths" ]] || continue

while IFS= read -r path; do
[[ -n "$path" ]] || continue
checked=$((checked + 1))

local target="${pkg_dir}/${path}"
if [[ ! -f "$target" ]] && [[ ! -d "$target" ]]; then
warn "Missing deliverable: ${target} (task ${task_id})"
errors=$((errors + 1))
fi
done <<< "$paths"
fi
done < "$roadmap"

if [[ "$checked" -eq 0 ]]; then
log "No completed tasks with deliverables found in ${roadmap} (${skipped} skipped — non-path deliverables)"
return 0
fi

if [[ "$errors" -gt 0 ]]; then
fail "${errors} deliverable path(s) missing out of ${checked} checked (${skipped} skipped)"
fi

log "All ${checked} deliverable path(s) valid in ${roadmap} (${skipped} skipped)"
}

# ---------------------------------------------------------------------------
# Dispatch
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -836,6 +1033,9 @@ show_usage() {
echo " clear-drift-sentinel <phase> Clear sentinel when phase advances"
echo " check-drift-sentinel <phase> Check sentinel; exits 0=stuck, 1=clear"
echo ""
echo "Validation:"
echo " validate-roadmap Check deliverable paths exist on disk"
echo ""
echo "General:"
echo " status [--phase N] Show per-phase progress summary"
echo ""
Expand Down Expand Up @@ -870,6 +1070,7 @@ main() {
check-branch) cmd_check_branch "$@" ;;
ensure-branch) cmd_ensure_branch "$@" ;;
next-work) cmd_next_work "$@" ;;
validate-roadmap) cmd_validate_roadmap "$@" ;;
status) cmd_status "$@" ;;
--help|-h) show_usage ;;
*) fail "Unknown subcommand: $subcmd. Run with --help for usage." ;;
Expand Down
Loading