Timeline & Journey Status

Oct 3, 2026 · @Mark

Bet 4 and FEATURE-26 are both committed and pushed to new-ui. Neither is shipped: the agreed state is pushed → awaiting device verification → shipped only after a list and grid pass.

Decisions settled

FEATURE-30 is decided: the organizing story is the journey, not a taxonomy — AstroMatrix takes you from who you are, to how you connect, to what's happening now, to where those patterns are going. Store-listing test it has to compress into: Your chart. Your relationships. What's happening now. What comes next.

The list/grid defect

The first bet 4 implementation would have been invisible to every user in list view, while reading as shipped. It was caught only because the reuse question was asked directly.

What was wrong. The duration label was written into AstroItemCard._buildGridLayout. But AstroItemCard.build() returns AstroListTile whenever isGrid == false (astro_item_card.dart:128), and MatrixCategoryPanel picks grid vs list from a user-toggleable view mode (matrix_category_panel.dart:120-138; _MatrixItemsList passes isGrid: false at :529 and :565). Anyone whose panel was in list mode would have seen nothing.

Why it matters beyond this change. This is the verify-the-effect-not-the-deployment trap in UI form: it compiled, the analyzer was clean, the code existed, and the label was absent from half the audience. A code-path citation showing a call site exists is not evidence that the call site renders.

How it was fixed. The logic moved into the one shared component both branches already used:

A latent force-unwrap was fixed on the way: AstroDateLabel's listUsesChartColors branch re-derived _formatFullDate(displayDate!) instead of using the computed value, and would have thrown whenever displayDate was null — already reachable through the isList range path.

Code paths touched

All in astromatrix-flutter, all uncommitted and unpushed. flutter analyze is clean on every file — the one remaining warning in astro_list_tile.dart:186 is pre-existing, confirmed by diff.

File Change Shared?
lib/utils/astro_helper.dart New temporalStatusLabel — the three bet 4 phrasings from begins/ends/exact Yes — single source of the phrasing
lib/widgets/astro_date_label.dart New opt-in showTemporalStatus; status substitutes for prefix+date in the same Row; listUsesChartColors branch now uses the computed value Yes — single source of the rendering, used by both layouts
lib/widgets/astro_item_card.dart Passes showTemporalStatus: true on the grid path; the duplicated block was removed Call site only
lib/widgets/astro_list_tile.dart Passes showTemporalStatus: true — the branch the Matrix/Home list panels actually render Call site only

Not mine, left untouched: lib/services/purchase_service_stub.dart was already modified before this session.

The already-committed half of bet 4 is ISSUE-137(a) (48c3725d): the active-first, nearest-peak sort at matrix_service.dart:757-774. It is also committed-not-pushed, so both halves ride the same push decision.

FEATURE-26 — two surfaces, only one solved

Do not read "facet routing exists" as "identity-led Home is done." These are different surfaces and only one is covered.

Shipped 2026-10-03 (51e6be0d). Identity is now integrated into the daily panel rather than promoted as a competing one. Two importantBirth items lead; the daily take(8) is untouched, so no transit content is lost. They lead rather than interleave on purpose — mixed together, a natal trait and a passing transit become indistinguishable, which is the confusion the panel exists to resolve. Core Themes stops being its own panel, so Home carries three instead of four, and _buildCoreThemes / _getTitleForImportantBirth were deleted with it.

The panel is renamed Daily Overview → What Matters Now: it now holds enduring items too, and the old name implied everything in it was about today. The HelpService section key stays 'Daily Overview' so existing help content still resolves.

The framing correction that made this right. Home was already fully personal — every panel comes from the same chart through filterByType. So this was never about adding personalisation. It is about enduring vs. time-bound: importantBirth items are true of you always, daily items are true this week. That is what two natal items at the top actually buy.

Applied to everyone for V1, deliberately. Weighting it by maturity needs a demonstrated-acts signal that does not exist, and the row's own "first ~3 sessions" wording is exactly the session count we do not gate on. Measure first; differentiate when there is a real signal to differentiate on.

Open dependencies

Three rows were filed this session. None is implemented, and all three need a change in a repo that is lookup-only here.

Row What it unblocks Blocked on
FEATURE-80 Strength-weighted ranking (Timeline V2) The external CalculateHoroscopes engine emitting a per-aspect orb, then mapping it into MatrixItem.orb — the field exists at matrix_models.dart:74 but nothing populates it. Owner is whoever owns the legacy engine; outside both repos. Deliberately off Timeline V1's path.
ISSUE-539 Per-cohort onboarding drop-off analysis A uid-joinable step event. Node must declare the receiving schema fields with or before the client change.
ISSUE-540 Slicing retention fixes by version instead of by date An appVersion field on the pagecounts write. Same schema precondition.

The precondition that would eat both silently. Mongoose discards undeclared keys without erroring. Ship the client half alone and the client gets a 200, the fields never exist, and each row's own verifyRoute reads as zero — indistinguishable from "the build never shipped". Each row carries this warning explicitly.

Two gaps from the original audit remain unfiled: no in-app experiment/flag framework, and pre-auth being fully invisible. Both were lower priority in that audit.

Critical path

[embedded content: critical path · 4 steps, 1 parallel track]

Bet 4 is the only box with code in it today. Everything between it and Timeline V1 is a decision or a schema change, not Flutter work — and the strength-ranking track below never blocks V1.

Verification gap

Bet 4 is not verified and should not be described as shipped.

What was actually checked:

What was not checked:

What closes it: one device pass in both list and grid mode. That is a requirement, not a nicety — the defect above was precisely a case where one mode worked and the other silently did not. Analyzer plus code-path tracing justifies committing; it does not justify claiming the UI effect.

Needs your call

  1. Device verification. Both commits are pushed and neither is shipped. One pass in both list and grid mode closes it. This is the only thing standing between the current state and "done".
  2. Whether the Add Someone tile ships ungated. Its copy is settled and it belongs to the beginner and developing tiers — but those tiers have no gate yet, by decision. The tile is additive and demotes nothing, so it could ship to everyone now instead of waiting. Not assumed either way.
  3. Nothing else is blocked. The maturity gating is deliberately deferred until a demonstrated-acts signal exists, and the three tier presentations below are defined so that wiring them later is not a design exercise.

Add-someone tile — agreed direction

Kept deliberately lightweight, so it reads as a natural next move inside the current surface rather than the start of another onboarding framework:

This is the only genuinely new widget in the whole plan; everything else reuses what ships today.

Tier presentations — defined, not wired

Presentation progression over one IA, not separate IA. Defined now so that wiring them later is not a design exercise; the gate waits on a real demonstrated-acts signal.

Tier What they see
Beginner Facet payoff + What Matters Now with identity context + Add Someone
Developing The same, plus a Timeline peek / what's-next entry
Mature Full Matrix / Relationships / Timeline, onboarding scaffolding largely gone