15 tasks · 3 phases · 2026-10-06

Spine flows by surface, and a Plot timeline

Group the Spine’s flows by the app’s nav (Desk, Training, Underworld, Phone), seeded from the tab bar and derived from the Map, and add a Plot section that lays the season’s story moments across those surfaces.

4Surfaces (Peregrine)
34Flows to place
15Tasks
The gist

Flows will sit under the app’s own tabs, in nav order, worked out from the Map and overridable. Plot is a thread through several surfaces, not a tab, so it gets its own lens: a matrix with one row per surface and one column per story moment, so the plot reads left to right across the surfaces it touches.

The problem

The Spine lists 34 Peregrine flows in file order. The app is navigated by four tabs (Desk, Training, Underworld, Phone), and nothing in Mockup Lab knows that. The season’s plot (Act I, the burn, Act II, cleared) shows up on the Desk, the Phone and in games, with no view that follows it.

Approach

Surfaces live in the spine’s resolution file

resolution.json is CodeRaven’s own file, so adding surfaces and moments leaves the Design Studio schema untouched. Old files decode unchanged.

Derived from the Map, overridable

A flow belongs to the surface whose root reaches its first placed step soonest without passing another root. An override wins. Flows no root reaches sit under “Elsewhere”.

Seeded from the tab bar

Tabs are read from TabView source (.tabItem { Label(…) } or Tab(…)) and matched to spine screens through linked mockups, then names. The rejected alternative, typing surfaces by hand only, would drift from the app.

Plot as a surface × moment matrix

One cell per flow per moment, with step-level moments overriding the flow’s. The existing matrix layout gets an explicit column order so moments read in story order.

Decisions made for you

Judgment call

Plot is a lens, not a fifth group

You said Plot isn’t a nav and asked for the best way to see it develop. A timeline across surfaces shows where and when each plot beat lands. Reversible by dropping the Plot section; the moment tags stay harmless.

Judgment call

One cell per flow per moment

A cell per step would put about 170 frames on the board. Tagging a single step still gives that step its own cell.

The work

Phase 1 — Surfaces

7 tasks
  • Add NavSurface + surfaces/flowSurfaces to ExperienceResolution with lenient decoding
  • Add SpineSurfaces derivation (override, else nearest root on the Map, else Elsewhere)
  • Add AppTabs reader for TabView tabs and map them to spine screens
  • Add heading groups to storyboards and group the Flows live board by surface
  • Group the Flows list view by surface
  • Add the Surfaces sheet and a Surface submenu on flows
  • Add Organize spine ops addSurface, updateSurface, moveSurface, removeSurface, setFlowSurface and show surfaces in the spine text

Phase 2 — Plot

5 tasks
  • Add StoryMoment + moments/flowMoments/stepMoments to ExperienceResolution
  • Add columnOrder to the resolved board so matrix columns follow the moment order
  • Add the Plot section: surface × moment matrix board and a list fallback
  • Add the Moments sheet and Story moment submenus on flows and steps
  • Add Organize spine ops addMoment, updateMoment, moveMoment, removeMoment, setFlowMoment, setStepMoment

Phase 3 — Verify

3 tasks
  • xcodebuild + verify-build-product
  • Harness: AppTabs on Peregrine's PeregrineRootView, surface derivation on Peregrine's real spine, old resolution.json decodes
  • In-app: Flows grouped by Desk, Training, Underworld, Phone; Plot after Organize drafts moments (Sarah)

Risks & edge cases

Edge case

Flows reached only via the Night Desk entry

They land under “Elsewhere” until a surface root or an override places them.

Edge case

The Phone tab’s root is a property

phoneTab isn’t a view type, so the Phone tab is matched to the spine screen by name.

Setup

The Plot starts empty

It needs moments drafted (by Organize or by hand) before it shows anything.

Out of scope

Grouping the Screens section and the Registry by surface. Both can reuse the same derivation later.

Final review

The model reuses the Map as the source of nav truth and keeps new state in CodeRaven’s own file. Weakest: tab-label parsing is regex over SwiftUI, and the Plot is only as good as the moments drafted for it.

72/100

The surface grouping is well grounded; the Plot lens is a new representation whose value depends on moment drafting.