Skip to content

Commit 40ddc7d

Browse files
khaliqgantclaude
andcommitted
Rework to hybrid: self-contained Phase 1 + deferred Phase 2
Phase 1 (specs/storybook/, single-repo, no product edits): - pull/watch instead of push: a story-builder watcher persona (020) synthesizes planning/review/runtime stories (021/022/023) from artifacts products already write to relayfile (/notion,/linear, /github/**/reviews, /nightcto/signals) — zero changes to sage/MSD/nightcto/pear. - renderer @code-story/react (030) vendored from MSD's tokenizer/diffUtils/PRStory (one-time copy, no MSD import); standalone web viewer (031) + guided tour (032) as the Phase 1 surface. - drop the per-repo **Repo:** slugs from Phase 1 -> single-repo per-wave mode. Phase 2 (specs/storybook-phase2/, DEFERRED, cross-repo dispatch): - per-product emit hooks for richer stories (sage 010, MSD 020, nightcto 030) and inline embeds (MSD webapp 021, Pear 040), each with a **Repo:** slug. Also: lint treats **Repo:** as optional (validated only if present); README + PROGRAM updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5f5b2bc commit 40ddc7d

31 files changed

Lines changed: 656 additions & 440 deletions

README.md

Lines changed: 58 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,46 +8,51 @@ metrics (churn, hotspots, coverage). Agents do the writing; humans read and stay
88
This repo holds the **spec program** and the **runbook**. It is built spec-by-spec by Ricky
99
(the workflow agent) via an overnight runner — not hand-written all at once.
1010

11-
## How it works
11+
## Two phases
1212

13-
```
14-
Sage / MSD / NightCTO workflows
15-
│ (call the shared story-writer skill as a side-effect of their work)
16-
17-
@code-story/skill ──writes──▶ relayfile /stories/<type>/<id>.json (the artifact)
18-
▲ ▲
19-
code-narrator persona ┘ └ code-health persona (churn/hotspots/coverage)
20-
21-
@code-story/react (one shared, artifact-driven, read-only renderer,
22-
▲ extracted from MSD's renderer + PRStory)
23-
┌──────────────┼───────────────┐
24-
MSD webapp Pear `story` web guided tour (stepped)
25-
(primary web) view mode hosted by MSD webapp + Pear
26-
```
13+
- **Phase 1 — self-contained (default).** Everything lives in this repo. A **watcher** persona
14+
synthesizes stories from artifacts products *already* write to relayfile (pull, not push), and
15+
a **standalone web viewer** renders them. **Zero changes to sage/MSD/nightcto/pear.** One repo,
16+
one deploy, per-wave PRs. → `specs/storybook/`
17+
- **Phase 2 — deferred, cross-repo (optional).** When you want *richer* stories (products emit
18+
with their internal context) or stories rendered *inline* inside Pear/MSD, edit those repos.
19+
Cross-repo, so it runs via dispatch mode. → `specs/storybook-phase2/`
20+
21+
Start with Phase 1; reach for Phase 2 only where the extra richness/inline-surface pays off.
2722

28-
- **relayfile** is the artifact substrate — stories are JSON files; "the filesystem is the protocol."
29-
- The **renderer is extracted from MSD** (custom tokenizer highlighting, `diffUtils`, and the
30-
`PRStory` slide-deck), generalized into one backend-free `@code-story/react` package that MSD's
31-
webapp, Pear, and the web tour all consume — so no surface reimplements code rendering.
32-
- Two helper **personas** (narrator, health) enrich stories; the three product agents emit them.
23+
## How Phase 1 works
3324

34-
See [`specs/storybook/PROGRAM.md`](specs/storybook/PROGRAM.md) for the full architecture and
35-
[`docs/storybook-boundary.md`] (produced by spec `000`) for the frozen scope.
25+
```
26+
products already write to relayfile (no storybook code in them):
27+
Sage → /notion,/linear MSD → /github/**/reviews NightCTO → /nightcto/signals
28+
│ (the watcher OBSERVES these)
29+
30+
personas/story-builder ─synthesize→ @code-story/skill ─writes→ /stories/<type>/<id>.json
31+
▲ ▲
32+
code-narrator persona ┘ └ code-health persona (churn/hotspots/coverage)
33+
34+
@code-story/react (read-only renderer, vendored from MSD)
35+
36+
web/ standalone viewer + guided tour ◀── the Phase 1 surface
37+
```
3638

