skip to content
Replays

Feed Card Durations

Durations That Survive the Feed

Making activity cards tick while open, freeze when closed, and replay with the same timing.

Gantry milestones

1 milestones 2 tasks

2 plan 2 execute 3 review

Making activity cards tick while open, freeze when closed, and replay with the same timing.

5h 58m total 11m 1s per task

This run made activity-feed timing a card contract instead of an accident of progress beats. The visible gap was merge work that could sit on screen without a duration, but the plan treated that as a symptom: any covered non-waiting card should derive elapsed time while running, settle it when finished, and keep useful metrics when a closing event has nothing new to report.

The decomposition put the front-end fold and render rule before the engine durability work. That let the later sprint make mechanical finishers provide authoritative timing without also deciding how cards display, replay, or preserve metrics.

How this walkthrough is structured

Feature

What did the run build and ship?

The feed, journal replay, headless output, and stage statistics now share durable elapsed values for timed work while preserving already reported card metrics.

Build

How did Gantry structure the work?

The run first established a card-level timing contract, then fed it from mechanical close events, with final integration needing resolver attention after the milestone itself had stayed green.

Milestone 1

Keep Durations

2 tasks 7 agents 33m 33s wall time

The milestone left timing behavior across the TUI, headless renderer, and engine finish paths. Current code still stores card start times, freezes closed elapsed values, merges sparse closing metrics with prior progress data, and formats finished headless stages from the same durable or reconstructed timing. The touched files are still present in the live tree, with later edits mostly extending the same areas rather than replacing the feature.

This milestone carried the whole duration change as a compact vertical slice. Its brief joined visible feed behavior, replay reconstruction, metrics preservation, and engine-side mechanical timings because those pieces had to agree on the same close-time precedence. The cut still split cleanly inside the milestone: first the card contract, then the durable producer side. The sprint work itself stayed green, while the run-level merge later exposed integration stress that needed resolver attention before the final gates cleared.

Card Timing Contract

2 agents 11m 1s wall time

The TUI state fold now keeps a card start instant, chooses a final elapsed value from closing metrics or event timestamps, and merges missing closing metrics with values already reported by progress. Rendering derives the header tag for running cards from the render time and leaves closed cards fixed, while review verdict suffixes remain after the duration. The deterministic fold and render tests for ticking, frozen merge cards and metric preservation are still in the tree.

This sprint took the front-end contract alone. Its brief gave a fresh agent a clear boundary: fold timestamped start and finish events into card state, render running cards from the current frame time, and keep waiting cards on their existing countdown semantics. It also carried the adjacent sparse-metrics bug because that bug lived at the same close-event boundary. The sprint passed without a recorded repair, which fits a contract sprint whose tests drove explicit event times rather than wall clock behavior.

Durable Mechanical Durations

2 agents 14m 1s wall time

Engine finish paths now attach measured durations to merge closes and mechanical resolution closes, including success and handoff-style outcomes. Headless output removes the stage start timestamp and prefers the durable duration when it prints a finished stage, falling back to event timing when needed. The live tests still cover journaled merge duration and measured resolution finishers, so replay and text output remain tied to the same metrics the feed consumes.

This sprint consumed the contract rather than reopening it. Its brief was engine-facing: timed mechanical finishers had to close with measured duration metrics, while progress beats stayed optional status updates. That made the work small enough for a clean-context agent because the front end already knew how to prefer an authoritative close duration and how to fall back when none existed. It also passed without a recorded repair, leaving the later conflict at the run merge boundary rather than inside this sprint.