The AstroMatrix Archive

Consolidated archive/ 7 source briefings/ assembled 2026-09-12

The AstroMatrix Archive

Seven separately published briefings on the same company, written across 10–11 September 2026, merged into one indexed document. Nothing was summarised away. Where two of them contradict each other — and several do, on load-bearing questions — the contradiction is named and resolved rather than quietly averaged.

3 orientation maps 2 audits 1 strategy playbook 1 task list 10 reconciled conflicts

§A · Front matter

The seven sources

All seven were published to claude.ai within about 36 hours of each other. Three are orientation maps covering substantially the same ground, which is why §B exists.

#DocumentKindUpdatedWhat it owns
I AstroMatrix Ground Truth Orientation 09-11 The roadmap with a live status column checked against the working tree. Strongest on what is built and connected to nothing, and on decisions waiting on a call.
II AstroMatrix Orientation Orientation 09-11 The fullest of the three. Carries the measured pricing analysis, the engine correction, the verified/retracted number tables and nine standing traps. Where it disagrees with I or III, it usually wins.
III AstroMatrix Orientation Map Orientation 09-11 The shortest route in. Best on which repo holds what and the three-lane doc taxonomy. Its roadmap detail is superseded by II.
IV The AstroMatrix Playbook Strategy 09-11 Product, competitive position, pricing shape, marketing channels and the advocate base. The only document covering marketing and the moat.
V The Matrix Question Product brief 09-11 One screen, in depth: why the Matrix works, where people fall out of it, and five moves. The only document with journey-level detail.
VI What AstroMatrix Knows Audit 09-11 Code-level audit of everything the product stores or could derive about a person. The only document on the knowledge and memory layer, and it found a security hole.
VII AstroMatrix Quick Wins Task list 09-11 Everything plausibly under half a day, with the verification state of each marked. The most recent of the seven — its issue numbers run highest.
reading order If you only read part of this

§B then §C. Between them they carry every conflict and every quotable number in the set. After that, VII if you want to do something today, IV if you want the argument, VI if you want the thing nobody else looked at.

§B · Front matter

Where these documents disagree

Ten places where two or more of the seven make incompatible claims. This is the section that did not exist in any source document, and it is the reason the set was worth consolidating: each of these would otherwise be re-derived, wrongly, by whoever read the wrong doc first.

The rule applied throughout: a claim checked against source code or a live console beats a claim carried forward from another document, regardless of which document is newer or longer.

B1Is “relationship transits” an engine build or a menu change?
I · Ground Truth, and IV · Playbook say

Not an engine build. “The engine already treats composite as natal and the 3-slot orb system already covers transit-to-composite.” The Playbook calls it “three menu entries, not a rebuild.”

II · Orientation, and VII · Quick Wins say

It is a real engine change, and both supporting points above are misreadings of the source. CalcChart() has exactly two chart slots, dPos and TransitPos. applyComposite() consumes both to midpoint person 1 and person 2 into dPos — line 869 only labels the result like a natal chart. Transits to a composite need three charts at once, which the two-slot model cannot express in one call. And Orbs[] is [0]=natal, [1]=synastry/composite, [2]=transit — three orb settings for three chart types, not a transit slot for composite.

Resolved

The correction wins — it is the only version that cites engine source. Three options exist and they are not equivalent: (1) transits to the composite, what the plan implies, needing a third slot or a two-pass API — real engine work; (2) a Davison chart, the midpoint in time and space, which has a genuine date/time/location and runs through the existing engine as an ordinary natal chart with syn=2 transits — no engine change, and not implemented anywhere; (3) each partner's own transits side by side, which works today with two existing calls but answers a different question. Name which one Horizon 1.1 is before estimating it. The underlying asymmetry is real either way: the self matrix has six lenses, the relationship matrix has none.

B2The lifetime SKU — reprice by how much, or retire it?
I, III and IV say

“Reprice to 3–4× annual, or retire it.” 41–45% of purchases; the single largest structural cap on LTV; stop stacking −30% on it.

II · Orientation says, measured 09-11

Raise to $79.99. Do not retire. The last price rise already ran the experiment — lifetime went $29.99 → $49.99 in Oct 2025, and Jun–Aug year-over-year (which controls for the Nov–May slump that hit every SKU) gives units −6%, realized price +78%, revenue +68%. On the break-even switch-rate table, at $79.99 retiring can never pay against annual ×1.5 and needs 98% switching at ×2.04. Lifetime money also arrives today; annual money arrives over 2+ years conditional on a renewal depth nobody has measured per SKU.

Resolved, and it goes further

II supersedes. Raising the price is itself what settles the keep/retire question. And the genuinely mispriced SKU is annual, not lifetime: at $39.99 it is dominated on both sides — quarterly is $19.99/quarter = $79.96/year, and lifetime is $49.99, so annual is both the cheapest single year and cheaper than two years of quarterly. Quarterly outsells the new annual 480 : 126 and is displayOrder: 1, shown first. Raise annual and reorder before adding any new SKU — and do not add a fourth subscription; the ladder is already incoherent. Execution steps are in VII §A.

B3Horizon 0.5 — is the language gate still an open decision?
III · Orientation Map says

“Decide the language gate before pushing ISSUE-39. Shipping ungated permanently forecloses charging for localisation.”

II says

12b9965 is already in origin/master, not pending. That window has closed or is closing.

I and IV say

Already decided in code: ISSUE-147 pulled language off the paywall, and e6c07df5 now sends the user's language with AI report requests. Effectively free by default.

Resolved

Decided free, by default rather than by choice. Gating it now would be a withdrawal rather than an addition, which is a materially worse thing to ship. Worth confirming deliberately on paper rather than inheriting. Separately note ISSUE-146: /ai/generateDataReport — the main AI surface — is still English-only for every user regardless of setting, on both sides of the call. That is narrower than ISSUE-122 and not covered by it. See VI §04.

B4Which issue is the Terms of Use 404 — 144 or 148?
I · Ground Truth says

There is a live numbering collision: the Flutter doc's “ISSUE-144 — Terms of Use URL 404s” is the master's ISSUE-148, and the master's actual ISSUE-144 is a different issue entirely about account deletion leaving personal data in three collections.

III says

Fixed while assembling, 09-11. Renumbered to ISSUE-148 across the master and the derived docs, because ISSUE-144 is anchored in routes/user.js and in commit 1823e6e.

II still says

Its uncommitted-work table labels the Terms fix “ISSUE-144” — carrying the pre-renumber label.

Resolved

Terms of Use 404 = ISSUE-148. Account-deletion data remnants = ISSUE-144. Any doc still using 144 for the Terms fix predates the renumber.

B5How many issues are open, and what is the next free number?
The four counts given

III: 33 open / 53 in progress / 60 resolved, next free № 149, “147 issues.”  II: 36 open / 54 fixed-not-live / 65 closed, “~147 issues.”  I: “129 numbered issues, running to ISSUE-148.”  VII: ISSUE-149, 150, 151 and 152 now filed.

Not a conflict — a moving target

These were written hours apart against a register that concurrent sessions were actively editing. The highest number known to this set is ISSUE-152. The standing rule holds and is the real takeaway: re-read the master register's highest number immediately before filing a new row — a stale read causes a silent collision, which is exactly what produced B4.

B6Is the free profile limit 5 or 10?
IV · Playbook's premium table says

Free tier gets 10 saved charts, 10 saved reports, and 5 people.

IV and VII also say

The iOS store listing advertises “10 profiles free” when the real limit is 5 — and separately advertises a 6-month plan that does not exist.

III's traps say

“Any chart-count threshold above 5 is mechanical, not predictive — the free limit is 5 charts.”

Resolved — two different limits, conflated by the store copy

People: 5. Saved charts and saved reports: 10. The store listing conflates them and is wrong in the user's favour, which is the direction that generates refund requests. Fix it while in the consoles for B2 — and note the analytical consequence: because the free gate is 5 people, any conversion threshold quoted above 5 charts is an artifact of the paywall, not a discovered behavioural boundary.

B7How much finished work is not live — and where is it stuck?
I says

24 commits committed and unreleased since the 09-08 build cut. 2 files uncommitted. “The single highest-value action on this page is a version bump.”

VII confirms and numbers it

ISSUE-149. Verified three ways: git log 8583ffaf..HEAD = 24 commits, pubspec.yaml still reads 11.0.0+300100090 with no bump since the 09-08 cut, and zero store release emails in 4 days. All already pushed to origin/new-ui — nothing is lost, it is purely a cadence gap. The fixes for ~13 tracked issues are stranded, including ISSUE-129, where Android purchases hit the payment call with an empty userId: 261 Google Play orders in 30 days landing unattributed.

II and III say, of the Node repo

III: “4 commits unpushed.” II: “4 unpushed commits.” VII, latest: “2 unpushed commits on master.”

Resolved

Two different problems wearing one label. Flutter is pushed but unreleased — the fix is to cut a build, not to push. Node had unpushed commits, and the count drifted 4 → 2 as sessions pushed. The operative rule, stated in both II and VII: check git, not the docs — two separate “committed but not pushed” claims in the fire register were already in origin/master. And remember the chain: committed ≠ pushed ≠ deployed ≠ released ≠ in a build a real user has.

B8Is ISSUE-85 still top priority?
The fire register says

“TOP PRIORITY, committed but not pushed.”

II, checked against git 09-11

It is in origin/master (e90aa02). Pushed still is not deployed on the Node box — but the register's framing is stale and should not be driving the priority order.

Resolved, with a caveat that is its own action item

The code exists on the mainline; whether it is deployed on the Node box was never confirmed. That is a one-command check against restart timestamps and it should be done rather than assumed. The general rule stands: verify any “unpushed” claim in the fire docs against git before ranking it.

B9Which LTV bar applies to paid acquisition?
Three different figures circulate

$0.85 blended LTV per new account · ≥$1.78 paid-ads bar · $2.40 twelve-month value at $0.20 ARPMAU.

II is explicit about the distinction

$0.85 ($0.50 IAP + ~$0.32 ads) is “correct for what it measures — a blended average over overwhelmingly organic installs. Not the paid-ads bar.” The paid-ads bar is ≥$1.78 net per install, IAP only, measured on the acquired PRIMO10 cohort — 643 installs, 46 payments, converting at 7.15% against 1.6–1.8% blended, because acquired users clicked an astrology ad on purpose.

But II's own closing list says

“Leave the ads campaign alone until day 3 gives an honest CPI against the $0.85 bar” — using the figure it had just ruled out for exactly this purpose.

Resolved — three bars, three questions, do not cross-quote

$0.85 answers “what is a new organic account worth?” ≥$1.78 answers “what must a paid install clear?” and is the one to judge a campaign against. $2.40 is IV's twelve-month projection from ARPMAU, useful only for the order-of-magnitude comparison against a $2–4 iOS CPI range. Judging the campaign against $0.85 sets the bar roughly 2× too low. Recompute with scripts/_ads-roi.js, which re-derives it from the ledger every run.

B10Is the app too complex, or too hard to navigate?
V, IV and II all agree — independently

Of roughly 49 interface complaints, exactly one named the Matrix as too complex. About 25 said a version of “I cannot find a thing I already know exists.” Four separate confirmed cases of a live feature being reported as deleted.

II adds the nuance the others miss

“Too complex” and “too sparse” are both right: six users want more on screen, one articulate user wants less. Solve it with a density mode — never by picking a side.

Corroborated, not conflicting — listed because it is the most consequential shared finding in the set

Three documents reached this independently, which makes it the best-supported conclusion here. Do not simplify the Matrix — it is already the simplification, and removing depth answers one user while damaging twenty-five. The fix is almost always the step between two screens, not either screen. And the standing rule that prevents the next occurrence: never convert a destination into a state without leaving a signpost for one release.

↑ Back to index top

§C · Front matter

The numbers, merged

Three of the seven documents carried a partial copy of this table. Here it is once, merged, with every retraction in one place. Before quoting any level, re-derive it: node scripts/_analytics.js verify runs about 2.5 minutes against live production with no cached stats.

the standing error Why so much was retracted at once

A usage-stats sample covering 16.6% of accounts, skewed toward engaged users, was quoted as if it were fleet levels. It inflates conversion ~2.8× and undercounts volume 14–44×. Anything dated before 2026-09-07 carries that error. Crucially: relative lifts in those documents still hold — only the levels moved.

The one variable that explains the revenue

Not which features someone likes, and not how often they visit. How many birth charts their account holds. Visit frequency spans only ~2.5×, and behavioural segment membership collapses to ~1.00× — no effect at all — once charts held is controlled for. So there are not five user types with different values. There is one axis.

