docs: specify the changelog, and source the first built-in tasks

The changelog has two tiers, each tied to git: short entries shown after
a reload, and release notes summarised from the history and specs.
Ridu Weekly (1,300) and the Weekly Routine (10) are now sourced. The
first guesses of 2,100 and 10 were checked against the owner's links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-13 14:02:16 +02:00
1 parent 5a4c746a44
commit 114a39867a
2 files changed
+131 -2

No files matched your search

@@ -0,0 +1,121 @@
# In-app changelog
**Date:** 2026-10-13
**Status:** approved; spec 3. Independent of specs 1 and 2, and announces them.
## Request and intended outcome
The owner wants the app to say what has changed: short summaries of updates, and a fuller record a
reader can browse. Two tiers, both tied to git:
- **Short entries** — one reader-facing line each, shown as **What's new** after a new version
loads. Each carries the commit it shipped in and its date.
- **Release notes** — a few summarised paragraphs per feature or milestone, written from the git
history and the spec documents: less than git's detail, more than a one-liner. Each carries the
commit range it covers, its date, and the specs it summarises. The footer's **Changelog** lists
them.
Coverage: **new features and fixes**, and **games and sources** (a game added, a source retired, a
reset clock corrected). Not data refreshes — the footer already states the data's age, and they
happen twice a day.
## Decisions taken
| Question | Answer |
|---|---|
| Who writes entries? | A person or an agent, at development time, in reader-facing language. Never an LLM at runtime (AGENTS.md constraint 2) |
| Where do they live? | In the app bundle, `src/shared/changelog.ts`. Works offline; ships with the version it describes |
| When does What's new show? | After the reload, in the new version. The update notice (F14) is unchanged |
| Who sees What's new? | Readers with unseen entries. A brand-new reader is marked up to date at first run |
| Existing readers when this ships | Shown the entries of the last 14 days once, so the launch is announced |
| Git link | Commit and compare links on `REPO_URL` (the public GitHub mirror) |
| Data refreshes, notifications | Out of scope |
## Model — `src/shared/changelog.ts`
Zod as the source of truth:
```ts
const Ref = z.string().regex(/^[0-9a-f]{7,40}$/); // a commit, abbreviated or full
const Day = z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
const EntrySchema = z.object({
id: z.string().regex(/^[a-z0-9-]{3,60}$/), // stable; what "seen" records
date: Day,
kind: z.enum(["feature", "fix", "games"]), // New · Fixed · Games & sources
title: z.string().min(1).max(90),
body: z.string().max(280).optional(),
ref: Ref, // the commit it shipped in
note: z.string().optional(), // a release note's id
});
const NoteSchema = z.object({
id: z.string().regex(/^[a-z0-9-]{3,60}$/),
date: Day, // the last commit's date
title: z.string().min(1).max(90),
summary: z.array(z.string().min(1)).min(1).max(6), // paragraphs, plain text
from: Ref, to: Ref, // the range it covers
specs: z.array(z.string()).default([]), // repo paths under docs/
});
export const ENTRIES: Entry[]; // newest first
export const NOTES: Note[]; // newest first
```
Pure helpers: `unseen(entries, seenId | undefined, today)` and `launchWindow(entries, today, 14)`;
`commitUrl(ref)`, `compareUrl(from, to)`, `specUrl(path)` built on `REPO_URL`.
A test pins: every entry and note parses; ids are unique; both lists are newest-first; every
`entry.note` names a note; every `note.specs` path exists on disk. **Refs are checked for shape,
not existence** — CI checks out shallowly, so a test asking git would fail there; existence is
checked by `scripts/check-changelog.ts`, run by hand or by the agent writing entries.
## Seen state
`prefs.changelogSeen?: string` — the newest entry id the reader has dismissed. **Absent means
unrecorded**, the `knownGames` distinction again:
- A reader finishing first-run setup gets it set to the newest id: nothing to announce.
- An onboarded reader with it absent (everyone, the day this ships) sees `launchWindow` once.
- Otherwise What's new shows the entries newer than the recorded id.
Dismissing writes the newest id. An id that no longer exists (an entry renamed) falls back to the
launch window rather than replaying everything.
## What the reader sees
**What's new card** — top of the main column, above the lists; never in the rail, which holds
instructions. Eyebrow `What's new`, up to five entries (`New` / `Fixed` / `Games & sources` tag,
title, date), `See all` (opens the changelog) and `Got it`. More than five shows `+ 3 more` inside
See all. Dismissible, never modal, never shown on first run.
**Changelog sheet** — a `What's new` link in the footer beside the existing credits opens a sheet
in the detail sheet's style. Release notes, newest first, each with title, date, summary
paragraphs, `commits from…to` (compare link) and spec links; the short entries a note covers listed
under it with commit links. Entries with no note are listed by month at the end.
## Conventions this adds
AGENTS.md § Conventions gains: **a change a reader can see adds a short entry in the same commit**,
with the ref filled in by a follow-up `chore(changelog)` commit when the change's own hash cannot
be known in advance (a commit cannot contain its own hash). A feature that spans several commits
gets a release note when it lands, summarising its spec and range.
## Backfill
Entries and notes for reader-visible work since August 2026, written from `git log` and
`docs/superpowers/specs/`: recurring custom events, game order, per-server reset clocks, games
added, check-in goals, weekly and monthly tasks, this changelog.
## Testing
Schema and ordering test above; `unseen`/`launchWindow` pure tests including the absent and
renamed-id cases; the card renders at most five and hides with nothing unseen; the sheet renders a
note with compare and spec links; first-run seeding; `scripts/check-changelog.ts` passes on the
backfill. Browser check of card and sheet, dark and light.
## Docs that change with it
PRD: F18 — the changelog; DATA-MODEL: `prefs.changelogSeen`; AGENTS.md: the convention above;
DESIGN.md: the card and the sheet.
@@ -119,8 +119,16 @@ Monday; monthly to the 1st.
- `src/shared/routines.ts`: per-game templates with the same fields plus `source` (URL)
and `checked` (date). **Only a task a cited source documents ships**, the bar
`dailyTasks` in `games.ts` is held to; the owner's examples (ZZZ weekly activity, 2100;
Endfield weekly routine, 10) are the first candidates and are verified, not assumed.
`dailyTasks` in `games.ts` is held to. The owner's first figures (ZZZ 2,100, Endfield 10) were
checked on 2026-10-13 against sources the owner supplied; the first two built-ins are:
| Game | Task | Measure | Week | Source (as checked) |
|---|---|---|---|---|
| ZZZ | Ridu Weekly | 1,300 points (last milestone) | Monday, at reset | game8.co/games/Zenless-Zone-Zero/archives/484723 (updated 2025-12-02) |
| Endfield | Weekly Routine | 10 points (last milestone; unlocks at Authority Level 15) | Monday, at reset | endfield.wiki.gg/wiki/Weekly_Routine (edited 2026-04-11) |
The Game8 page is ten months old; its figure ships with its `checked` date shown, so a stale
number is visibly dated rather than presented as current.
- **Asking.** When a game with built-ins becomes visible — first-run picker, or switched on
in settings — and is not in `routinesAsked`, a one-line card at the top of the dailies
strip asks: `Track Zenless Zone Zero's weekly and monthly tasks? Yes · No thanks`. Either