Skip to content

Commit caca763

Browse files
authored
Merge pull request #245 from run-vibes/coherence-verification
feat(board): add coherence verification system
2 parents 24168eb + ec77a96 commit caca763

File tree

14 files changed

+1310
-71
lines changed

14 files changed

+1310
-71
lines changed

.justfiles/board.just

Lines changed: 135 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ default:
2020
echo " just board start <id> Move story to in-progress"
2121
echo " just board done <id> [summary]"
2222
echo " Move story to done + changelog"
23+
echo " just board ice <id> Move story to icebox (blocked/deferred)"
24+
echo " just board thaw <id> Move story from icebox to backlog"
2325
echo ""
2426
echo "Epic/Milestone management:"
2527
echo " just board new epic \"name\" [description]"
@@ -184,6 +186,7 @@ status:
184186
cd "{{board_dir}}"
185187

186188
# Count stories in each stage
189+
icebox=$(find stages/icebox/stories -name "*.md" ! -name ".gitkeep" 2>/dev/null | wc -l | tr -d ' ')
187190
in_progress=$(find stages/in-progress/stories -name "*.md" ! -name ".gitkeep" 2>/dev/null | wc -l | tr -d ' ')
188191
backlog=$(find stages/backlog/stories -name "*.md" ! -name ".gitkeep" 2>/dev/null | wc -l | tr -d ' ')
189192
done_count=$(find stages/done/stories -name "*.md" ! -name ".gitkeep" 2>/dev/null | wc -l | tr -d ' ')
@@ -194,6 +197,7 @@ status:
194197
echo "Stories by Stage:"
195198
echo " In Progress: $in_progress"
196199
echo " Backlog: $backlog"
200+
echo " Icebox: $icebox"
197201
echo " Done: $done_count"
198202
echo ""
199203

@@ -225,21 +229,30 @@ _next-id TYPE:
225229
#!/usr/bin/env bash
226230
cd "{{board_dir}}"
227231
type="{{TYPE}}"
232+
type_upper="${type^^}"
228233
max=0
229234