Ever-paid rate by number of charts held

460,694 accounts · verified against production 2026-09-07

1 chart
1.58% · 300,710
2–3
5.92% · 102,069
4–7
13.94% · 37,709
8–15
34.29% · 11,440
16+
54.24% · 8,766
whole base
5.37% · 460,694

A 34× spread, perfectly monotonic — and it points at two different jobs. The 1 → 2 chart step (1.58% → 5.92%) is the largest lever over the largest population: 300,710 accounts who have not yet done the thing that predicts paying. Separately, ~11,500 accounts hold 8+ charts and have never paid — demonstrated demand, unconverted. That second one is a conversion play, not an ARPU play; an earlier brief called the segment near-saturated, and that was the inflated number.

Segment names used across the docs: Solo (1) · Curious (2–3) · Enthusiast (4–7) · Collector (8–15) · Astrologer (16+).

Verified — safe to quote

Accounts460,694 · 5.37% ever paid · 3.73% paying now
Scale87,467 MAU (Android 43,983 / iOS 43,128) · $0.20 ARPMAU · ≈$17,195/mo, roughly $17–20K/mo with renewals · ads ≈29% of revenue · 18-minute sessions, 86.6% engagement · 4.6★ displayed on both stores
The declineAndroid active device installs 137,256 → 88,659 (Dec 2022 → Aug 2026) — about 35% over four years, steady rather than accelerating. Android-only; no verified iOS equivalent exists
Blended LTV≈$0.85 per new account ($0.50 IAP + ~$0.32 ads). A blended average over overwhelmingly organic installs. Not the paid-ads bar — see B9
Paid-ads bar≥$1.78 net per install, IAP only — PRIMO10 cohort, 643 installs / 46 payments, converting 7.15% against 1.6–1.8% blended. Before price work-through, renewals or ad revenue. Re-derive with scripts/_ads-roi.js
Store payout79.8% — not 70%
Payer value is risingavg net $17.34 → $25.10 (+44.7%) as the $49.99 and quarterly SKUs displace legacy ones
Purchase timingMedian days from first open to purchase: 0. 63% buy same-day, 82% within seven days, and 57% buy before they have even registered. Time-to-value is a revenue mechanic, not a satisfaction one
Purchase mix45% of all purchases are a one-time lifetime unlock; one SKU at $49.99 is 41% of all sales. Average realised price $34.86; the 30% discount vehicle takes lifetime as low as $34.95
Age paysA 65+ user is worth 8.8× an 18–24 user. Ages 45+ are 18.9% of accounts and 32.2% of revenue
Tarot6.26M journal entries, 4.54M carrying a typed question · ~638k completed readings/yr at 67% completion · 8.5% of free-text questions are romance · 17 visits per account — the best-retained feature
Relationships155,361 accounts (34.6%) hold another person's chart · 72.2% of multi-chart accounts have never opened the relationship screen · 93.2% of share-link arrivals bounce under 10s · adding a second chart moves reading rate 20.7% → 51.2%
Discoverabilityreports 7.8% reach and no route at all · harmonizer 2.8%, one link · store 0.2%, one link · synastry 1.5% · composite 0.3% · the Guide 1.3% · Progressed 1.3% · /chartupcoming 0.2%
Matrix screen68.8% of tracked accounts reach it — more than any screen except Home · 29.1% never return, second lowest in the app · retention is a slide not a cliff: 94% reach a 2nd visit, 78% a 5th, 41% a 20th
Activation thresholdReading one interpretation moves activity 2.7% → 17.9% — the sharpest threshold measured
Website~89–98K monthly users · 54,872 search clicks per 28 days · CTA click rate ~3.2% · 90%+ never return · zero site → app conversion tracking
Content & cost~59,700 interpretation documents across 7 languages · total AI spend $80.79/month, of which only 25% is the product · non-English users are ~14% combined, split across 29 languages
Competitor pricingThe four major subscription competitors average ~$230/year — Nebula $415, Sanctuary $240, CHANI $144, The Pattern $120. The $49.99 lifetime is 22% of that in year one and 7% over three

Retracted — do not quote these again

Wrong, and still circulatingVerified against production
15.02% ever paid5.37%
448,892 accounts460,694
Solo: 35,430 at 4.69%300,710 at 1.58%
“Tarot converts worst”False — an aggregation artifact. Within any collection size, tarot users convert better
Practitioner segment “63% converted, an ARPU play”~11,500 unconverted — a conversion play
Synastry ≈23% of chart views6.5%
“316 documents carry user text”4,544,139 stored tarot questions
Website CTA rate 0.21%~3.2%
“$585K/yr” revenue~$15.5K/mo new + renewals ≈ $20K/mo
GA4's “50% crash in H2 2024”Measurement artifact — use Play Console device counts
Chani's “42% retention / 3.1× premium”Fabricated. Never cite
“There is no Meta pixel on the site”It exists — it was firing into an orphaned pixel
Any chart-count threshold above 5Mechanical, not predictive — the free limit is 5 people
vocabulary trap profiles and users are not the same thing

profiles = accounts (531,848). users = charts and people (1.24M). They are not interchangeable and they have already been mixed up in published figures. Related: sample levels are not fleet levels, and usage of an undiscoverable feature is not a measure of demand — reports have no route, the harmonizer has one link, astrocartography's route is not registered, and 8,352 journal prompts were built and never surfaced. Low numbers on any of those mean nothing until they are reachable.

↑ Back to index top
I

AstroMatrix Ground Truth

Orientation 🏕 updated 2026-09-11 reconciled from flutter docs/, nodejs docs/, docs/product/, git log + working tree on new-ui original →

One bet, three document lanes, one roadmap. Everything scattered across those sessions is one of three lanes describing the same company from a different angle.

You are not missing a roadmap. You have one, and it is buried.

The roadmap is competitive-position-2026-09.md §7 — Horizon 0 / 1 / 2. Nothing else is a roadmap. Everything else is either evidence feeding into it, or a defect register tracking what breaks underneath it.

The bet

Relationships as structural distribution. Committed for the quarter. Can AstroMatrix generate users from users?

The constraint

Nothing can be graded. Per-user events do not exist, so no shipped fix in the register can be proven to have worked.

The drift

24 commits are unreleased. Two days of fixes sit in the repo with no version bump, in nobody's hands.

State of the code, checked against the working tree

MeasureValueNote
Mainlinenew-uiIn sync with origin. master is unused — and new-ui is 116 commits ahead of it. Do not reason about Flutter state from master.
Live on both stores11.0.0Build 300100090, released 09-09. iOS and Android on the same build.
Committed, unreleased24Commits since the build was cut on 09-08. No version bump since.
Uncommitted2 filesPaywall copy + products_config.json at 1.2.0.
Fire register129Numbered issues, running to ISSUE-148.
highest value here The single highest-value action on this page is a version bump

The aspect-grid fixes, the Matrix auto-pairing fix, the purchase-queue drain, four telemetry repairs, the AI report language fix and the app_version metric tagging are all committed and in nobody's hands. They were written on 09-10 and 09-11; the last release was cut on 09-08. Cutting a build converts two days of finished work into shipped work, and it is the prerequisite for measuring any of it.

The quarter's bet: relationships as distribution, not a feature

The diagnosis behind it: Android active installs fell 137,256 → 88,659 over four years — steady, structural, not a bad release. In that same period product work was real and effective, but no feature ever had “create a new user” as its primary job. This quarter tries the one mechanism that has never been tried.