37-
## Why its own repo
39+
- **relayfile** is the substrate *and* the integration: the watcher reads files products already
40+
produce, so Phase 1 touches no other repo. "The filesystem is the protocol."
41+
- The renderer is **vendored from MSD** (its tokenizer highlighting, `diffUtils`, and the `PRStory`
42+
slide-deck) into one backend-free `@code-story/react` — a one-time copy, no MSD import/edit.
3843

39-
Storybook spans repos — Sage, MSD, Pear, and a shared `@code-story` package all participate.
40-
It does not belong inside any one of them, so the spec program + orchestration live here.
44+
See [`specs/storybook/PROGRAM.md`](specs/storybook/PROGRAM.md) for the architecture and
45+
`docs/storybook-boundary.md` (produced by spec `000`) for the frozen scope.
4146

42-
## Spec program (14 specs, 5 waves)
47+
## Phase 1 spec program (14 specs, 5 waves — all in this repo)
4348

44-
| Wave | Specs | Target |
45-
|---|---|---|
46-
| 0 — Contract | `000` boundary · `001` `CodeStory` schema | shared `@code-story` |
47-
| 1 — Writer | `010` story-writer skill · `011` index + ACL | shared `@code-story` |
48-
| 2 — Emit | `020` Sage planning · `021` MSD review · `022` NightCTO runtime | sage · My-Senior-Dev/app · nightcto |
49-
| 3 — Renderer | `030` extract `@code-story/react` from MSD · `031` Pear mount · `032` MSD webapp surface · `033` web tour | My-Senior-Dev/app → shared · pear |
50-
| 4 — Narrate/health/proof | `040` narrator persona · `041` health persona · `042` e2e proof | shared (cross-repo e2e) |
49+
| Wave | Specs |
50+
|---|---|
51+
| 0 — Contract | `000` boundary · `001` `CodeStory` schema |
52+
| 1 — Library | `010` story-writer skill · `011` index + ACL |
53+
| 2 — Watcher | `020` story-builder · `021` planning synthesis · `022` review synthesis · `023` runtime synthesis |
54+
| 3 — Renderer + viewer | `030` `@code-story/react` (vendored) · `031` standalone viewer · `032` guided tour |
55+
| 4 — Narrate/health/proof | `040` narrator persona · `041` health persona · `042` e2e proof |
5156

5257
Each spec is bounded (`Goal / Context / In scope / Out of scope / Acceptance / Review / Handoff`)
5358
and ends with a reviewer-checkable PASS gate.
@@ -59,60 +64,47 @@ Specs are implemented one at a time by Ricky, in dependency order, with an
5964
`specs/storybook/_review.md` / `_fix.md`).
6065

6166
```bash
62-
# inspect the plan (no side effects)
63-
./scripts/run-overnight.sh storybook --dry-run
64-
65-
# run it: implement → review → fix each spec, commit, open a draft PR per wave
66-
./scripts/run-overnight.sh storybook
67+
# Phase 1 (self-contained, single repo, per-wave PRs)
68+
./scripts/run-overnight.sh storybook --dry-run # inspect the plan (no side effects)
69+
./scripts/run-overnight.sh storybook # implement → review → fix, commit, PR per wave
6770
```
6871

6972
Flags / env:
7073
- `--from <spec-id>` — resume from a spec (e.g. `--from 030`)
7174
- `--no-pr` — skip per-wave draft PRs
7275
- `MAX_REVIEW_ITERS` (default 3) — review/fix loop cap
73-
- `REVIEW_CMD` / `FIX_CMD` — override the reviewer/fixer invocation (default: Ricky local with `_review.md` / `_fix.md`)
74-
75-
### Cross-repo dispatch (automatic)
76-
77-
Storybook is cross-repo, so each spec declares a machine-readable **`**Repo:**` slug** in its
78-
header. The runner auto-detects these and switches to **dispatch mode**: each spec is
79-
implemented in its **target repo** on a `results/storybook` branch, and a draft PR is opened
80-
**per touched repo** — no manual repo-hopping.
81-
82-
Slugs resolve to local repo paths (sibling clones assumed):
76+
- `REVIEW_CMD` / `FIX_CMD` — override the reviewer/fixer invocation
8377

84-
| slug | resolves to | holds |
85-
|---|---|---|
86-
| `code-storybook` | this repo | the shared `@code-story` package (schema, skill, `react` renderer, helper personas) |
87-
| `sage` | `$PROJECTS_ROOT/sage` | `020` planning story |
88-
| `my-senior-dev` | `$PROJECTS_ROOT/../My-Senior-Dev/app` | `021` review story, `030` extract, `032` webapp surface |
89-
| `nightcto` | `$PROJECTS_ROOT/nightcto` | `022` runtime story |
90-
| `pear` | `$PROJECTS_ROOT/pear` | `031` story view |
78+
### Phase 2 (deferred, cross-repo dispatch)
9179

