The Release Machine
City Pulse Live has two blockers. Both are 90% complete and both are late. One holds a local launch asset; the other keeps nine unfinished tasks across four teams from even becoming possible.
Which blocker prevents the most downstream work from becoming possible?
Count the unfinished tasks that depend on each blocker. That identifies how widely a delay reaches; estimating a launch date would also require task durations and capacity.
The schedule looks busy and nearly ready.
Use the schedule to compare planned dates, task duration, progress and team ownership.
The machine stalls at a decision.
A completed task tips its tile and releases a ball for each dependency. Follow those balls to see which tasks have all their prerequisites and can begin.
| Task | Lane | Progress | State | Waiting on | Downstream reach |
|---|---|---|---|---|---|
| Approve product brief | Product | 100% | Armed | None | 15 tasks /5 lanes |
| Finalize interaction specification | Product | 100% | Waiting | brief | 8 tasks /3 lanes |
| Approve event-retention policy | Product | 90% | Blocked | Legal decision on 30-day event retention | 9 tasks /4 lanes |
| Build representative event fixture | Data | 100% | Waiting | brief | 12 tasks /4 lanes |
| Finalize event schema | Data | 25% | Waiting | privacy-approval, sample-fixture | 8 tasks /4 lanes |
| Implement streaming ingest | Data | 0% | Waiting | event-schema | 4 tasks /3 lanes |
| Implement aggregation API | Data | 10% | Waiting | event-schema | 4 tasks /3 lanes |
| Build dashboard shell | Frontend | 100% | Waiting | interaction-spec | 5 tasks /3 lanes |
| Build static dashboard view | Frontend | 100% | Waiting | app-shell, sample-fixture | 5 tasks /3 lanes |
| Add replay and pause controls | Frontend | 70% | Waiting | static-view | 0 tasks /0 lanes |
| Connect the live event stream | Frontend | 15% | Waiting | aggregate-api, stream-ingest | 3 tasks /2 lanes |
| Implement keyboard navigation | Quality | 60% | Waiting | static-view | 2 tasks /1 lanes |
| Validate settled SSR rendering | Quality | 80% | Waiting | static-view | 2 tasks /1 lanes |
| Complete security threat model | Quality | 10% | Waiting | event-schema, privacy-approval | 2 tasks /1 lanes |
| Run live-stream load test | Quality | 0% | Waiting | live-binding | 2 tasks /1 lanes |
| Finalize documentation copy | Launch | 45% | Waiting | event-schema, interaction-spec | 2 tasks /1 lanes |
| Finish launch illustration | Launch | 90% | Blocked | Asset license has not been cleared | 2 tasks /1 lanes |
| Produce social preview card | Launch | 0% | Waiting | hero-art | 1 tasks /1 lanes |
| Cut release candidate | Launch | 0% | Waiting | docs-copy, keyboard-nav, live-binding, load-test, ssr-settle, threat-model | 1 tasks /1 lanes |
| Launch City Pulse Live | Launch | 0% | Waiting | release-candidate, social-card | 0 tasks /0 lanes |
Approve event-retention policy
Legal decision on 30-day event retention
Data / Frontend / Quality / Launch
Physics performs the enactment; chart logic preserves the claim.
Recorded completedDay, pushed done state, or a clearly labelled mechanical completion.
One prerequisite became satisfied. It does not mean the target work happened.
Every incoming edge must be delivered before the task becomes armed.
Blocking is a readable pin, never hidden friction, mass, or restitution.
The analysis survives without animation.
| Task | Lane | Progress | State | Waiting on | Downstream reach |
|---|---|---|---|---|---|
| Product | 100% | done | None | 15 tasks / 5 lanes | |
| Product | 100% | done | brief | 8 tasks / 3 lanes | |
| Product | 90% | blocked | Legal decision on 30-day event retention | 9 tasks / 4 lanes | |
| Data | 100% | done | brief | 12 tasks / 4 lanes | |
| Data | 25% | waiting | privacy-approval, sample-fixture | 8 tasks / 4 lanes | |
| Data | 0% | waiting | event-schema | 4 tasks / 3 lanes | |
| Data | 10% | waiting | event-schema | 4 tasks / 3 lanes | |
| Frontend | 100% | done | interaction-spec | 5 tasks / 3 lanes | |
| Frontend | 100% | done | app-shell, sample-fixture | 5 tasks / 3 lanes | |
| Frontend | 70% | in-progress | static-view | 0 tasks / 0 lanes | |
| Frontend | 15% | waiting | aggregate-api, stream-ingest | 3 tasks / 2 lanes | |
| Quality | 60% | in-progress | static-view | 2 tasks / 1 lanes | |
| Quality | 80% | in-progress | static-view | 2 tasks / 1 lanes | |
| Quality | 10% | waiting | event-schema, privacy-approval | 2 tasks / 1 lanes | |
| Quality | 0% | waiting | live-binding | 2 tasks / 1 lanes | |
| Launch | 45% | waiting | event-schema, interaction-spec | 2 tasks / 1 lanes | |
| Launch | 90% | blocked | Asset license has not been cleared | 2 tasks / 1 lanes | |
| Launch | 0% | waiting | hero-art | 1 tasks / 1 lanes | |
| Launch | 0% | waiting | docs-copy, keyboard-nav, live-binding, load-test, ssr-settle, threat-model | 1 tasks / 1 lanes | |
| Launch | 0% | waiting | release-candidate, social-card | 0 tasks / 0 lanes |
The machine is compiled from a dependency graph.
The chart extracts DAG validation, longest-path levels, lane placement, socket IDs, point-based track routes, logical joins, replay folding, and blocker amplification. The kernel has no angular dynamics, so task tipping remains honest logical rendering; StreamPhysicsFrame owns the dependency-token motion and settling.
const commonTaskProps = { data: cityPulseTasks, taskIDAccessor: "id", labelAccessor: "title", laneAccessor: "lane", startAccessor: "startDay", endAccessor: "endDay", progressAccessor: "progress", statusAccessor: "status", dependencyAccessor: "dependsOn", completionTimeAccessor: "completedDay", blockerAccessor: "blockerReason", } // View 1 — conventional swimlane, via the shipped recipe. <OrdinalCustomChart data={cityPulseTasks} layout={intervalLanesLayout} categoryAccessor="lane" oExtent={LANES} layoutConfig={{ laneAccessor: "lane", startAccessor: "startDay", endAccessor: "endDay", domain: [0, 18], lanes: LANES, axisTicks: [0, 3, 6, 9, 12, 15, 18], periods: [{ start: 0, end: 11, name: "Elapsed through day 11" }], color: (task) => STATUS_FILL[task.status], }} /> <ChainReactionChart {...commonTaskProps} currentTime={11} mechanism="domino-ball" orientation="vertical" mode="replay" insight="blocker-amplification" /> // A preview changes mechanical state, never supplied data. machineRef.current.previewResolve("privacy-approval")