Record what shipped, and what is still only believed

STATUS was written before the deploy and still asked for a VACUUM that has
since been run. Replaces that with what was actually verified against the
running service, and with the two things a next session would otherwise have
to rediscover.

The post-vacuum sizes were never measured, so the projection stays a
projection; the query to settle it is in the file. And the scroll gap is
promoted from a footnote to the one real open item, because re-reading that
path after shipping found a bug in it -- which is the argument that reading it
again is not the fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Dvvqn9ZDR4ixeFPHNbww7
This commit is contained in:
parththakkar106
2026-08-17 15:26:29 +05:30
co-authored by Claude Opus 5
parent 39296d1b44
commit 1030a7f234
+38 -18
View File
@@ -18,23 +18,30 @@ project page points at (`docs/index.html`), not the service name in the blueprin
--- ---
## Needs a human: one VACUUM after the next deploy ## Shipped and live, 2026-08-17
Migration 43 compresses `context_snapshot`, and **Postgres does not hand the disk back PRs #1 and #2 are merged and deployed. Verified against the running service:
on its own.** `DROP COLUMN` only marks a column dropped, and the backfill leaves a dead `/api/health` 200, the adventure payload carries `action_count`, `/actions` returns
tuple per row, so `actions` gets *bigger* before it gets smaller — peaking near twice `{actions, total, has_more}` and accepts `before_id`. The app booting at all is proof
its size while both columns are live. Once the deploy is up and healthy, run once: migrations 42–45 ran — `bootstrap()` executes at import, so a failed migration means no
service. The deployed JS bundle hashes to `index-4vjcKxkv.js`, which is what this tree
builds, so the frontend live is exactly this code.
`VACUUM FULL actions;` has been run. **The post-vacuum sizes were never measured** —
worth one query next session, and the only reason to touch production again:
```sql ```sql
VACUUM FULL actions; SELECT pg_size_pretty(pg_database_size(current_database())),
pg_size_pretty(pg_total_relation_size('actions'));
``` ```
It needs exclusive access to the table and free space equal to the finished copy. On Projection was ~53 MB total against a 512 MB tier, from 99.6 MB. If it did not land
the 2026-08-17 figures: 99.6 MB now, peaking near 200 during the migration, settling near that, the vacuum did not reclaim what it should have and that is worth knowing
around 53 afterwards, against a 512 MB tier. Skipping it is safe and simply leaves the before the tree adds columns to `actions`.
win unrealised — the database keeps working, it just stays large.
Same caveat applies to migration 42 dropping `memories.embedding` (4 MB). **Aggregates only, and ask first.** Real users are on this database. Counts,
`octet_length` sums and catalog sizes answer every sizing question this project has
needed; nothing requires reading a row of anyone's story.
--- ---
@@ -132,6 +139,11 @@ Everything left open in `plan/13` closed, plus two bugs that fell out of doing i
| `context_snapshot` on disk | ~89 MB | ~43 MB (3.5x, after a VACUUM) | | `context_snapshot` on disk | ~89 MB | ~43 MB (3.5x, after a VACUUM) |
| database total | 99.6 MB | ~53 MB projected | | database total | 99.6 MB | ~53 MB projected |
**One follow-up after the merge** (PR #2). Prepending older actions changes `actions`,
and the bottom-pinning effect watches `actions` — so unless a scroll had already
un-pinned the view, loading earlier turns jumped to the newest one instead. A prepend
now clears the pin explicitly. Found by re-reading the path, not by running it.
**The story is a window now.** `GET /adventures/{id}` returns the newest 60 actions and **The story is a window now.** `GET /adventures/{id}` returns the newest 60 actions and
`action_count`; older pages come from `GET /{id}/actions?before_id=`. Anchored on an `action_count`; older pages come from `GET /{id}/actions?before_id=`. Anchored on an
action, never an offset — an offset counted back from the newest shifts every older action, never an offset — an offset counted back from the newest shifts every older
@@ -211,15 +223,23 @@ with `pg_total_relation_size`, and do not mix them up.
## `plan/13` is closed ## `plan/13` is closed
All six of its open items landed on 2026-08-17. What is left is not from that plan: All six of its open items landed on 2026-08-17, and are live. What is left is not from
that plan:
- **The VACUUM**, above. Until it runs, the storage win is on paper. - **Nothing has ever exercised the scroll in a browser.** This is the one real gap, and
- **Nothing verifies the scroll behaviour in a browser.** The paging is covered by it has already cost something: re-reading that path after shipping turned up a bug
`tests/test_action_paging.py` and was exercised against a running backend, but the where loading earlier turns scrolled *past* them to the end of the story, worst on
frontend has no test runner and the prepend-and-restore is the part most likely to the short-window case the button exists for (fixed, PR #2). One bug found by reading
feel wrong. Worth thirty seconds of scrolling a long adventure before trusting it. means reading is not a substitute. Either scroll a long adventure by hand, or add a
vitest + jsdom harness — that would have caught this one. jsdom has no layout, so the
scroll-position arithmetic still needs eyes.
- **`ACTION_PAGE = 60` is a guess.** It should be a page or two of reading. If loading - **`ACTION_PAGE = 60` is a guess.** It should be a page or two of reading. If loading
older turns feels like it interrupts, that is the number to move. older turns feels like it interrupts, that is the number to move
(`routers/adventures.py`).
- **Post-vacuum sizes unmeasured**, above.
- **Anyone who switched embedding models has a stale bank.** The bug is fixed, but
those memories only re-embed as the post-turn pass reaches them, which costs an
embedding call each. Nothing forces it; playing does.
Deliberately not taken: moving `context_snapshot` out of the database entirely Deliberately not taken: moving `context_snapshot` out of the database entirely
(compressing it bought the same runway for a much smaller change), and pgvector (breaks (compressing it bought the same runway for a much smaller change), and pgvector (breaks