92-
`PROJECTS_ROOT` defaults to this repo's parent; override any path with `REPO_<slug>` env
93-
(e.g. `REPO_my_senior_dev=/path/to/app`). Inspect routing first with `--dry-run`:
80+
Phase 2 specs declare a machine-readable `**Repo:**` slug; the runner auto-detects these and
81+
switches to **dispatch mode** — each spec is implemented in its target repo on a
82+
`results/storybook-phase2` branch, one draft PR **per touched repo**.
9483

9584
```bash
96-
./scripts/run-overnight.sh storybook --dry-run # prints START <spec> -> <slug> (<repo>)
85+
./scripts/run-overnight.sh storybook-phase2 --dry-run # prints START <spec> -> <slug> (<repo>)
86+
./scripts/run-overnight.sh storybook-phase2
9787
```
9888

99-
Because of dependencies, the shared pieces (waves 0–1 + the `030` extract) build first in
100-
`code-storybook`; publish `@code-story`, then the per-product specs consume it. The runner
101-
walks them in order and the review cycle gates each before moving on.
89+
Slugs resolve to local repo paths (sibling clones assumed): `sage`, `nightcto`, `pear`
90+
`$PROJECTS_ROOT/<slug>`; `my-senior-dev``$PROJECTS_ROOT/../My-Senior-Dev/app`. `PROJECTS_ROOT`
91+
defaults to this repo's parent; override any path with `REPO_<slug>` (e.g. `REPO_my_senior_dev=…`).
92+
Phase 2 depends on Phase 1 being merged and `@code-story` published.
10293

10394
## Spec format & CI
10495

10596
Every numbered spec must carry the sections the runner + reviewer rely on
106-
(`Goal / In scope / Out of scope / Acceptance / Review / Handoff`) and a valid `**Repo:**`
107-
slug. `scripts/lint-specs.sh` enforces this and runs in CI (`.github/workflows/lint-specs.yml`)
108-
on every push/PR touching `specs/`:
97+
(`Goal / In scope / Out of scope / Acceptance / Review / Handoff`). A `**Repo:**` slug is
98+
**optional** (Phase 1 omits it; Phase 2 requires it for dispatch) and, when present, must be a
99+
valid slug. `scripts/lint-specs.sh` enforces this in CI (`.github/workflows/lint-specs.yml`) on
100+
every push/PR touching `specs/`:
109101

110102
```bash
111-
./scripts/lint-specs.sh # OK — N specs, all have required sections + a valid **Repo:** header
103+
./scripts/lint-specs.sh # OK — N specs, all have required sections (and any **Repo:** slug is valid)
112104
```
113105

114106
## Related
115107

116108
- `AgentWorkforce/nightcto``specs/persona-migration/` — the reference persona migration this
117-
storybook program assumes (NightCTO emits runtime stories from its migrated watch handler).
109+
program assumes (NightCTO writes the `/nightcto/signals/**` the runtime synthesizer reads).
118110
- `AgentWorkforce/nightcto``specs/INVENTORY.md` — front door indexing both programs.

scripts/lint-specs.sh

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
88
SPECS_ROOT="${1:-$ROOT/specs}"
99

1010
REQUIRED_SECTIONS=("## Goal" "## In scope" "## Out of scope" "## Acceptance" "## Review" "## Handoff")
11-
REQUIRED_HEADERS=("**Repo:**") # machine-readable dispatch target
11+
# **Repo:** is OPTIONAL: single-repo (Phase 1) specs omit it; cross-repo (Phase 2) specs
12+
# carry it for dispatch. When present it must resolve to a known slug (checked below).
1213

1314
fail=0
1415
count=0
@@ -19,10 +20,7 @@ while IFS= read -r f; do
1920
for s in "${REQUIRED_SECTIONS[@]}"; do
2021
grep -qF "$s" "$f" || missing="${missing}\n missing section: ${s}"
2122
done
22-
for h in "${REQUIRED_HEADERS[@]}"; do
23-
grep -qF "$h" "$f" || missing="${missing}\n missing header: ${h}"
24-
done
25-
# the Repo header must resolve to a known slug
23+
# **Repo:** is optional; if present it must resolve to a known slug
2624
if grep -qF "**Repo:**" "$f"; then
2725
slug="$(grep -m1 -oE '\*\*Repo:\*\* [A-Za-z0-9_-]+' "$f" | awk '{print $2}')"
2826
case "$slug" in
@@ -38,9 +36,9 @@ done < <(find "$SPECS_ROOT" -type f -name '[0-9][0-9][0-9]-*.md' | sort)
3836