230-
# Search in all stages for stories with this type prefix
235+
# Search for new format: [TYPE][NNNN]-*.md
236+
for f in $(find stages -name "\[${type_upper}\]\[*\]*.md" 2>/dev/null); do
237+
# Extract sequence number from [TYPE][NNNN] format
238+
num=$(basename "$f" .md | grep -oE "\[${type_upper}\]\[[0-9]+\]" | grep -oE "[0-9]+")
239+
[[ -z "$num" ]] && continue
240+
num=$((10#$num))
241+
if [[ "$num" -gt "$max" ]]; then
242+
max=$num
243+
fi
244+
done
245+
246+
# Also search old format for backwards compatibility: type-NNNN-*.md
231247
for f in $(find stages -name "${type}-*.md" -o -name "*-${type}-*.md" 2>/dev/null); do
232-
# Extract sequence number after type prefix (e.g., feat-01, m37-feat-01)
233-
# Pattern: TYPE-NN where NN is the sequence number we want
234248
num=$(basename "$f" .md | grep -oE "(feat|bug|chore|refactor|fix|docs)-[0-9]+" | grep -oE "[0-9]+$")
235-
# Skip if no match found
236249
[[ -z "$num" ]] && continue
237-
# Strip leading zeros to avoid octal interpretation (e.g., 08 -> 8)
238250
num=$((10#$num))
239251
if [[ "$num" -gt "$max" ]]; then
240252
max=$num
241253
fi
242254
done
255+
243256
printf "%04d" $((max + 1))
244257

245258
# Get next milestone number
@@ -333,24 +346,16 @@ _new-story TITLE TYPE="" EPICS="" MILESTONE="":
333346
# Create slug from title
334347
slug=$(echo "$title" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-')
335348

336-
# Build filename - include milestone prefix if provided
337-
if [[ -n "$milestone" ]]; then
338-
# Extract milestone number (e.g., "27" from "27-crt-design-system")
339-
ms_num=$(echo "$milestone" | grep -oE '^[0-9]+' || echo "")
340-
if [[ -n "$ms_num" ]]; then
341-
filename="stages/backlog/stories/m${ms_num}-${type}-${id}-${slug}.md"
342-
else
343-
filename="stages/backlog/stories/${type}-${id}-${slug}.md"
344-
fi
345-
else
346-
filename="stages/backlog/stories/${type}-${id}-${slug}.md"
347-
fi
349+
# Build filename with new [TYPE][NNNN] format
350+
# Format: [TYPE][NNNN]-verb-phrase.md
351+
type_upper="${type^^}"
352+
filename="stages/backlog/stories/[${type_upper}][${id}]-${slug}.md"
348353

349354
# Create the story file
350355
date=$(date +%Y-%m-%d)
351356
{
352357
echo '---'
353-
echo "id: ${type^^}${id}"
358+
echo "id: ${type_upper}${id}"
354359
echo "title: ${title}"
355360
echo "type: ${type}"
356361
echo "status: backlog"
@@ -558,8 +563,8 @@ _find-story PATTERN:
558563
cd "{{board_dir}}"
559564
pattern="{{PATTERN}}"
560565

561-
# Search in stages (backlog, in-progress, done)
562-
for stage in backlog in-progress done; do
566+
# Search in stages (icebox, backlog, in-progress, done)
567+
for stage in icebox backlog in-progress done; do
563568
dir="stages/$stage/stories"
564569
[[ -d "$dir" ]] || continue
565570

@@ -718,6 +723,116 @@ done ID SUMMARY="__PROMPT__":
718723
just board generate
719724
echo "Board updated"
720725

726+
# Move story to icebox (blocked or deferred)
727+
ice ID:
728+
#!/usr/bin/env bash
729+
set -euo pipefail
730+
cd "{{board_dir}}"
731+
732+
path=$(just board _find-story "{{ID}}")
733+
734+
if [[ -z "$path" ]]; then
735+
echo "Error: Story '{{ID}}' not found"
736+
exit 1
737+
fi
738+
739+
# Check if already in icebox
740+
if [[ "$path" == *"icebox"* ]]; then
741+
echo "Error: Story is already in icebox"
742+
exit 1
743+
fi
744+
745+
# Check if already done
746+
if [[ "$path" == *"done"* ]]; then
747+
echo "Error: Cannot ice a completed story"
748+
exit 1
749+
fi
750+
751+
name=$(basename "$path")
752+
dest="stages/icebox/stories/$name"
753+
754+
# Get epics from frontmatter before moving
755+
epics=$(grep -m1 "^epics:" "$path" 2>/dev/null | sed 's/^epics: *//' | tr -d '[]' || echo "")
756+
757+
# Move the file
758+
mv "$path" "$dest"
759+
760+
# Update status in frontmatter
761+
sed -i 's/^status: .*/status: icebox/' "$dest"
762+
sed -i "s/^updated: .*/updated: $(date +%Y-%m-%d)/" "$dest"
763+
764+
echo "Iced: $name"
765+
766+
# Update symlinks in epics
767+
if [[ -n "$epics" ]]; then
768+
IFS=', ' read -ra epic_list <<< "$epics"
769+
for epic in "${epic_list[@]}"; do
770+
epic=$(echo "$epic" | tr -d ' ')
771+
link="epics/$epic/$name"
772+
if [[ -L "$link" ]]; then
773+
rm "$link"
774+
ln -sf "../../stages/icebox/stories/$name" "$link"
775+
echo "Updated symlink in epic: $epic"
776+
fi
777+
done
778+
fi
779+
780+
# Regenerate README
781+
just board generate
782+
echo "Board updated"
783+
784+
# Move story from icebox to backlog (unblock)
785+
thaw ID:
786+
#!/usr/bin/env bash
787+
set -euo pipefail
788+
cd "{{board_dir}}"
789+
790+
path=$(just board _find-story "{{ID}}")
791+
792+
if [[ -z "$path" ]]; then
793+
echo "Error: Story '{{ID}}' not found"
794+
exit 1
795+
fi
796+
797+
# Check if in icebox
798+
if [[ "$path" != *"icebox"* ]]; then
799+
echo "Error: Story is not in icebox (current location: $path)"
800+
exit 1
801+
fi
802+
803+
name=$(basename "$path")
804+
dest="stages/backlog/stories/$name"
805+
806+
# Get epics from frontmatter before moving
807+
epics=$(grep -m1 "^epics:" "$path" 2>/dev/null | sed 's/^epics: *//' | tr -d '[]' || echo "")
808+
809+
# Move the file
810+
mv "$path" "$dest"
811+
812+
# Update status in frontmatter
813+
sed -i 's/^status: .*/status: backlog/' "$dest"
814+
sed -i "s/^updated: .*/updated: $(date +%Y-%m-%d)/" "$dest"
815+
816+
echo "Thawed: $name"
817+
818+
# Update symlinks in epics
819+
if [[ -n "$epics" ]]; then
820+
IFS=', ' read -ra epic_list <<< "$epics"
821+
for epic in "${epic_list[@]}"; do
822+
epic=$(echo "$epic" | tr -d ' ')
823+
link="epics/$epic/$name"
824+
if [[ -L "$link" ]]; then
825+
rm "$link"
826+
ln -sf "../../stages/backlog/stories/$name" "$link"
827+
echo "Updated symlink in epic: $epic"
828+
fi
829+
done
830+
fi
831+
832+
# Regenerate README
833+
just board generate
834+
echo "Board updated"
835+
721836
# Start a milestone (set status to in-progress)
722837
start-milestone ID:
723838
#!/usr/bin/env bash

0 commit comments

Comments
 (0)