ElementDecided
QuestionCan AstroMatrix generate users from users?
LoopAdd a partner → generate a live relationship reading (strongest connection now, current tension, what's changing, next window) → send it → recipient opens with no install required → recipient is the subject, not a bystander → they create an account to unlock their side.
AudienceState 2 — accounts holding 2+ charts who have never opened the relationship screen (72.2% of them), and Self-Explorers. Explicitly not Newcomers, who already carry too much setup burden.
Hard constraintDo not gate the first reading behind the partner installing. If the loop fails it must be because the mechanism does not work, not because users resented a gate.
The testDoes attributable acquisition from this loop exceed enough of the existing loss rate to change the net curve? Not engagement, not shares — new users who appeared because existing users brought them.
Ships alongsideThe funnel instrumentation. Named as a prerequisite, not a follow-on.

Explicitly deprioritised for the quarter — not for lack of value, but because running them in parallel makes the one question unanswerable: more chart types · more generic interpretations · broad Ask-AstroMatrix development · journalling expansion · meditation/harmoniser expansion · a generic social feed · a large UI redesign · extensive ASO iteration · growth-content campaigns · offline/local calculation.

The roadmap, with what has actually moved

Horizon 0 — this month, no new systems

Entirely additive or price-side. Carries no grandfathering exposure. There is no case for scoping a new paywall limit until 0.1–0.4 have shipped and been measured — until then nobody knows what the product converts at when its entrance is findable and its paywall describes the real product.

#ActionStatusWhere it stands
0.1Replace the store's plan copyUnreleasedCommitted a16c5d50. The “50GB storage / 24-7 support / API access” copy was also found to be dead code that never rendered — belt and braces.
0.2Fix the lifetime SKUYour callUntouched. 41% of purchases and the single largest structural cap on LTV. superseded — see B2
0.3Delete the false upgrade bulletsIn working treeTwo removed earlier; ISSUE-147 removed two more (“Every chart type”, “Reports in your language”) after tracing every gate and finding neither is gated anywhere. Paid plans now show three bullets.
0.4Link the store and reportsOpenThe highest-value unstarted item in Horizon 0. The /premium dead-end behind all 12 gates was fixed 09-07, but the store still has one inbound link in the whole app (0.2% reach) and reports have no route at all — modal-only inside 6 screens, 7.8% reach, plateaued after launch. ISSUE-76.
0.5Decide the language gateDecided in codeSettled by default: ISSUE-147 pulled language off the paywall and e6c07df5 now sends the user's language with AI report requests. Worth confirming on paper — and note ISSUE-146, where the Matrix AI report is still English-only for everyone.

Horizon 1 — the quarter, relationships and time-to-value

1.1–1.3 are the core bet — make the relationship layer timed, legible and not only romantic. Everything else in this horizon distributes it.

#ActionStatusWhy it's on the list
1.1Relationship transits — “what's happening between you two this week”Not startedThe angle nobody else can match. Turns a one-shot verdict into a daily reason to return. this doc's “not an engine build” claim is wrong — see B1
1.2A one-word verdict on every pairNot startedWe compute more and conclude less. A dashboard cannot be retold; a single word gets screenshotted.
1.3Relationship types — friend, family, colleague, partnerNot started9 of the 12 facets are already relationship-neutral. The astrology is non-romantic already; only the packaging is romantic.
1.4Invite-from-chart flowNot started155,361 accounts already hold another person's chart. The highest-ROI person-to-person moment in the product, and our largest dormant asset.
1.5Shareable pair card — “Us”, not “me”Not startedThe competitors' actual unit of growth. We share only self-charts today.
1.6Fix the cold-arrival landingNot started93.2% of share-link visitors to relationshipfacets bounce in under 10 seconds. Do this before 1.5 sends more traffic at it.
1.7Public-figures databaseNot startedThe famous fields exist with zero rows and the isFamous param is read but unused. Cheapest viral surface in the category — a content job, not engineering.
1.8Promote the synastry wheelNot startedIt sits sixth in the chart dropdown, below Progressed. A practitioner chart outranks the one chart a normal person came for.
1.9Surface comparisons to the 72.2% who never make oneNot started1 → 2 charts moves conversion 1.58% → 5.92%. Needs pre-filtering and a cap: O(n²), 79,800 pairs at 400 charts.
1.10Resolve MessagesScreen — foundation or deleteNot startedDon't build a second messaging surface beside an unreachable one. ISSUE-47.
1.11Contextual reading button on the relationship surfaceNot startedThe cheapest link in the app. Pastes both names in as the tarot question — which is the question users already type by hand.
1.12Refresh the video libraryNot startedOwned channel, stale content. Production not engineering — and it cheaply tests whether presented content lands before committing to an audio hire.
1.13Per-user event measurementHalf shippedBlocks all pricing work. The cheap half shipped 09-11 (fcd34d34 — app_version on every metric at the single choke point). The expensive half is real design work. ISSUE-77 / ISSUE-142.

Horizon 2 — the year, new models

#ActionStatusNote
2.1The Coach / Oracle session layerSpeccedFull spec written across three docs, nothing built. The answer to the only real competitive weakness. Total AI spend today is $80.79/month, of which only 25% is the product — real headroom.
2.2The Oracle as a shareable weekly cardSpeccedTurns the Coach into the social object the product currently lacks.
2.3Practitioner marketplaceConceptPower users take paid consultations, we take a cut. Built on 4,011 Astrologers at 54% conversion plus the P2P substrate. The largest revenue model in the category, and the only one competitors cannot replicate.
2.4AudioGatedThe stack is already shipped; the content needs a hire. Do not schedule until 1.7 has told us whether presented content lands at all.
sequencing The one rule

Fix the revenue shape and ship additive value before subtracting anything. The product is already perceived as harder to use than a cheaper competitor, and the internal rating moved 3.78 → 3.44 on a change that added something. Adding limits to that product risks making the limit, rather than the packaging, the reason to leave.

Built, working, and connected to nothing

Repeatedly, strategy passes proposed things that turned out to already exist. These are code-verified as present and unreachable — the common shape is that the computation exists and the distribution does not.

AssetVerified stateMissing piece
Universal sky-event engineVoid-of-Course, Out-of-Bounds and moon phase are computed with no chart, no location and no user — and a batch generator already writes 4 years of them to JSON. The live API returns post-ready sentences today.Any publishing or broadcast layer. Nothing reads the generated files.
Event-triggered broadcast pushThe client receiver is fully wired on a MoonPhases topic channel.The sender. Absent from all three repos.
Big Three rarity~165k charts with stored Sun/Moon/Ascendant including house.Any feature that uses it.
Astrocartography894 lines, substantially complete — and advertised on the website as shipped.One timezone bug misplacing lines 100+ km, plus un-gating the flag.
The onboarding answerStep 2 asks “what do you need answers about?”, requires an answer to advance, and discards it in the same frame — never persisted, not even as an analytics label, since it shipped in Dec 2025.One field. Roughly a day's work, on a self-declared life priority collected from 100% of new users at peak intent.
A behavioural storeusers.stats accumulates per-screen visit counts and dwell times for every user, syncs to Mongo, and survives reinstall.Nothing has ever read it. No surface, no report, no AI prompt.
Three native home-screen widgetsMoon Phase, Sabian Symbol and Planetary Hours — built twice, once for each platform.Unknown whether they are promoted anywhere. Their Android refresh was also broken for months by the install-referrer bug.

Decisions nobody else can make

Each has the analysis finished and is waiting on a call, not on engineering.

  1. Cut a build ships 24 commits

    Two days of finished fixes, including the instrumentation that makes every later question answerable, sitting unreleased behind an unchanged version number.

  2. The lifetime SKU — reprice or retire Horizon 0.2

    41% of purchases and the largest structural cap on lifetime value. No existing user loses anything either way. See B2 — the measured answer is $79.99, do not retire.

  3. The ISSUE-61 remediation rollout 48,576 accounts

    Birth locations silently mismatched from their town labels. The id-based fix is live and stops new profiles hitting it, but the rollout — auto-correct 39,839 high-confidence records, ask the other 8,737 to re-enter — was designed and never started. The largest data-integrity exposure on the register by account count, frozen until someone says go.

  4. The paywall's fourth bullet ISSUE-147

    Removing the two ungated claims leaves paid plans showing three bullets instead of five. Nothing was invented to fill the gap. Whether a fourth gets added is a copy decision, owned by positioning-and-paywall-copy.md.

  5. The Matrix report size gate ISSUE-136

    The Summary + All Aspects report is gated as an oversized payload, but the gated path allows 50MB against an estimated ~1MB report. The 100kb limit that is real belongs to a route that button never calls. Needs the original dev to say whether it was ever measured — otherwise re-justify it as a render-memory gate and move it to the PDF path.

  6. Confirm the language decision on paper Horizon 0.5

    Already made in code. That forecloses charging for localisation, which is a real strategic choice worth making deliberately rather than inheriting.

The tracking system itself has drifted

Part of why this feels scattered is that the doc meant to prevent scattering is out of date. Verified against both files:

  • The Flutter fire doc is missing real, open, Flutter-owned issues — 91, 94, 104, 111, 138, 142 and 146 are all in the master register and absent from the derived view. Its own banner flagged four of them on 09-10 and they are still missing.
  • There is a numbering collision — see B4.
  • It is being hand-patched against its own stated rule that it must be regenerated rather than edited — which is how both problems above arose.
  • The two biggest absentees are not small. ISSUE-138: the 2,921-test suite never runs anywhere, there is no CI test or analyse step, master deploys straight to production ungated, and the suite is currently red with 82 failures. ISSUE-142: release attribution — whose absence is why no fix in the register can be proven to have worked.

The fix is a regeneration from the master register, not another patch. Until that happens, check the master's index before concluding any Flutter issue is not tracked.

↑ Back to index top
II

AstroMatrix Orientation

Orientation 🧭 updated 2026-09-11 5 repos · 3 doc trees · source of truth docs/ROADMAP.md original →

The fullest of the three orientation documents, and the one that does the most correcting. It collates and reconciles the scattered docs, introduces no new findings, and points every claim at the doc that owns it.

The company, in one paragraph

AstroMatrix is a profitable, deeply-built astrology product — roughly $17–20K/month, 87,467 MAU, 4.6★ — whose Android install base has declined about 35% over four years, steadily. Three years of real product depth work were effective at what they targeted, but no feature ever had user-creation as its explicit job.

Separately, the loyal base that remains is badly monetised (5.37% ever paid, $0.20 ARPMAU) — largely because the paths to pay were structurally broken, not because demand is absent. Those are two distinct problems: a growth-engine failure and a packaging failure. They have separate fixes and should not be collapsed into one narrative.

The single company question this quarter: can AstroMatrix generate users from users?

The five lanes

There is no single project here. There are five parallel lanes that each acquired their own tracker — which is the actual source of the “it's all over the place” feeling.

LaneWhere it livesIts trackerState
A · Product & growth strategyflutter/docs/, nodejs/docs/product/FEATURE-LIST.mdconverged
B · Engineering firesnodejs/docs/SUPPORT-fire-*master fire report~147 issues
C · Website & SEOastromatrix-public/memory: SEO auditaudit done, queue open
D · Paid ads & economicsastromatrix-public/docs/SESSION-HANDOFFday-3 read pending
E · Infra, DR & migrationnodejs/docs/INFRA-*, MIGRATION-*on a 3–6 mo clock
36issues open
54fixed, not yet live
65closed
how the lanes relate

Lanes A and B are the same product at two altitudes. A fire-report ISSUE number is the engineering half of most roadmap items — roadmap “link the store” is ISSUE-76. C and D are the acquisition side and barely touch A/B. E is a clock: the legacy .NET database goes offline in 3–6 months and the tarot migration is running right now.

Four documents read like roadmaps — they are one plan at four altitudes

DocumentWhat it actually is
q4-growth-plan-2026-09.mdThe committed bet. One question, one mechanism, one scoreboard.
competitive-position §7The full sequence (Horizon 0/1/2). H1.1–1.6 is the Q4 bet, decomposed.
FEATURE-LIST.mdThe ranked forward list. Collates both repos, flags the numbers that changed.
STRATEGY-brief §5The revenue-unblocking subset — effectively Horizon 0, stated separately.

Read in that order and nothing conflicts. Use FEATURE-LIST as the working list and competitive-position §7 as the sequence.

Pricing, measured — this supersedes “reprice 3–4× or retire”

The last price rise already ran the experiment. Lifetime went $29.99 → $49.99 in Oct 2025. Same month year-over-year, which controls for the Nov–May slump that hit every SKU:

Jun–Augunitsrealized pricerevenue
2025637$27.24$17,355
2026598$48.55$29,062
change−6%+78%+68%

Keep vs retire is settled by arithmetic, not elasticity. Retiring only pays if enough lifetime buyers switch to annual. Break-even switch rate = lifetime net ÷ annual net over its life (annual $39.99 × renewal depth × 0.798 payout):

lifetime priceannual ×1.5×2.04×3.0×4.0
$49.9983%61%42%31%
$59.99never74%50%38%
$79.99never98%67%50%
$99.99nevernever83%63%

The only direct evidence: the +78% rise moved 13% of lifetime-inclined buyers elsewhere — a lower bound, since a price rise is a smaller shock than removal. Raising the price is what settles the keep/retire question — at $79.99, retiring can never pay. Lifetime money also arrives today; annual money arrives over 2+ years, conditional on a renewal depth nobody has measured per SKU.

the real mispricing Annual, not lifetime

At $39.99 annual is dominated on both sides: quarterly is $19.99/quarter = $79.96/year, and lifetime is $49.99. Annual is both the cheapest single year and cheaper than two years of quarterly. Quarterly outsells the new annual 480 : 126 — and quarterly is displayOrder: 1, shown first. Raise annual and reorder before adding any new SKU. Do not add a fourth subscription — the ladder is incoherent and a new rung makes it worse.

Execution: price fields only, three consoles, two traps

Verified: products_config.json carries no prices; there are no hardcoded prices in any .dart/.ts/.tsx; and the 30% discount works by swapping to a separate product id, not a coupon. So changing two price fields is sufficient.

#Consolefull_purchase2025discount_full_purchase2025
1Google Play$49.99 → $79.99→ $55.99
2App Store Connect$49.99 → $79.99→ $55.99
3Stripe (web — easily missed)$49.99 → $79.99$34.95 → $55.99
trap 1 A Stripe Price amount cannot be edited

You make a new Price and repoint the link. /payments/get lists every active link with no dedupe by shortcode, so leaving the old one active shows two lifetime products at two prices. Deactivate it in the same change.

trap 2 The analysis tooling goes quietly wrong

_payments.js's usdPriceByType() medians price across all history per SKU. After this, full_purchase2025 holds both $49.99 and $79.99 and its median drifts for months — every per-SKU revenue figure stays plausible and becomes wrong. Patch it to bucket by (SKU, month) before changing prices.

for Mark Decide what the discounted price really is

Every website CTA now routes through applyDiscount?code=WEBPROMO1, which serves the discount SKU — so web-acquired buyers pay $55.99, not $79.99. That is +12%, not +60%. Today that path is tiny (21 of 1,551 purchases), but the CTA fix was built to grow it. $55.99 is the price most new web users will actually see — choose it deliberately.

why 0.4 matters more than it looks

Every conversion baseline measured before 2026-09-07 was measured against a funnel whose exit did not exist — all 12 upgrade gates dead-ended on an unregistered /premium route. Do not scope pricing against those numbers.

The engine correction — relationship transits are not free

Both FEATURE-LIST §8b.1 and competitive-position 1.1 claim the engine already supports this — “it treats the composite as a natal chart” and “its orb system has a transit slot for synastry/composite.” Both supporting points are misreadings. Verified in the engine source:

  • CalcChart() has exactly two chart slots — dPos and TransitPos. A chart is natal (syn=0), synastry (syn=1), or transit (syn=2).
  • applyComposite() consumes both slots to build the composite — it midpoints person 1 and person 2 into dPos. Line 869 only labels the result like a natal chart.
  • Transits to a composite need three charts at once — person 1, person 2, and the sky now. The two-slot model cannot express that in one call.
  • Orbs[] is [0]=natal, [1]=synastry/composite, [2]=transit — three orb settings for three chart types, not a transit slot for composite.

Three options, not equivalent. (1) Transits to the composite — what the plan implies; needs a third slot or a two-pass API. Real engine work. (2) Davison chart — the midpoint in time and space, so it has a genuine date/time/location and runs through the existing engine as an ordinary natal chart with syn=2 transits, no engine change. Not implemented anywhere. (3) Each partner's own transits side by side — works today with two existing calls, but answers a different question.

Name which one 1.1 is before estimating it. The asymmetry itself is real: the self matrix has six lenses, the relationship matrix has none.

prerequisite, not follow-on

The Q4 plan says instrumentation ships alongside, explicitly — because shipping the loop without it reproduces the exact failure the whole strategy diagnosed: real work shipped with no way to know if it moved anything.

The one thing blocking everything

Per-user event measurement does not exist — ISSUE-77, ISSUE-142. Metrics go to Prometheus, an aggregate time-series store. A uid label across 460,694 accounts is a cardinality explosion, not a one-liner. This was mis-priced as trivial and it is design work — a uid-keyed event collection that does not exist yet.

What it blocks: grading the Q4 bet · every gating, capping and pricing question · per-session funnels · experiment assignment.

shipped 09-11 The cheap half is in

app_version and platform now tag every metric at the single choke point every metric passes through. So “did release X improve anything?” is now answerable. “Did this session go A → B?” is not, and cannot be without an event store. That is the honest boundary.

Live state — verified against git, not against a prior summary

The fire docs' deploy-state claims lag reality in both directions.

already pushed ISSUE-85 — a security fix

The fire doc ranks this “TOP PRIORITY, committed but not pushed.” It is in origin/master (e90aa02). Pushed still is not deployed on the Node box — but the doc's framing is stale and should not drive the priority order.

window closing The AI-language fix is also already pushed

12b9965 is in origin/master, not pending. FEATURE-LIST §C says to decide the language gate “before this is pushed” — that window has closed or is closing.

needs an answer The legacy .NET fixes were reverted, not shipped

In the legacy astromatrix repo, local master is 8 ahead / 2 behind, and four of those commits are reverts. The ISSUE-106 GDPR tarot-deletion fix, the ISSUE-107 fix and the ISSUE-82 Sabian fix were each committed and then reverted.

Verified: RemoveAllData in Website/API/UserController.cs does not touch TarotReadingJournals today. The docs describe these as “fixed, committed, not pushed.” They are not in the working tree and not pushed. Whether the reverts were deliberate needs an answer before anything is re-applied — and the legacy database sunset makes it a dated question.

Uncommitted at time of writing

RepoFilesWhat it is
astromatrix-publicapp/home/terms/
Footer.tsx
style.css
ISSUE-148 (labelled 144 here — see B4) — the Terms URL printed in every store description 404s. Page restored, Footer link added. Blocks an ASO submission (Apple 3.1.2). The restored text has no auto-renewal clause — a lawyer's call, not an audit's.
astromatrix-flutter new-uiproducts_config.json
gated_content_widget.dart
ISSUE-147 / Horizon 0.1 — the false paywall bullets, removed.
astromatrix-nodejsdoc edits
+ 4 unpushed commits
ISSUE-143/144 fixes and a navigation-architecture UX audit.
  • Branch note: the shipping Flutter branch is new-ui, 116 commits ahead of master. Don't reason about Flutter state from master.
  • Website deploys work again. Push to astromatrix-public master → Gitea Actions → live. Run npm run build locally first and check git log origin/master..HEAD, because the server takes whatever is on origin/master. The “no auto-deploy” note in older docs is stale.
  • Concurrent sessions are editing these docs. docs/README.md changed on disk mid-session. Re-read before editing anything under astromatrix-nodejs/docs/.

The doc map

DocOwnsTrust
FINDINGS-2026-09-11.mdVerified fleet numbers and the retraction listread first
product/FEATURE-LIST.mdThe forward list — what to build nextworking list
product/README.mdIndex for the product-design lanecurrent
docs/README.mdIndex for the support / fire / migration lanecurrent
q4-growth-plan-2026-09.mdThe committed quarterly betcurrent
competitive-position-2026-09.mdMarket position, Horizon 0/1/2, the AI-era answer, Memory as the fourth pillarnewest strategy
strategy-reference-2026-09.mdRanked strategy map, visibility map, turnaround research, what NOT to dolevels predate 09-07
built-but-disconnected-2026-09.mdFour assets built and unshipped: sky events, broadcast push, Big Three rarity, astrocartographycode-verified
acquisition-channels-2026-09.mdCreator seeding, PR, store editorial, the paid-UA mathno first-party data
STRATEGY-brief-2026-09-07.mdProduct-consequence view of the active firescurrent
SUPPORT-fire-manager-reportMaster bug tracker — all ~147 numbered ISSUEsauthoritative
SUPPORT-fire-FLUTTER / NODE / PROCESSDerived per-area dev specsderived; FLUTTER self-flags stale
SUPPORT-ux-experience-issues.mdNon-technical UX complaints, counted by headcountcurrent
product/five-user-modes.mdMode briefing pack, code-verifiedlevels superseded
product/app-map-and-changes.mdVerified app map — check here before claiming a screen is unreachablecurrent
user-knowledge-audit-2026-09.mdWhat the product knows about a user; the proposed knowledge modelnew, untracked in git
INFRA-resilience-roadmap.mdDR / failover phases, open security itemscurrent
MIGRATION-*.mdLegacy .NET → Node port3–6 month clock
SESSION-HANDOFF-2026-09-11.mdAds, revenue economics, the website funnelread before the test plan
paid-ads-test-plan-2026-09-09.mdAds working doc4 generations of economics, 3 wrong

Nine standing traps

Things that keep getting re-derived wrongly. Each one has cost a session already.

  1. Don't propose a feature without checking whether it already exists. Event-triggered push, UGC/community, rewarded ads, the Guide deep-link and the in-chart South Node were each proposed as new work and each already shipped. Two of two “Bet”-tier items in one doc already existed.

  2. Usage of an undiscoverable state is not a measure of demand. /chartupcoming at 0.2% and Progressed at 1.3% are evidence of no route, not no demand.

  3. Never convert a destination into a state without leaving a signpost for one release. This has produced four confirmed “you deleted it” reports for features that still ship. ~25 of ~49 UI complaints are “I can't find things”; one named complexity.

  4. “Too complex” and “too sparse” are both right. Six users want more on screen; one articulate user wants less. Solve it with a density mode — never by picking a side.

  5. Never quote a truncated list as complete. Print a count, reconcile it, state N of N. Paginated Meta reads return partial data silently under rate limiting.

  6. Verify writes by re-reading state — not by an exit code or a chained echo.

  7. profiles = accounts (531,848). users = charts/people (1.24M). Not interchangeable, and they have been mixed up in published figures.

  8. Pausing a Meta campaign does not pause its ads. Audit status, never effective_status.

  9. Committed ≠ pushed ≠ deployed ≠ released. For Flutter, add ≠ in a build a real user has.

The twelve-month concentration — four systems, not twenty features

Matrix

The first-level answer everywhere. Raw astrology becomes evidence, not interface.

Relationships

Persistent people, not synastry inputs.

Timeline

The only one of the four with no roadmap entry anywhere.

Memory

~4.5M user-written questions we already hold. The pillar that cannot be bought.

AI sits across these — it is not one of them.

A fifth thing not to postpone: surfacing. The product is already large. The next win is making users realise what they already have.

So: what now?

  1. Horizon 0.4 — link the store, give reports a route. Small, verified, and everything downstream is unmeasurable without it.

  2. Decide the lifetime SKU (0.2) and the language gate (0.5). Both are decisions rather than builds, and both are load-bearing.

  3. Scope the event store properly. It gates grading the quarter, and it is not the one-liner it was priced as.

  4. Ship Horizon 1.1 — relationship transits. It is the prerequisite half of the committed bet that the Q4 plan assumed already existed.

  5. Leave the ads campaign alone until day 3 gives an honest CPI. judge it against $1.78, not $0.85 — see B9

  6. Resolve the legacy .NET reverts before the database sunset makes it urgent.

↑ Back to index top
III

AstroMatrix Orientation Map

Orientation 🧭 updated 2026-09-11 4 repos · 3 lanes · 147 issues original →

The shortest route in. Nothing here is new information — it is the existing docs, arranged. The confusion has one cause: three separate tracking systems run in parallel, each with its own source of truth, and the roadmap lives in a fourth place that is not called a roadmap.

The three lanes

Every doc in the project belongs to exactly one of these. They are deliberately separate — a technical defect, a thing to build, and a customer who did not get an answer are different jobs with different owners. Mixing them is what makes the folder look chaotic.

Lane 1 · Fires

Technical defects

“What's broken, and has it actually been fixed?”

  • Source of truth: docs/SUPPORT-fire-manager-report-2026-08-26.md — 147 numbered issues, index table at the top, detail sections below.
  • Derived — never hand-edit: SUPPORT-fire-NODE.md, -FLUTTER.md, -PROCESS.md. Regenerated from the master.
  • How to work it: SUPPORT-fire-manager-PROCEDURE.md

Lane 2 · Product

What to build next

“What should we do, in what order, and why that order?”

  • The forward list: docs/product/FEATURE-LIST.md — ranked items plus every direct user request, weighted by repeat count.
  • The actual roadmap: docs/product/competitive-position-2026-09.md §7 — the 3-horizon plan. This is the roadmap; it just isn't named like one.
  • Index: docs/product/README.md

Lane 3 · Support

The inbox

“Did we drop a customer, and what are they telling us?”

  • Queue & volume: docs/SUPPORT-status-report.md — updated in place, never a new file per session.
  • Non-technical complaints: docs/SUPPORT-ux-experience-issues.md — navigation, moved features, tone. Deliberately separate from bugs.
  • How to work it: SUPPORT-manager-procedure.md

Two more workstreams that are none of the above

WorkstreamWhat it isWhere
Legacy migrationPorting the .NET API onto Node. A real, active workstream that was missing from the docs index entirely until 09-11.docs/MIGRATION-*.md — 6 docs
Infra & disaster recoveryWindows/Ubuntu failover phases, incident history, open security items.docs/INFRA-resilience-roadmap.md
The numbers baselineCross-cutting, and the one to read before quoting any figure. Part 1 is a list of numbers that were previously wrong and are still repeated elsewhere.docs/FINDINGS-2026-09-11.md

Which repo holds what

The product lane spans two repositories, which is the second-biggest source of “I can't find it”. Strategy docs live in the Flutter repo; feature and competitive docs live in the Node repo.

RepoHoldsState at time of writing
astromatrix-nodejsBackend. All fire, support, product, migration and infra docs.4 commits unpushed
astromatrix-flutterThe app. The strategy layer: q4-growth-plan, strategy-reference, built-but-disconnected, acquisition-channels, product-strategy, user-knowledge-audit3 files uncommitted — two are Horizon 0 work
astromatrix-publicThe website. Store/legal pages.5 files uncommitted, incl. the Terms fix
astromatrix-engineGo calculation engine.Clean
astromatrixLegacy .NET. Only edit when Node genuinely can't do the fix.Being migrated away from

State of the board

33Open — not started. Includes chart-accuracy reports and a security item.
53In progress / partial. Several are “fixed, committed, not pushed” — done in the tree, not live.
60Resolved, plus one waiting on an external reply (ISSUE-4).
149Next free issue № — re-check immediately before filing; concurrent sessions move it.

see B5 These counts are a snapshot; the highest number known across the whole set is ISSUE-152.

Work that exists but isn't live

This is the gap most worth closing, because several items are already written. Four commits sit unpushed in astromatrix-nodejs — including the ISSUE-143 tarot recovery (31,507 rows, 8,866 users unblocked) and the ISSUE-144 account-deletion data purge, both compliance-relevant. The Flutter tree holds uncommitted edits to products_config.json and gated_content_widget.dart — those are Horizon 0.1 and 0.3. The website tree holds the Terms of Use fix (ISSUE-148), which gates the pending store-metadata submission.

Pushing auto-deploys and restarts production here, so these are decisions, not chores.

sequencing The one rule

Fix the revenue shape and ship additive value before subtracting anything. There is no case for scoping a new limit until 0.1–0.4 have shipped and been measured — until then we don't know what this product converts at when its entrance is findable and its paywall describes the actual product. The store rating already moved ~3.78 → ~3.44 on a change that added something.

Five traps — things the docs still get wrong

These are the reasons two documents can disagree and both look authoritative.

  1. Everything in docs/analytics/ is pre-correction

    Those files still quote conversion inflated ~2.8× and volumes understated 14–44×, plus a retracted “tarot converts worst” framing. five-user-modes.md was corrected; the analytics files were not. FINDINGS-2026-09-11.md Part 1 lists every number to un-believe.

  2. Sample levels are not fleet levels

    The usage-stats sample covers 16.6% of accounts and skews engaged. Use it to compare segments; never quote a level from it. node scripts/_analytics.js verify re-derives the headline numbers from production in ~2.5 minutes.

  3. The reach percentages are due a re-pull

    Reports 7.8%, store 0.2%, harmonizer 2.8% — all quoted throughout the FEATURE-LIST, and all exactly the kind of level that moved. The ISSUE-77 instrumentation fix shipped on both platforms 2026-09-09, so a clean post-09-09 measurement is now possible and has not been taken.

  4. Per-user measurement is mispriced as trivial

    It is named as the blocker for most of the monetisation work, and the original “one-liner” estimate was wrong. sendCounter writes to Prometheus — aggregate-only. A uid label across 460,694 accounts is a cardinality explosion. This is an event-store design task.

  5. Usage of a hidden feature is not a measure of demand

    Reports have no route; the harmonizer has one link; astrocartography's route isn't registered; 8,352 journal prompts were built and never surfaced. Low numbers on any of these mean nothing until they're reachable.

Where to start — the reading order

  1. FINDINGS-2026-09-11.md

    Twenty minutes. The verified baseline and the list of retracted numbers. Everything else assumes it.

  2. competitive-position-2026-09.md §7

    The roadmap itself — the three horizons, with the reasoning attached to each item.

  3. FEATURE-LIST.md

    The ranked list and, in the second half, every direct user request with its repeat count. This is where a new ask gets filed.

  4. The fire report's index table

    Just the table at the top — 147 rows with a status each. Skip the detail sections unless a specific issue matters.

  5. docs/README.md and docs/product/README.md

    The two folder indexes. Both were stale and were brought current on 09-11 — every file on disk now appears in one of them.

fixed while assembling, 09-11

Two different issues had both been filed as ISSUE-144 — the account-deletion data remnants, and the 404ing Terms of Use URL. The second was renumbered to ISSUE-148 across the master and derived docs, since ISSUE-144 is anchored in routes/user.js and in commit 1823e6e. The two folder indexes were also missing 12 files between them — FINDINGS, both role-procedure docs, the entire 6-doc MIGRATION family, and the three product docs written that day. All now listed.

Not covered here: this is a map, not a review. It takes each doc's own claims at face value except where a claim was already contradicted by another doc in the set.

↑ Back to index top
IV

The AstroMatrix Playbook

Strategy updated 2026-09-11 product · features · growth — no engineering original →

What the product actually is, what it has that nobody else does, what it's missing, how it makes money, and the four places new users could come from.

The sentence that isn't anywhere in the product

Practitioner-grade astrology in a consumer app — the charts the serious tools have, the packaging the popular ones have, for one payment instead of every year.

appears in no store screen · no upgrade dialog · no store listing · no web page

The four major subscription competitors average ~$230/year — Nebula $415, Sanctuary $240, CHANI $144, The Pattern $120. The $49.99 lifetime is 22% of that in year one and 7% over three; the $39.99 annual is 17%. “More than the competition in several areas, at under a fifth of the price” is literally true on both SKUs, and it is said nowhere. This is the largest unexploited marketing asset in the business, and it is free to use.

copy rules Three that go with it

Name the capability gap, never the competitor. “Includes synastry and composite charts” is defensible and matches what competitors publish about themselves. “Better than CHANI” is not.

Never claim “no AI” or “written by humans” — position on specificity instead: your chart, not your sign, which is true, checkable, and attacks both leading competitors at once.

Use the price shape, not the price — “one payment, not every year” ages well; printed competitor prices don't.

Buying is a day-zero impulse

reprioritises the whole list

Median days from first open to purchase: 0. 63% buy same-day, 82% within seven days, and 57% buy before they have even registered. Time-to-value is therefore a revenue mechanic, not a satisfaction one — and anything sold on accumulated value (a content library, a subscription coach, a relationship history) is fighting observed behaviour until the first session is fixed.

The two opportunities that fall out of the charts-held table (see §C) are different jobs. The near one — 11,500 accounts holding 8+ charts who never paid: they already exhibit the strongest purchase predictor in the product and did not convert, so this is a conversion job — packaging, a reason, a findable way to pay. The far one — 300,710 accounts holding exactly one chart: all the headroom is here, but the question isn't “how do we sell to them”, it's what makes a second chart worth adding.

What we have that they don't, and what they have that we don't

Verified against the competitors' own published material. Composite charts appear in the practitioner tools and in none of Co–Star, The Pattern, CHANI, Sanctuary or Nebula.

The moat

Ours alone

  • Real synastry and composite. No mass-market app has a composite chart. CHANI has no compatibility feature at all.
  • Chart-specific, not sign-generic. CHANI ships one reading per rising sign, shared by thousands. Ours is computed from the actual chart.
  • 29 bodies — Chiron, Eros, Psyche, Vertex, Part of Fortune, Eris, all four nodes. The consumer set stops at ten planets.
  • Seven languages of interpretation content, ~59,700 documents. Every major competitor is English-first.
  • Tarot integrated with the chart. Nobody in the astrology set has it — and it's our best-retained feature: 17 visits per account.
  • Relocation, solar and lunar returns, progressed, draconic, astrocartography. Practitioner-tier, absent from consumer apps.
  • One payment, not every year. Every major competitor is subscription-only.
  • Relationship transits — not built. this doc says the engine supports it; it does not — see B1

The gap

Theirs, not ours

  • A one-line verdict on a pair. The Pattern says “Soulmate” or “Complex”. We return four sliders — richer, and nobody can repeat it. The single word is what gets screenshotted.
  • A friend/partner graph with daily updates. A second person is the reason to open the app. We have the charts, no graph, no daily pair state.
  • A public-figures database. Free viral surface — try it on a celebrity. Our fields exist with zero rows.
  • Audio — meditations, sleep stories. Can't be screenshotted, justifies recurring payment. Our full audio stack is shipped and serves only the Harmonizer. Needs an astrologer hire, not engineering.
  • A guided beginner course. The Pattern has Astrology 101. Our Guide is a reference, not a path — 1.3% reach.
  • A live human astrologer. The biggest revenue model in the category. We have none — but we have the practitioners.
  • Journal prompts tied to transits. Turns a blank box into a reason to write. Ours is an unprompted shelf.
  • Non-romantic relationship types. Nine of our twelve facets already work for a colleague or a parent. Packaging only.

The complexity complaint is not a complexity problem

Of ~49 interface complaints, one named complexity. ~25 said some version of “I can't find things.” The app is legible at the top of every screen and expert one level down — which is a much smaller problem than “the app is too complex”, and it means the fix is almost always the step between, not the screen. Three places that step is missing:

  • The home tiles. Moon House, Astro House and Planetary Hour are three of the seven tiles on the first screen a new user sees, and they're the first thing that says “this isn't for you.” Translate them to consequence, or demote them.
  • Between the slider and the aspects. The summary says Communication: +4; one tap down is “Mercury square Saturn”. Nothing bridges them.
  • The chart-type names. “Draconic”, “Progressed”, “Composite” are offered with no one-line explanation of what question each one answers.

The loop, and the scoping rules that are easy to get wrong

155,361accounts already hold another person's chart — the dormant asset
72.2%of multi-chart accounts have never opened the relationship screen
2.5×lift in reading rate once someone touches add-person (51.2% vs 20.7%)
93.2%of share-link arrivals bounce in under ten seconds

Someone adds a partner → the app generates a live relationship reading, not a static score → they send it → the partner opens it with no install required → the partner sees content about themselves and the relationship they're in, not someone else's content → they create an account to unlock their own side → the pair is now live, and both have an ongoing reason to return.

the MCP, concretely What the minimum compelling product actually says

You + Alex — strongest connection right now · current tension · what's changing · next important relationship window. Alex can see their side →

Not “here is your compatibility score.” And note: three of those four lines are relationship timing, which does not exist today. The static half — synastry, composite, the Matrix, the wheel, sharing — is all built. The timing half is the actual work.

  • Aim it at people with 2+ charts who've never opened the relationship screen, and at Self-Explorers. Not Newcomers — half of solo accounts are Newcomers already holding 5.2 charts, for whom “add someone” is a bigger, riskier ask than “open a reading”.
  • Do not gate the first reading behind the partner installing. The first user gets full value alone; the partner joining unlocks genuinely new shared state.
  • Fix the cold-arrival landing before sending more traffic at it. Inbound relationship demand exists today and is being wasted.
  • Cap the pair maths. 120 pairs at 16 charts, 79,800 at 400. Any “your notable relationships” feature needs pre-filtering.

The test — and it is a hard one on purpose. Not “people loved it.” Not “relationship engagement rose.” Not “shares increased.” Did attributable acquisition from this loop exceed enough of the existing user-loss rate to change the net growth curve? If it fails after a properly instrumented quarter, that's a real answer too. The only bad outcome is running it too loosely to tell the difference.

Premium is five annoyance-removals and one real capability

FreePremiumShape
Ads, interstitial and rewardedNo adsAnnoyance removed
Reading gated every 10 → 7 → 5 views, tightening with useNever gatedAnnoyance removed
10 saved chartsUnlimitedLimit removed
10 saved reportsUnlimitedLimit removed
5 people; basic city searchUnlimited people, exact-location searchLimit removed
No downloadable reportsPDF reportsA real capability

The structural problem: five of six are “the annoyance stops”, and the reading gate tightens the more someone uses the app. So the heaviest, most engaged users — exactly the ones most likely to pay — experience premium mainly as nag-removal. That is why a retained paying subscriber, asked directly, could not name a single benefit beyond “no ads.”

If new limits are added anyway — ranked by upside ÷ backlash

Lower risk — gate a capability

Adds something rather than taking it away

  • A daily cap on AI report generation. Best-shaped of the set: a genuine capability with real marginal cost, and a daily cap reads as fair rather than punitive.
  • Export and share beyond PDF — chart images, shareable links, printable wheels. Same shape as the PDF gate, which users already accept.
  • New relationship depth, gated as it ships. Pairs with the quarter's bet: gating new depth adds value without removing any.

Higher risk — takes away what people have

Every one lands on the cohort most likely to write a detailed review

  • Tightening saved-chart or saved-report limits. Hits the practitioner segment directly — the ~11,500 unconverted high-chart accounts — and is the single most review-bomb-prone change available, because it breaks existing saved work.
  • Lowering the 5-person limit. Worse: people store family and clients there.
  • Transit date-range limits. Cheap, but invisible until someone hits it, which makes it feel arbitrary.
  • Tightening the reading gate further. Already the most-complained-about mechanic, and it punishes engagement. Probably don't.
the stated biggest risk The grandfathering rule

Any new limit must not retroactively remove something an existing user already has. The exposure is not hypothetical — the internal rating moved 3.78 → 3.44 on a UI rollout that added something.

Grandfather on observed usage, not purchase date — someone free who has already saved 40 charts keeps 40; limits apply to new accumulation. Say it out loud in-app — a visible “you keep everything you already have” notice converts the most likely 1★ reviewer into a neutral one, and silent enforcement generates review bombs more than the limit itself. And ship the additive capabilities first, so the pitch is “premium now does more” rather than “free now does less.”

Your work is great and closer to original astrology compared to The Pattern… but it is built for busy people. It gives them enough context to understand what is happening and then helps them apply that understanding to their lives. — a user explaining why she keeps leaving for a shallower competitor

The competitor is not beating us on depth or accuracy — the things premium could gate — but on packaging and time-to-value, which is free to fix.

Four channels, and only one where the audience already exists

87,467monthly active app users, 18-minute sessions, 86.6% engagement
88,882monthly website users — and 90%+ of them never return
$0.20blended revenue per monthly active user, which gates everything paid
4.6★displayed rating on both stores, high and stable

1. The website → app handoff the standout

~89,000 monthly web users and 54,872 search clicks per 28 days already exist. There is zero conversion tracking between the site and the app, so nobody knows how much of that earned attention ever becomes an install — and a known parameter-drop bug breaks part of the handoff before it can even be measured. Every other item below is a bet on manufacturing new discovery in a saturated market. This one is finding out how much already-earned discovery is silently leaking. It's plumbing, not a growth hack, and it's the only place the audience is already there.

2. Creator seeding pilot sized, not greenlit

Not paid placements — free premium access to creators in exchange for organic content. The one anecdotal signal that has ever worked for this product is that people are blown away when shown the app in person, and competitors can't replicate that on camera because they don't compute this depth.

The pilotSized
Budget$750 — not buying posts, but covering attribution setup, assets, and a small reserve to boost the one or two that land.
Creators10 nano/micro, each posting one video of a real synastry reading generated live for two real people. Not a generic astrology-lifestyle script.
The bar≥391 attributable Android installs — i.e. did seeding beat what the same $750 would have bought through paid ads. That's 30–40 per creator. Stated as a threshold, not a prediction: no astrology-specific conversion data exists anywhere, which is exactly the gap the pilot fills.
Hard prerequisiteThe referral attribution from the relationship loop has to be live first. Without it, seeded installs land in generic “organic” and the pilot produces an unmeasurable number instead of the figure it exists to generate.

3. Paid advertising not now — a triggered re-test, not a permanent no

At $0.20 per user per month, twelve-month value is $2.40 — which sits right at the bottom of the iOS lifestyle cost-per-install range ($2–4) and roughly matches Android's average ($1.92). That's break-even-to-marginal, not wildly unprofitable. The honest caution is that paid-acquired users typically retain worse than organic. Raising revenue per user to $0.35 would put twelve-month value at $4.20 — comfortably inside the range, and a real case rather than a break-even one. So: re-run this math once the premium layer ships, and if it's ever tried, pilot Android-only, which is both cheaper and the platform with the confirmed decline. compare against $1.78, not $2.40, when judging a live campaign — see B9

the better version of the same idea

Standard install ads send every clicker to the same generic first-open wizard regardless of what the ad promised. Deep-linked campaigns — creative built around one specific feature, dropping the clicker straight into that feature on first open — have a documented 1.2–1.6× conversion lift. And the plumbing already exists: the affiliate system already carries an install token through the Play Store referrer and matches it on first open. Extending that token to carry a feature target is reuse, not a new system. The obvious first creative: relationships, deep-linked straight into add-person — already the best-converting step in the app.

4. Press and store editorial free to attempt, unproven

  • Apple's Featuring Nominations is a real, structured channel in App Store Connect. Lead time is 6–8 weeks realistically, up to three months ideally. Pitch the relationship loop, not “Chart Wrapped” — the loop is actually shipping this quarter. Working backwards from a mid-December ship, the submission window is early-to-mid November, and the feature must be demoable by then, not just described. Visual craft is reportedly the highest-weighted informal criterion, so an honest look at the relationship screen belongs in October.
  • Google Play editorial is not an addressable channel at this scale — no public submission route, and editorial contact runs through an assigned account manager reserved for far larger publishers. The only real lever on that side is the algorithmic quality signal.
  • “Chart Wrapped” is the stronger press story — genuinely hard to copy, because we retain multi-year chart history most astrology apps don't track. But it isn't scheduled, and pitching a feature with no build date is pitching vaporware. Park it until it has one.
  • Fleet-data hooks — “the most common placement among X”, seasonal trend pieces — run on a real anonymised dataset most competitors don't have. Close to free to attempt, no guaranteed pickup.

Eighteen identified advocates, and nothing in the product serves them

Praise clusters on content depth and visuals, not on the interface — which confirms “the substance is better, the packaging isn't” from the opposite direction. Mostly from payers.

I have left a review and I recommend your app to everyone in my astrology groups. I'm a big supporter of you guys.— 44 saved charts, and still on the free tier
I do a lot of readings and teach astrology… I'll definitely be putting in another review, all positive.— lifetime buyer, promotes the app and the tarot deck unprompted
Yeah I can leave a review, I'll do it now before I forget.— the intent is perishable, and nothing captures it
I was using AstroMatrix as the storage for all of my clients.— one of five users running a paid practice on top of the app

People volunteer gifting, promoting and reviewing, and no feature supports any of those actions. There is no gift flow, no referral path, no share-a-reading built for advocacy, and no prompt that catches someone at the moment they say it. One user gifted a lifetime subscription to her sister in 2019 — organic gifting happens today with zero product support and zero tracking. Another left a review before buying, then bought lifetime because of the experience: the advocacy-to-conversion loop running entirely by accident.

the mirror image The same lever produces 1★ reviews

The same sweep surfaces it in users' own words — my 5 star rating is going to be lowered if these issues and my requests for help are not answered, after three unanswered messages. The lever that produces 5-star reviews and the lever that produces 1-star reviews are the same lever. An unanswered advocate becomes a reviewer with a grievance — directly relevant to the grandfathering exposure above: the existing advocate base is both the biggest buffer against a review-bombing and, if neglected, its source.

Four things to build, none needing new astrology: capture the moment (when someone expresses advocacy, that is the point to hand them the link — cheapest version is a prepared reply with a store link and a gift link) · a gift flow (it already happens manually, so it neither scales nor is measurable) · an individual referral path distinct from the creator-scale affiliate programme · a practitioner surface — client charts, sharing a reading with a client, export. The five professionals identified have the highest switching cost, the loudest professional networks, and the most to lose.

One user asked for Part of Fortune, got it, and came back with “thank you for hearing my requests” — a complainer converted into an advocate purely by visibly shipping what they asked for.

The value isn't only in the feature; it's in the reporter learning it shipped.

Already proposed, checked, and ruled out

Each of these was suggested in a previous pass and retracted after checking. They keep coming back, so they're written down.

  • Don't gate the existing free chart and report depth. It's the one thing that produces the “blown away” reaction when the app is shown in person — locking it away kills the only organic signal that currently works.
  • Don't merge the Report and Chart screens. Deliberately separate, both convert well, working as intended.
  • Don't treat store-listing copy as a growth lever. Fix it once, cheaply — the current copy leads with “free and easy” instead of depth, and drops “horoscope” as a keyword — then stop iterating.
  • Don't build offline calculation as a growth play. Real and worthwhile for practitioners handling other people's sensitive birth data, but it has no sharing mechanic and won't move installs.
  • Don't replace the tarot free-text box. The 28-character typed question is the product — the only place in the app where users tell us in their own words what they want to know, and there are 4.5 million of them.
  • Don't push tarot on the basis that it has “lowest reach.” That guidance was backwards: within any collection size, tarot users convert better.
  • Don't chase organic social growth. A documented prior dead end for this brand — a 30k stale audience in a saturated niche. Targeted creator partnerships are a different thing and remain untested.
  • Don't build non-English store screenshots. All non-English users combined are ~14%, split across 29 languages.

Decisions nobody else can make

  1. The lifetime SKU — reprice, retire, or leave it

    45% of purchases, one SKU at $49.99 is 41% of all sales, and it's the largest structural cap on lifetime value. The only change with zero grandfathering risk, and everything else in the pricing conversation is downstream of it.

  2. Are we adding new limits at all, or only new capabilities?

    The recommendation is additive-first, and there's a real case that a product already seen as harder to use than a cheaper competitor cannot afford a subtractive change. But this is a pricing call, not an analysis one.

  3. Is localisation a premium feature or a free one?

    Effectively decided free by default. Gating it afterwards becomes a withdrawal rather than an addition. See B3.

  4. Greenlight the $750 creator pilot?

    Yes/no, contingent on the relationship-loop attribution shipping first. The number it produces — a real, AstroMatrix-specific cost per install — doesn't exist anywhere today and can't be borrowed from industry benchmarks.

  5. Commit to the November Apple nomination?

    Free, and rides on work shipping anyway, but it forces a date: the relationship feature must be demoable by early November, and the visual pass has to happen in October.

  6. Is “Chart Operator” a named product surface or not?

    A workspace mode — client notes, last-seen, session history, pinning, transit alerts — for the practitioner segment. It doesn't fit inside the four-pillar story, so it needs an explicit yes or no rather than drifting.

↑ Back to index top
V

The Matrix Question

Product brief updated 2026-09-11 evidence: 11 Sept production scan, in-app support, store reviews original →

The Matrix is the most-reached screen in the app after Home, and the second best at bringing people back. It is also the same screen every single time you open it. This is about closing that gap.

The Matrix is our simplification, not our complexity

It takes a birth chart — 29 bodies, several hundred aspects, a vocabulary that takes years to learn — and turns it into five words anyone can read: Purpose, Harmony, Love, Abundance, Evolution. That is the whole product thesis in one screen. Someone who knows nothing about astrology can open it and understand what they are looking at. No competitor ships the depth underneath it, and almost none ship a way in that is this gentle.

68.8%of tracked accounts reach it — more than any screen except Home
29.1%never come back — second lowest in the app, behind only interpretations
1 of 49UI complaints that actually name the Matrix as too complex

That last figure is the one to sit with. Months were spent treating “the app is too complex” as a Matrix problem. Of roughly forty-nine people who complained about the new interface, exactly one said the Matrix itself did not make sense. Everyone else said a version of “I cannot find a thing I already know exists.” Those are opposite problems with opposite fixes. Simplifying a screen that is already the simplification would make the product worse.

And because the Matrix's parts also render inside Home, the Moon screen and the weekly report, anything improved here lands on six surfaces at once. It is the highest-leverage screen in the product.

Three journeys — where people actually fall out

  • Journey one — the newcomer, thirty seconds after signing up

    They finish a four-step setup — name, what they care about, birth date, birth place — and are dropped straight onto the Matrix, on the category they chose. This screen is the payoff for signing up. What they get is a radar chart and a grid of scored categories. After four screens of questions, the reward for answering is one more thing to navigate.

    The break: we asked them what they cared about and then handed them a menu instead of an answer. Reading one interpretation is the sharpest activation threshold measured — activity jumps from 2.7% to 17.9% once someone reads one. We route them to the door and do not walk them through it.

  • Journey two — the returner, on their fourth visit

    They tap the Matrix tab. They see what they saw last time. Same categories, same scores, same cards, in the same order. By default the screen shows everything it knows at once — their birth chart and every current transit, merged into one list. Nothing says what is permanent and what is passing. Nothing says what is happening today.

    The break: a screen that never changes gives no reason to come back tomorrow. Retention is a smooth slide, not a cliff — 94% reach a second visit, 78% a fifth, 41% a twentieth. That shape is what “no fresh reason to return” looks like.

  • Journey three — the person who was sent a link

    A friend shares their compatibility. The link opens the Relationship Matrix. Roughly half of these people are gone inside ten seconds — and among people arriving cold from a share link, 93% leave in under ten seconds. It is the worst-performing surface in the app. What greets them: no time filter at all, so there is nothing about right now. And in the default view, no Report button — the screen's main action is simply not rendered until you change a setting you do not know exists.

    The break: this is also the best monetisation signal. Adding a second chart moves conversion from 20.7% to 51.2%. The relationship surface is where that happens, and it is the one finished least. 72% of accounts have never opened it.

Almost every complaint is the same complaint

Can no longer see yearly things like time lord and profection year.— Google Play review

Time lord and profection year are on the Summary tab. They were never removed. This is the fourth separate confirmed case of a live feature being reported as deleted — the others were weekly and monthly transits, solar return interpretations, and saved charts.

Everything looks the same, no visual differentiation to find what I need.— in-app support

This is the actual problem, said plainly. Not too much, not too hard — too flat. When every card looks like every other card, the eye has nowhere to land, and a person who knows the feature exists still cannot find it.

The new matrix system doesn't make sense, difficult to read through.— in-app support — the one complexity complaint in forty-nine

Worth taking seriously as a minority signal, not as a mandate. “Difficult to read through” is closer to the flatness complaint above than to a request for fewer features.

We are not failing to give people enough. We are failing to tell them what they are looking at.

Five moves, in the order to make them

  • 1 · Make the screen different every day

    highest returnsmall buildno new data

    Right now cards are ordered by category — houses, then aspects — which never changes. But every card already knows whether its influence is active right now and how close it is to peaking. We compute this for every item and then ignore it completely. Sort by what is live and cresting today. Badge the active ones. The screen then changes on its own, every day, because those values move on their own.

    Why this one first: it is the only fix on this list that gives people a reason to return tomorrow, and it needs nothing we do not already have. It also sidesteps the argument about which default view is correct — the screen becomes time-aware without anyone choosing a default.

  • 2 · Answer the question instead of showing the data

    high returnfree — no AI cost

    Every category already carries a pair of words and a count — Passion against Distance, Success against Obstacles, eight supporting influences against two challenging ones. The screen holds all of it and displays only the category name. Put one line under each category: “Intimacy & Romance — Passion 8, Distance 2.” That is the difference between a chart and an answer, and it is the thing the setup flow implicitly promised.

    It also fixes a quieter problem: the score bars scale to each person's own maximum, so no number on the screen means anything in absolute terms. Words give it a direction even when the bar does not.

    Keep the AI where it is. The deep written report stays behind the button — that is the payoff for tapping in, and it is genuinely good: people who reach a report spend 1.4 minutes there and 90% do not bounce.

  • 3 · Fix the relationship first-run

    highest commercial upsideone engineering unknown

    The worst-performing surface is also the strongest conversion signal. Three things are wrong on arrival: the main action is invisible (in the default view the Report button is not shown at all); there is no “right now” (the solo Matrix has weekly, monthly and all-transits views — the relationship side has none); and we pick their partner for them (if an account has exactly two people saved, opening the Relationship Matrix silently pairs them and remembers it, changing what every other relationship screen shows, without asking).

    The unknown: the hidden Report button was disabled because that specific report was thought too large to save. The reasoning does not match how the app actually saves it, and the real limit looks to be roughly fifty times larger than the report. One measurement settles whether it can simply be turned back on.

  • 4 · Stop features from feeling deleted

    medium returnreduces support load

    Four confirmed cases of people reporting removals that never happened. The Matrix makes this worse in a specific way: influences that have finished quietly disappear from the list. Correct behaviour, never explained. Someone who saw an aspect last week and cannot find it today concludes we took it away. Two cheap moves: say when a view is empty and why, instead of showing a blank panel; and give finished influences a visible “ended” state rather than vanishing them.

    The wider version: our depth is invisible — synastry 1.5%, composite 0.3%, the store 0.2%. We are not short of things to sell. We are short of people finding them.

  • 5 · Don't lose people's reports

    low volumetiny buildhigh indignation per occurrence

    When a report is generated but fails to save — a network blip — we show a warning with a “View Now” button so the person can still read what they waited for. That button goes nowhere. It has never worked. Rare, but it lands at the worst possible moment: right after we told someone their thing was ready, and then lost it.

Three things not to do

Don't rename the Home buttons

The standing recommendation is that people cannot find weekly and monthly transits because the buttons do not say “transits”. But the two people who reported it asked “where is the weekly and monthly forecasts” — and the buttons say exactly Weekly and Monthly. They used our words and still did not find it. The label is not the barrier; where it sits on the page probably is.

Don't change the default view on instinct

Tempting to switch the opening view from everything-at-once to transits. But there is no A/B framework, no way to tell one session from another, and no app-version tag on stats — so we would be swapping a default we cannot grade. Bet 1 makes the screen time-aware without needing this decision at all. Make it later, with evidence.

Don't simplify further

One person in forty-nine called the Matrix too complex. The rest could not find things. Removing depth would answer the minority and damage the majority — and the depth is the only thing competitors cannot copy quickly.

The blocker: we cannot currently tell whether any of this worked

Everything measured is screen-level: how many people reached a screen, how long they stayed, whether they came back. Nothing tells us what they were trying to do, or what they tried just before giving up. Three things are missing, and each blocks grading the bets above:

  • Session-level events — we count screen views, not app opens, so “visits” means something different from what everyone assumes when they read it.
  • An app-version tag on stats — without it, no change we ship can be separated from any other change we ship. shipped 09-11 — see II §05
  • Any A/B capability at all.

None of this should stop bets 1, 2 and 5 — they are small, obviously directionally right, and cheap to reverse. It should stop expensive or irreversible calls, like the default view, until the result can be read.

free measurement available today

We can already tell whether a person has ever changed the Matrix's view filter, because choosing one leaves a trace and never choosing one does not. Nobody has ever counted it. If that number turns out to be 3%, the whole default-view debate is settled by the data rather than by argument.

Evidence: production scan of 11 Sept 2026 covering 102,600 tracked accounts — the first pull after the instrumentation fix released on both platforms, so the first trustworthy one. Complaint analysis from 45 days of in-app support (756 users) plus store and Facebook backlogs. Engineering detail behind bets 3 and 5 is filed as issues 131, 132, 136 and 137.

↑ Back to index top
VI

What AstroMatrix Knows

Audit 🔭 updated 2026-09-11 branch new-ui · 454 Dart files + nodejs schemas & AI routes · no changes made original →

A code-level stock-take of everything the product currently stores, observes or could derive about a person — and how much of a user knowledge profile is already sitting in production, unread. The suspicion behind this audit was right, and stronger than expected: three of the five layers already exist as production data.

LayerStateWhat exists
Explicit factsWorkingBirth data, Big Three, 60+ chart and display preferences, language, selected partner — all persisted and synced. One critical fact is collected and discarded.
Behavioural signalsBuilt, never readusers.stats accumulates per-screen visit counts and dwell averages for every user, server-side, surviving reinstall. No product surface has ever read it.
Saved & intentional actsWorkingThe Journal is already a timestamped, per-account, free-text-annotated store of everything a user deliberately kept. Rich. Under-modelled.
Derived patterns1 of 14 domainsTarot stats prove the aggregation mechanism works end to end — and cover the one domain where the dimension was pre-classified at write time.
AI memoryNot wiredA complete conversational-memory schema, CrucibleChat, exists in Node against the same Mongo. Zero Dart files reference it.

Five headline findings

  1. The most valuable fact we collect is thrown away in the same frame it is collected. Onboarding step 2 asks “What do you need answers about?”, requires an answer to advance, and never persists it — not to disk, not to the server, not even as an analytics label. It has been that way since the step shipped in df13e1ab (2025-12-22); git log -S selectedFacet shows nothing has touched it since.

  2. A per-user behavioural store already exists in production and is write-only. stats.pagecounts and stats.avgs accumulate on every screen change and sync to Mongo. The only read anywhere in the app increments a separate ads counter.

  3. Behavioural granularity is destroyed at three specific choke points — all fixable, none architectural. We can answer “how many people opened a relationship interpretation this week”; we cannot answer “has this user been reading relationship content”.

  4. The AI knows nothing that distinguishes a returning user from a first-timer with the same chart. The richest AI request in the product sends a chart, a list of transit items, and a first name.

  5. The interest taxonomy we would need to build already exists — as the 14 Self-Matrix and 12 Relationship-Matrix categories, already rolled up to the five onboarding facets by a tested mapping.

The ledger — identity and astrology, well covered

Every row was verified in source. Persistent means it survives app restart; AI means it reaches an AI prompt today.

KnowledgeStored wherePersistentAIStatus
Name, birth date / time / town, lat / lng, timezone
lib/models/user_profile.dart:8–47 → models/User.js:12–41
usersyesyesFact
Big Three — sign, degree, minutes, house
lib/services/user_service.dart:1665–1734
users.datayesnoFact
Every saved person (“additional charts”)
one users row per person, peer of the account's own
usersyeswhen selectedFact
Currently selected partner — the one durable user↔person link that exists
lib/services/horoscope_service.dart:401–410
prefs + localyessynastryFact
House system, zodiac system, 3 orb settings, smart orbsusers.settingsyesnoFact
14 asteroid / point toggles, aspect & display prefs
lib/constants/preference_keys.dart:55–95, 269–288
users.settingsyesnoLiteracy signal, unused
Languageusers.settingsyespartlyHalf-wired
Declared area of interest — Love / Evolution / Abundance / …
lib/views/user_wizard_screen.dart:365–470; never reaches saveUser()
nowherenonoDiscarded

Every chart, aspect, transit, progression, synastry, composite, draconic and return is computed on demand and cached disposably. No computed-chart collection exists anywhere — the engine README still lists “Database integration” and “Caching layer” as Not Implemented.

Behaviour — a real store exists, and nothing reads it

SignalWritten byStored whereServerStatus
Per-screen visit countsScreenTimerServiceusers.stats.pagecountsyesWrite-only
Per-screen average dwell secondsrunning meanusers.stats.avgsyesWrite-only
Ads seenAdsServiceusers.stats.ads_seenyesWrite-only
Chart-type dwell, per typechart_screen.dartfolds into pagecountsyesWrite-only
Tarot sessions + per-deck dwellTarotReadingSessionpagecounts + PrometheusyesWrite-only
Gating session count / view countContentGatingServicelocal onlynoDevice-bound
Which interpretation, aspect, planet or house was opened———Not recorded
Which person a report was about—name inside a title string—Not recorded
Searches, AI questions, per-user notification opens, sessions———Not recorded

Where the granularity goes

Three choke points, each a deliberate past decision that was right for its own purpose and wrong for this one. The most consequential is a single line.

Choke 1 · The route already carries the answer, and drops it

/component?component=Venus+square+Saturn&category=Intimacy+%26+Romance
↓  _sanitize() splits on ? and keeps the head — screen_timer_service.dart:165–166, mirrored in metrics_service.dart:326
"component"

The component name and its category are present in the route, at the call site, and are discarded one line later. We record that a user opened 200 interpretations; we never record which. This is the cheapest high-value fix in the document.

Choke 2 · Prometheus cannot carry a person

All metrics go to Prometheus counters and gauges. A session id is generated and deliberately left unattached — the comment at metrics_service.dart:30–52 spells out why: an unbounded label is one time series per session, a cardinality bomb. It ends: “It exists so session-scoped events can carry it once a real event store exists to receive them.” No such store was ever built.

Choke 3 · The one content metric carries category only

component_opened_total is labelled {category, source} — never the component name, never a user. Aggregate by construction. Firebase Analytics is not a second source: its whole surface is purchases, shares and four main-user diagnostics, it is disabled on web, and it joins to no user id we hold.

What reaches the AI today

Three AI endpoints exist. Two are reachable from the app, and the third is only used for translation.

Path 1 · Chart reports — POST /ai/calculatereport

{ reportType, chart: <ChartPayload>, profileId, language } // profileId is sent and never used // no history, no prefs, no people

Path 2 · Matrix reports — POST /ai/generateDataReport the main AI surface

{ data: { category, view, matrixType, items[]: component, facet, aspect, sign, concept, opportunity, pattern, begins, ends, percentComplete, orb }, metadata: { userName, reportName, … } } // specificQuestion IS supported server-side // and no Flutter code ever sets it

Path 3 · GPTService — generic completion, one caller: translation

{ prompt, systemMessage, temperature, maxTokens } // stateless by construction
  • No conversation exists. No chat surface, no follow-up, no history. specificQuestion is plumbed end-to-end in Node and unreachable from the client — the “ask about this reading” capability is built and unwired.
  • AI history is a file, not a record. logAIInteraction appends to ai_log_YYYY_MM.json by rewriting the whole file, stores a first name and no user id, races across a clustered process, and has a user_feedback field that is always null. It is prompt QA, not memory.
  • A working memory schema is one repo away. CrucibleChat defines per-user history with per-turn metadata, running stats, and a currentState block documented as “re-injected into next prompt”. It belongs to the quiz funnel, not the app — but it is a reviewed design for exactly this layer, already running against the same Mongo.
defect found in passing ISSUE-146

ISSUE-39/122 threaded language through five AI paths. /ai/generateDataReport is not one of them, on either side. Every Matrix category report — the main AI surface — is still English-only for every user regardless of their language setting. Narrower than ISSUE-122, and not covered by it.

The model: facts, signals, inference

Twelve relationship lookups support relationship_interest: high. They never support has_relationship_problems: true.

Five layers, separated so an observation can never be promoted into a fact by accident. Facts and saved acts mostly exist already; signals need scoring; inference needs receipts and decay.

Action weights — intentional acts outrank passive ones

ActionWeightWhy
Journal comment written5.0Effort, in the user's own words
Tarot question asked5.0An explicit statement of need — already captured today
Report generated4.0Deliberate, costly, often gated
Interpretation saved (heart)3.0Intentional keep — already a journal write
Entry reopened later3.0Sustained, not momentary
Person selected for a reading2.0Directed attention
Interpretation opened1.0Passive
Screen dwell > 20s0.5Corroboration only — a backgrounded app looks identical
Screen opened0.2Navigation noise
Interpretation un-saved−3.0Negative signal; prevents stale interests

Scored with a 30-day half-life for current interest and 180-day for long-term themes, damped by novelty — ten opens of one component means attachment to that item, not interest in its domain. Nothing is reportable below 3 events across ≥2 distinct days.

An inference is only ever written with its receipts

{ "statement": "Relationships appear to be a current area of focus", "confidence": 0.72, "timescale": "current", "supportingSignals": [ { "dimension": "category:Intimacy & Romance", "score": 41.2, "events": 18 }, { "dimension": "person:p_8f2a", "score": 22.0, "events": 9 }, { "dimension": "chartType:chartrelationship", "score": 12.5, "events": 5 } ], "aiEligible": true, "userVisibleAs": "You've been exploring relationship themes a lot lately" }

The whole knowledge document is derived and disposable: delete it and it rebuilds from journals, events and settings. That single property is what makes “reset my personalization” a one-line delete, and what makes changing the scoring rules safe to ship.

The taxonomy already ships. The interest dimensions exist twice over, as the 14 Self-Matrix categories — Path & Career, Intimacy & Romance, Security & Roots, Soul Path & Karma, Emotional & Mental Health and ten more — and the 12 Relationship-Matrix categories. They are already rolled up to the five onboarding facets by a tested mapping in component_image_helper.dart:247–273, so Intimacy & Romance → Love is the same vocabulary the discarded onboarding answer speaks.

Retrieval, not ingestion

The profile is the index, not the payload. Each request assembles a budgeted context from ranked candidates: relevance × recency × actionWeight.

BudgetTokensContents
Always sent~600Chart placements and current transits for the subject · the screen the user is on · language, knowledge tier, length and terminology preference
Retrieved, capped~1,200People named or implied by the query (≤2) · journal entries matching the category or person (≤5) · prior AI reports on the same category or person, as stored 2-line summaries (≤2) · saved interpretations in the category, titles only (≤5) · derived patterns at confidence ≥0.6 and AI-eligible (≤3)
Never sentany budgetRaw event logs · full journal text · unrelated categories · low-confidence inferences · anything the user has not consented to, or that touches a sensitive category

Summarising at write time rather than read time keeps this flat: a prior report costs ~40 retrieval tokens instead of ~1,500. A fully personalised Matrix report grows from roughly 2,500 to 4,000 prompt tokens — about +60% on a gpt-4.1-mini call, a rounding error against the revenue those reports gate.

Trust, and one thing to fix regardless

The design goal is that a user reading their own profile page thinks “yes, that's fair” — not “how do you know that?” Every stored claim carries its provenance, and inferred ones are dismissible in one tap, with the dismissal actually suppressing the inference rather than hiding it.

Forbidden outright: never infer or store sexual orientation, gender identity, religion, health or mental-health status, pregnancy, substance use, immigration status, financial distress, or the state of a relationship. These are exactly what astrology browsing tempts. Reading twelve “Intimacy & Romance” interpretations is a content preference. The permitted claim is always “you have been reading X”, never “you are Y”.

fix before Phase 1 ships Journal access needs stronger authentication

[Details of an open security item are withheld from this public copy.] Harden journal access before enriching what journals store.

What to do first

Ordered by value ÷ effort, and specific to what already exists. Everything here is capture or repair — none of it depends on the model being right, and all of it makes the model possible.

  1. Persist the onboarding facet

    One field, one line, today. A self-declared life priority collected from 100% of new users at the moment of highest intent, currently discarded between two function calls. Before any AI work it can order the home screen and pick the first Matrix tab.

  2. Read stats.pagecounts

    Already in Mongo for every user. One read-only query answers “which categories does this person actually spend time in” — no new capture, no migration, no client release.

  3. Stop stripping the query string

    One line in each of two files converts the most-used behavioural counter in the app from “opened the component screen 200 times” into real content history.

  4. Write subjectPersonIds onto journal entries

    Additive to an existing Mixed field, so no migration. Unblocks the entire relationship model — and fixes the real bug where reopening a saved relationship report renders whoever the partner is now.

  5. Harden journal access

    Do it before anything above enriches journal data.

  6. Fix the Matrix AI language gap

    Small, self-contained, and the last English-only AI surface in the product.

  7. Read the tarot questions

    Already in Mongo, already indexed, and the only unmediated user language the product holds. Even a manual read of a few hundred would inform the taxonomy and the prompt more than any inference engine.

  8. Then start scoring

    Phase 2 and beyond only after the capture gaps are closed.

Item 1 alone is arguably worth more than Phases 2–5 combined per unit of effort. It should not wait for a roadmap.

Full audit with every file:line citation, the complete data structures, the event taxonomy, the privacy controls and the five-phase roadmap: docs/user-knowledge-audit-2026-09.md. Companion docs: built-but-disconnected-2026-09.md · strategy-reference-2026-09.md · product-strategy-2026-09.md.

↑ Back to index top
VII

AstroMatrix Quick Wins

Task list 🔧 updated 2026-09-11 source docs/DEV-quick-wins.md original →

Everything here is plausibly under half a day. Anything bigger was deliberately left out — the last block says what, and why. This is the most recently written of the seven, so where its issue numbers differ from the others, its are the current ones.

✓ verified in code or live on 2026-09-11    § from the docs, not re-verified

A · The price change

Lifetime $49.99 → $79.99, discounted lifetime $34.95 → $55.99. No new products and no app release — ✓ products_config.json carries no prices, ✓ no hardcoded prices in any .dart/.ts/.tsx, and ✓ the 30% discount works by swapping to a separate product id, not a coupon.

#WhereChange
A0scripts/_payments.jsDo this first. usdPriceByType() medians price across all history per SKU. After the change full_purchase2025 holds both $49.99 and $79.99 and the median drifts between them for months — every per-SKU revenue figure stays plausible and becomes wrong. Bucket by (SKU, month).
A1Google Play Consolefull_purchase2025 → $79.99 · discount_full_purchase2025 → $55.99. Set regional pricing deliberately, not auto-convert. ✓ Not doable by API — inappproducts 403s with “migrate to the new publishing API” and no v3 replacement resolves. Console UI only.
A2App Store ConnectSame two. ✓ No API path at all — no .p8 key exists.
A3Stripe — lastSame two. ✓ Live state confirmed: $49.99 / $34.95. A Stripe Price amount cannot be edited — create a new Price on the existing Product (so metadata.shortcode carries over), create a new Payment Link, then deactivate the old link.
two traps

Deactivate the old Stripe links. /payments/get (routes/payments.js:1433) lists every active payment link with no dedupe by shortcode — leave the old one up and the app shows two lifetime products at two prices.

Stripe goes last. Doing it before the stores leaves web at $79.99 while both apps still charge $49.99.

✓ Safe: nothing hardcodes a buy.stripe.com URL anywhere — links are fetched live, so replacing them is transparent.

for Mark, not the dev What is the discounted price really?

Every website CTA now routes through applyDiscount?code=WEBPROMO1, which serves the discount SKU. So web-acquired buyers pay $55.99, not $79.99 — +12%, not +60%. That path is tiny today (21 of 1,551 purchases last quarter) but the CTA fix was built to grow it. $55.99 is the price most new web users will actually see.

While in the consoles: grab the three real prices. The corrected store copy is blocked on exactly those, and the iOS listing is wrong today — it advertises a 6-month plan that does not exist, and “10 profiles free” when the real limit is 5.

B · Ship what is already fixed

Zero new code. ✓ Verified against git on 2026-09-11.

#RepoAction
B0all — firstISSUE-149 — 24 finished Flutter commits have been sitting unreleased since 2026-09-09. Verified three ways: git log 8583ffaf..HEAD = 24 commits, pubspec.yaml still reads 11.0.0+300100090 with no bump since the 09-08 cut, and zero store release emails in 4 days. All pushed to origin/new-ui — nothing is lost, purely a cadence gap. The fixes for ~13 tracked issues are stranded, including ISSUE-129 (Android purchases hitting the payment call with an empty userId — 261 Google Play orders in 30 days landing unattributed). Cut a release. Single highest-value item on this page.
B1astromatrix-publicCommit + push app/home/terms/ and Footer.tsx. The Terms URL printed in every store description 404s, which blocks the ASO submission under Apple guideline 3.1.2. Push auto-deploys — run npm run build locally first and check git log origin/master..HEAD.
B2astromatrix-flutter
(new-ui)
Commit products_config.json + gated_content_widget.dart — the paywall sells two things the free tier already has. Note the shipping branch is new-ui, 116 commits ahead of master.
B3astromatrix-nodejs2 unpushed commits on master.
B4infra, not codeSet the autosupport key in production config and update the scheduled job in the same change, or live autosupport breaks.
before you start Check git, not the docs

Before working any “committed but not deployed” item from the fire docs, check git first. Two such claims were already in origin/master despite the docs saying otherwise.

C · Quick code fixes

now tracked Filed in the fire report

ISSUE-150 (C5), ISSUE-151 (C7) and ISSUE-152 (the pricing work in §A) are now numbered issues in the master fire report and reflected into SUPPORT-fire-FLUTTER.md / SUPPORT-fire-NODE.md. The rest were already tracked — C1 and C3 in SUPPORT-ux-experience-issues.md, C4 as ISSUE-132, C8/C9 in that same doc §8.

⚠ Removed since the first draft: the /matrix-report dead route. It was fixed 2026-09-11 (9b7dd49e) and the app-wide sweep came back clean — zero unregistered navigation targets remain. Do not re-file it.

#WhereItem
C1✓ home_buttons.dart:149-161The home button says the wrong word. Home says “Weekly”; reporters search for “transits”. ⚠ The obvious fix — carrying the "Weekly (Transits)" label onto the button — is NOT buildable: home labels are maxLines: 1 + TextOverflow.ellipsis at fontSizeSM, so it renders as “Weekly (Tra…”, and every label runs through getLang() so German and Turkish truncate sooner. Existing labels sit at 6–13 characters — that is the budget. The real fix: merge Weekly + Monthly into ONE “Transits” button (8 chars), opening the Matrix with the Weekly/Monthly/All chips from C3 visible on arrival. Fewer words, the exact word three reporters used, one freed grid slot. Ship with C3.
C3✓ matrix_service.dart:898Surface the Matrix lens names as on-screen chips instead of dropdown contents — nobody opens a dropdown to discover a feature. All 7 labels already exist in getCategoryMenuOptions(): All Aspects · Foundation (Birth) · All Transits · Weekly (Transits) · Monthly (Transits) · Growth (Progressed) · Soul (Draconic). Presentation only — no new strings, no astrology.
C4§ ISSUE-132Relationship Matrix silently auto-pairs a second profile and persists it app-wide. Two bail-out guards are written && mounted, so an unmounted widget skips the return as well as the pop. Small and self-contained; not verified on a device.
C5§ notification_router.dartISSUE-150 — notification deep-links dead-end on Home. The router is wrapped in a try/catch that only debugPrints, so any throw silently leaves the user where they were — on a cold launch, the home screen. Fall back to a real destination and record the failure. Reported by a lifetime customer; this is an engagement channel already being paid for.
C6✓ routes/journals.js:520The post-reading tarot comment is discarded — writes comment: '', ignoring the request body. One line — but it is deliberate legacy parity, not a bug, so confirm intent first. (The docs cite :451, which is the wrong line.)
C7§ chart_screen.dartISSUE-151 (UNVERIFIED — check the widget first) — the synastry wheel sits 6th in the chart dropdown, behind Progressed at 3rd — a practitioner chart outranking the one chart a normal person came for. Reorder. Not verified.
C8§ astro_helper.dart:1375South Node not visible on some surface. It already exists end to end — engine body index 27, glyph present, already a row in the transit aspect table. Scope is only “find which surface drops it”. Narrower than originally filed.
C9§ chart_constraints.dartAdd a showOuterPlanets flag for Uranus/Neptune/Pluto. 13 per-body visibility flags already exist; classical and outer planets currently share one blunt showPlanets. Leave nodes and angles on the existing flag — traditional practice uses the nodes, so a naive “classical vs post-Saturn” split hides exactly what the requester wants kept.

× · Deliberately excluded — not quick

ItemWhy not
Event storeDesign work, not a one-liner. Prometheus is aggregate-only; a uid label across 460,694 accounts is a cardinality explosion. A design already exists in user-knowledge-audit-2026-09.md §I3.
Relationship transitsAn engine change, despite the docs saying otherwise. CalcChart() has two chart slots and applyComposite() consumes both. Needs a decision on which of three techniques first. see B1
Link the store / give reports a routeThe highest-value item on the roadmap, but real work — not a quick win.
Raising the annual subscription priceSubscriptions carry Apple/Google consent and notification requirements for existing subscribers. Lifetime is a non-consumable and has none. Separate job.
Anything needing App Store Connect automation✓ No .p8 key exists. Provisioning one (Admin role) unblocks four things at once: Apple price automation, the 62% of revenue never reconciled against Apple's ledger, iOS review monitoring, and iOS install data.

Source: astromatrix-nodejs/docs/DEV-quick-wins.md. Companion to docs/ROADMAP.md, which carries the reasoning behind the price change and the engine correction.

↑ Back to index top

§D · End matter

How this was assembled

Each of the seven briefings was read in full from its published source and restated here under one type system, with its structure and its claims preserved. Nothing was summarised away, and no claim was strengthened: where a source hedged, the hedge is kept.

The one thing added is §B. Those ten conflicts were found by reading the seven against each other — none of them is noted in any individual document, because each document was written without sight of the others. Where a conflict was resolved, the rule applied was that a claim checked against source code or a live console beats a claim carried forward from another document. Where the sources simply drifted rather than disagreed — issue counts, unpushed commit counts — that is said plainly rather than resolved to a false single answer.

§C merges the verified/retracted number tables that three of the documents each carried a partial copy of. Cross-references marked see Bn inside the briefings point at the place a claim in that briefing is contested.

This is a snapshot. Every deploy-state claim, commit count and issue number in it was true on 10–11 September 2026 and will drift; the underlying repository documents stay authoritative. The standing rules in the sources apply to this page too — re-derive any fleet level with node scripts/_analytics.js verify, and check git rather than a document before acting on any “committed but not pushed” claim, including the ones printed above.

Seven sources, all published privately to claude.ai: AstroMatrix Ground Truth · AstroMatrix Orientation · AstroMatrix Orientation Map · The AstroMatrix Playbook · The Matrix Question · What AstroMatrix Knows · AstroMatrix Quick Wins. Each dossier header links back to its original.

↑ Back to index top