Conversation
A collapsible, in-world "war narrative" for each season's /archives page —
a chronological chronicle generated in the Ministry of Truth propaganda voice
from existing getCampaign data (no schema/DB/query changes).
- buildWarNarrative(data): pure helper → ordered [{day, text}] beats — opening,
faction arrivals (introduction_order + first_seen), cascade runs collapsed via
findAllCascades, per-event field reports, and a getWarOutcome cap. Defensive:
empty → []; reduce-min war_start fallback (no Math.min spread).
- NarrativeSection.jsx: native <details>/<summary> collapsible, hide-when-empty,
data-umami-event="archive-narrative-toggle". Wired into ArchivesClient after
the Player Engagement section.
- 12 unit tests incl. an Illuminate-cascade regression for the article-stripped
faction name ("The Illuminate", not "The The Illuminate").
Verified: lint, typecheck, test:unit (1515), build all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…157) Surface WHEN each faction entered the war on the /archives timeline, as synthetic "<Faction> enter the war" markers interleaved chronologically with the event rows. Archives-only; the live dashboard is untouched. - buildIntroMarkers(data): pure helper → one marker per faction with a positive introduction_order slot AND a non-null first_seen; day math + article strip mirror buildWarNarrative; reduce-min war_start fallback; missing data → []. - EventLog: opt-in `introMarkers` prop (default []). When empty, output is byte-identical to today (HomeClient passes nothing) — a test asserts default- vs-empty render identical. Markers render via a faction-colored IntroMarker divider, keyed intro-${enemy}, excluded from the day W/L count. - ArchivesClient computes + passes the markers. Verified: lint, typecheck, test:unit (1518), build all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…catter) Replace the per-event Player Engagement scatter with a per-war player-count line that hooks into the existing /archives faction toggle: - global → total-players line (brand primary) + dots for every event - a faction → that faction's line (faction-colored) + only its events' dots Event dots sit on the line at each event's start day with a type · region · faction · outcome tooltip. No legend (the toggle labels it). - getCampaign: additive `playerTimeseries` field (per-bucket players from h1_statistic via new groupStatisticByBucket); [] for pre-telemetry seasons. - buildPlayerLine.mjs: pure, unit-tested line+dots builder. - PlayersOverTimeChart.jsx (+ Loader), wired into ArchivesClient's faction section; removed PlayerEngagementChart + buildEngagementSeries (+ scatter). - Hides for historical seasons with no player timeseries. Verified: lint, typecheck, test:unit (1514), build; DevTools across all toggle states + hide-when-empty on a telemetry-less season. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The x-axis plotted the integer day, so multiple intra-day buckets collapsed
onto one column and the line drew vertical stacks instead of a real time
series. Use continuous (fractional) day-into-war anchored to war_start, and
switch the line from monotone to linear so sharp changes read as honest cliffs
rather than smoothed curves.
- buildPlayerLine: `warStart` param; fractional `dayInto` x for points + dots
- PlayersOverTimeChart: declares `warStart`, line type="linear"
- ArchivesClient: passes `warStart={data?.war_start}`
- tests: fractional-x dot, intra-day-distinct-x regression, warStart anchor
Verified: lint, typecheck, test:unit (1516), build; DevTools on S157 — x is
strictly increasing, no vertical collapse.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Show a tick for every day (D0…D<last>) instead of the ~5 auto-thinned ticks, and anchor the axis 0-based to war_start so the day labels match Conquest Progress for side-by-side reading. The line stays time-proportional (continuous fractional x); only the tick set and base changed. - buildPlayerLine: 0-based dayInto (drop the +1) - PlayersOverTimeChart: explicit ticks=[0..lastDay], domain=[0, lastDay] - tests updated to the 0-based convention Verified: lint, typecheck, test:unit (1516), build; DevTools S157 shows D0…D40.
Two fixes for the players-over-time chart and its comparability with Conquest Progress (FactionHealthChart): 1. Tooltip was stuck on one event regardless of cursor. It read the dots Scatter (a separate data array from the line), whose payload doesn't follow the active index. Rewrote it to read the LINE series + active `label` — showing "Day N · M players" at the hovered point, with the event details appended when an event sits on that day. 2. Conquest Progress used a category x-axis (one slot per snapshot, not time-proportional, duplicate day labels). Gave it the same continuous, 0-based, time-proportional day axis as players-over-time, and a SHARED day-domain (warDayMax, passed to both) so the two charts line up day-for-day. - FactionHealthChart: fractional 0-based day, type=number XAxis, all-day ticks, warStart + domainMax props; ChartTooltip rounds the day. - PlayersOverTimeChart: PlayerTooltip reads line+label+event; domainMax prop. - ArchivesClient: computes warDayMax, passes warStart+domainMax to both charts. - Tests: FactionHealthChart intra-day fractional-day regression. Verified: lint, typecheck, test:unit, build; DevTools — both axes D0-based, time-proportional, shared [0,44] domain; tooltip reads the hovered line point.
Clicking a cascade card pins a persistent faction-tinted highlight over all its events and scrolls the event log to it, hash-driven for shareability. Design corrected by a 5-way model debate and grounded against the code, then adversarially self-reviewed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cursor The players-over-time tooltip froze past the first few days. The <Scatter> held its OWN short data array (~25-78 dots) inside a ComposedChart whose single activeTooltipIndex sweeps the ~600-point line; past the scatter's indices recharts clamped the index and froze the tooltip. Conquest Progress never broke because all its series share one data array. Render events as <ReferenceDot> markers (non-data decorators) instead of a Scatter, so the Line is the SOLE tooltip data source — like Conquest. The tooltip now reports the player count (+ event) at every hovered day. Root cause + fix from a four-way debate (Opus/Sonnet/Codex/Gemini): unanimous on the cause, 3/4 on ReferenceDots over Gemini's unified-data merge. Verified: lint, typecheck, test:unit, build; DevTools differential sweep — Players now tracks D6/186 → D28/168 → D34/166, identical behaviour to Conquest.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t hash via replaceState
Cascade → event-log deep-linking on /archives: clicking a cascade card pins a persistent faction-tinted highlight across all of its events and scrolls the event log to the topmost one (sort-agnostic, JS scrollIntoView), shareable via a URL hash that rehydrates on direct load and back/forward. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Auto-generated War Narrative section on /archives (#274): a collapsible, hide-when-empty in-world chronicle of each season's campaign in the Ministry of Truth's voice, built chronologically from event data. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Players Over Time chart on /archives (replaces the Player Engagement scatter): a per-war player-count line driven by the faction toggle, with event dots and a shared day x-domain. getCampaign gains an additive playerTimeseries field from h1_statistic; section hides for pre-telemetry seasons. Resolved ArchivesClient (combined with cascade + war-narrative) and CHANGELOG conflicts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Faction introduction markers in the /archives Event Log (#157): synthetic 'faction enters the war' dividers interleaved chronologically among event rows, faction-colored, archives-only via a new opt-in EventLog introMarkers prop. Resolved EventLog.css + EventLog.test.jsx conflicts with the cascade highlight work (kept both); EventLog.jsx + ArchivesClient auto-merged cleanly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pecheck) The faction-intro-viz merge brought a formal @param typedef for EventLog that predated the cascade highlightedKeys prop, so tsc rejected highlightedKeys. Documenting the prop restores typecheck. No behavior change.
Replace the chevron <details>/<summary> toggle with the shared primary Button (yellow border, square) reading SHOW when collapsed / HIDE when expanded. The Ministry subtitle now stays visible whether collapsed or expanded; only the beats list toggles. DevTools-verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Four features (seeded phrasing, player surge/collapse, territory turning-points, war-by-numbers) computed server-side so getCampaign stays untouched. Grounded against the code; covers perf + page-impact. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
points/points_max is Super Earth's OFFENSIVE conquest progress (high = SE winning), not enemy pressure — verified vs computeMapState + HD1 API docs. The inverted 'darkest hour' is replaced with correct offensive conquest milestones (breakthrough / first homeworld falls), non-redundant with the cascade beats. Added a coherence/adjacency guard for the new highlight beats. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
War Narrative SHOW/HIDE primary Button + always-visible Ministry subtitle. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8 TDD tasks: 4 pure beat-generator modules + getSeasonTelemetryTotals query + buildWarNarrative orchestrator (phrasing + coherence guard) + server wiring + changelog. Grounded against the code; Task 6 loosens the existing test's variant-sensitive assertions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
buildConquestBeats was computing day as Math.floor(time/86400), treating snapshot.time as a day number when it's actually an absolute unix timestamp (~1.7e9). Other beats in the feature use war-start-relative day numbering. Added warStart parameter and fixed dayOf helper to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Type array with literal unions to preserve kind discriminants through contextual typing. Add null guards in dedupe condition for TS narrowing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…; correct guard docs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
War Narrative enrichment on /archives: deterministic per-season phrasing variety, player surge/collapse beats, offensive conquest milestones, and a war-by-numbers telemetry beat — all computed server-side so getCampaign and the rest of the app stay untouched. Brainstormed + 5-way-reviewed (feature 3 corrected from an inverted territory reading), built TDD via subagents, DevTools-verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v0.65.0
Promotes
develop→mainfor the v0.65.0 production release.mainwas last released at v0.60.0; this bundles six versions of/archivesenhancements (43 commits).Highlights (0.61.0 → 0.65.0)
getCampaignand the rest of the app are untouched.getCampaigngains an additiveplayerTimeseriesfield.Verification
develop: lint clean, typecheck clean, 1572 unit tests passing,next buildOK, DevTools-verified.Post-merge release steps (project workflow)
v0.65.0on themainmerge commit and push it — the production Docker build triggers only on version tags.mainback intodevelopso the next release PR doesn't trip the "branch not up to date" check.🤖 Generated with Claude Code