3937
if [ "$count" -eq 0 ]; then echo "No numbered specs found under $SPECS_ROOT"; exit 1; fi
4038
if [ "$fail" -eq 0 ]; then
41-
echo "OK — $count specs, all have required sections + a valid **Repo:** header."
39+
echo "OK — $count specs, all have required sections (and any **Repo:** slug is valid)."
4240
else
4341
echo
44-
echo "Spec lint failed. Each numbered spec needs: ${REQUIRED_SECTIONS[*]} and a **Repo:** <slug> header."
42+
echo "Spec lint failed. Each numbered spec needs: ${REQUIRED_SECTIONS[*]}. (A **Repo:** slug is optional but must be valid if present.)"
4543
fi
4644
exit "$fail"
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# 010 — Sage planning emit (richer)
2+
3+
**Status:** DEFERRED | **Phase:** 2 | **Repo:** sage | **Depends on:** Phase 1 (`@code-story` published)
4+
5+
## Goal
6+
Make Sage emit a planning `CodeStory` directly from its issue pipeline, carrying its **internal**
7+
S/M/L rationale and reuse/conflict analysis as first-class data — richer than what Phase 1's
8+
watcher can synthesize by observing Sage's relayfile outputs.
9+
10+
## Context
11+
Phase 1 (`specs/storybook/021`) already produces a planning story by reading Sage's spec/Linear/
12+
Notion artifacts. This spec upgrades that for Sage specifically: Sage calls the `@code-story`
13+
writer at proposal time with data it has in-process but doesn't fully persist (sizing rationale,
14+
candidate reuse targets). When Sage emits, the watcher defers to the emitted story (dedupe by subject).
15+
16+
## In scope
17+
- Add `@code-story` (skill) as a sage dependency.
18+
- After Sage synthesizes a proposal, build + `.write()` a planning story with: narrative (proposal + S/M/L rationale), ascii arch diagram, code refs for reuse candidates, links (Slack/Linear/Notion).
19+
- Mark the story so the Phase 1 watcher skips synthesizing a duplicate for that subject.
20+
- Test: a fixture Sage proposal emits a schema-valid planning story richer than the observed-synthesis baseline.
21+
22+
## Out of scope
23+
- Changing Sage's planning logic. Rendering. Other layers.
24+
25+
## Acceptance
26+
- Sage's planning-emit test passes; story validates against `@code-story/schema`.
27+
- The watcher does not also synthesize a duplicate planning story for the same subject.
28+
29+
## Review
30+
Reviewer confirms emission is best-effort (never breaks the proposal), the dedupe prevents
31+
double stories, and the emitted story is genuinely richer than the Phase 1 baseline. PASS on green tests.
32+
33+
## Handoff
34+
Supersedes Phase 1 `021` for Sage-originated planning stories.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# 020 — MSD review emit (richer)
2+
3+
**Status:** DEFERRED | **Phase:** 2 | **Repo:** my-senior-dev | **Depends on:** Phase 1 (`@code-story` published)
4+
5+
## Goal
6+
Make MSD emit a review `CodeStory` from its review flow, carrying its own prioritized findings,
7+
merge-readiness verdict, and blocker explanations — richer than Phase 1's watcher synthesis from
8+
`/github/**/reviews/**`.
9+
10+
## Context
11+
Phase 1 (`specs/storybook/022`) synthesizes a review story by observing PR reviews in relayfile.
12+
MSD has more in-process (finding priority, merge-readiness, autofix eligibility); this spec emits
13+
that directly. When MSD emits, the watcher defers (dedupe by PR subject).
14+
15+
## In scope
16+
- Add `@code-story` (skill) as an MSD dependency.
17+
- After a review completes, build + `.write()` a review story: diff sections, prioritized findings narrative, merge-readiness verdict, code refs, links (PR + upstream planning story if traced).
18+
- Mark the story so the Phase 1 watcher skips the observed-synthesis duplicate.
19+
- Test: a fixture review emits a schema-valid review story richer than the baseline.
20+
21+
## Out of scope
22+
- Changing MSD's review/autofix logic. The webapp embed (`021`). Other layers.
23+
24+
## Acceptance
25+
- MSD's review-emit test passes; story validates against `@code-story/schema`.
26+
- No duplicate observed-synthesis story for the same PR.
27+
28+
## Review
29+
Reviewer confirms emission reuses MSD's existing findings (no re-review), is best-effort, dedupe
30+
holds, and the emitted story is richer than the Phase 1 baseline. PASS on green tests.
31+
32+
## Handoff
33+
Supersedes Phase 1 `022` for MSD-originated review stories; `021` can surface them in MSD's webapp.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# 021 — MSD webapp inline embed
2+
3+
**Status:** DEFERRED | **Phase:** 2 | **Repo:** my-senior-dev | **Depends on:** Phase 1 (`@code-story/react` published)
4+
5+
## Goal
6+
Mount `@code-story/react` inside MSD's webapp so stories render **inline** in MSD's product UI,
7+
not only in the standalone viewer — and link a PR's review story from MSD's existing PR view.
8+
9+
## Context
10+
The renderer was vendored *from* MSD in Phase 1 (`specs/storybook/030`), so MSD re-consuming it
11+
as a package keeps its review UI and the storybook DRY. MSD webapp: React 18 + Vite + `vite-react-ssg`
12+
+ Tailwind 4. Stories load from relayfile (read scope), so planning/runtime stories render too.
13+
14+
## In scope
15+
- Add `@code-story/react` + `@relayfile/sdk` to the webapp.
16+
- A `/stories` route: list (via `listStories`) + a story page mounting `<StoryView>` / `<StoryTour>`.
17+
- `onOpenRef` opens the file read-only via MSD's existing file viewer (reuse, don't rebuild).
18+
- Link the review story from the existing PR view when one exists.
19+
- Test: `/stories` renders a fixture story of each type via the shared renderer.
20+
21+
## Out of scope
22+
- Refactoring MSD's `FileDetailModal`/backend. The standalone viewer (Phase 1 `031`). Auth beyond the relayfile read scope.
23+
24+
## Acceptance
25+
- MSD webapp builds with `@code-story/react`; `/stories` renders one story of each type.
26+
- Stories load from relayfile, not the MSD backend API.
27+
28+
## Review
29+
Reviewer confirms the webapp consumes the shared package (no second renderer), stories load via
30+
relayfile (decoupled from MSD's PR backend), and read-only holds. PASS on green build + test.
31+
32+
## Handoff
33+
MSD users get inline storybooks; the standalone viewer remains the cross-product surface.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# 030 — NightCTO runtime emit (richer)
2+
3+
**Status:** DEFERRED | **Phase:** 2 | **Repo:** nightcto | **Depends on:** Phase 1 (`@code-story` published)
4+
5+
## Goal
6+
Make NightCTO emit a runtime `CodeStory` from its incident handler at incident time, carrying
7+
triage internals (rationale, urgency, hotfix reasoning) — richer than Phase 1's watcher synthesis
8+
from `/nightcto/signals/**`.
9+
10+
## Context
11+
Phase 1 (`specs/storybook/023`) synthesizes a runtime story by observing the signals/feature-log
12+
NightCTO already writes (per the persona-migration). This spec emits a richer story inline in the
13+
watch handler, with data it has at triage time. When NightCTO emits, the watcher defers (dedupe by incident).
14+
15+
## In scope
16+
- Add `@code-story` (skill) as a nightcto dependency (its `personas/watch` handler).
17+
- In the high-urgency incident path, build + `.write()` a runtime story: incident + triage rationale narrative, implicated code refs, hotfix diff if any, links (source alert, hotfix PR, upstream review/feature).
18+
- Mark the story so the Phase 1 watcher skips the observed-synthesis duplicate.
19+
- Test: a fixture incident emits a schema-valid runtime story richer than the baseline; correlated incident links the upstream review.
20+
21+
## Out of scope
22+
- Changing triage/hotfix logic (the persona-migration owns it). Rendering. Other layers.
23+
24+
## Acceptance
25+
- NightCTO's runtime-emit test passes; story validates against `@code-story/schema`.
26+
- No duplicate observed-synthesis story for the same incident.
27+
28+
## Review
29+
Reviewer confirms emission reuses the migration's incident/triage output (no re-derivation), is
30+
best-effort (never blocks the alert), dedupe holds, and the emitted story is richer than the
31+
Phase 1 baseline. PASS on green tests.
32+
33+
## Handoff
34+
Supersedes Phase 1 `023` for NightCTO-originated runtime stories; closes the richest plan→review→runtime loop.

0 commit comments

Comments
 (0)