Creative ideas + design notes
Commits with substantial prose (≥120 chars) — the rationale behind each move.
955b609 · 2026-09-10 · TK-11231: archive + clear the 7 superseded vendor drafts
Steve 2026-09-10 'approve all 4, ungate and run'. Same discipline as the 13:
full bodies archived before deletion, since Gmail drafts.delete has no Trash.
7/7 deleted, 0 failures; the 5 READY vendor asks verified untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
584f7f4 · 2026-09-10 · Prove the snapshot actually restores — restore.mjs, rehearsed end to end
A snapshot nobody has replayed is a claim, not a backup. Same lesson as
dw-restore-rehearsal, which exists because a pg_dump ran green for 12 days while
producing output that would not restore. Codex flagged the same gap here.
restore.mjs replays a snapshotted body back into Gmail as a NEW draft. It can
only create drafts, so it structurally cannot deliver mail. Dry-run by default.
Rehearsed three times against live Gmail, recipient redirected to an internal
address so no real vendor draft was duplicated. Result: the recipient-visible
message round-trips byte-identical (516 == 516 chars). The only delta is
George's provenance banner carrying the restore timestamp, which is correct.
The rehearsal caught a real defect: restore was NOT idempotent. George prepends
a 'From job:' banner to every draft it creates, so each restore stacked another
one. The first strip attempt failed because the banner is a styled <div>
wrapping <strong>From job:</strong> — matching the bare phrase left the wrapper
behind. Now strips the whole leading div block; verified 1 banner in, 1 out.
All three rehearsal drafts deleted; info@ is back to its exact 41-draft baseline.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3fb2245 · 2026-09-10 · TK-11231: archive + delete the 13 stale customer replies per Steve's call
Steve answered the gated question directly on 2026-09-10: delete all 13,
overruling the DTD panel's send-all recommendation. His original 09-04
instruction stands.
Archived every draft's full body, recipient, subject and date BEFORE deleting
(data/archive/), because Gmail drafts.delete is permanent with no Trash. The
Gmail artifacts are gone; the content is not. Snapshot-first is house practice
for any irreversible delete.
Scope was held exactly to the 13 he named: the 5 READY vendor asks, the 7
superseded vendor drafts, and the 2 info@ drafts he chose to let expire were
all left untouched. steve-office 136 -> 123, info 41 unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
f7ed61f · 2026-09-10 · Rebuild the board around Steve's 2026-09-10 decisions — send 7, keep 13, 7 inert
The old board was split ready/delete, which no longer matches reality: Steve
ruled send-both-fuse-drafts + send-all-5-vendor-asks, 'put in drafts' for the 13
customer replies, and that HE clicks Send in Gmail. So the board is now grouped
by action and it neither sends nor deletes anything.
- build-board.mjs derives every age from Gmail's own internalDate in the
snapshot rather than a hand-typed number, so the fuse cannot silently drift.
It reads 3d (bmwallpaper) and 4d (Kravet) until permanent deletion.
- The two fuse drafts were never on the old board at all; they are now the
first thing on the page.
- Cards carry the created date+time chip and a snapshot marker, so it is
visible at a glance that the text survives even if Gmail loses the draft.
Verified: 401 gate healthy, 200 authed, 7/13/7 cards, 27 date chips, rendered
in a real browser.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
b443b7c · 2026-09-10 · Snapshot every tracked draft body to disk — deletion is no longer irreversible
com.steve.george-drain-old-drafts calls Gmail drafts.delete, which has no Trash,
so every decision on TK-11231 was previously one-way. 27/27 live drafts are now
captured on disk, including both info@ drafts on the ~4-day permanent-delete fuse.
Caught two bugs in the snapshot itself before trusting it:
- The two George routes name the body field differently (/api/messages/:id ->
body, /api/info/messages/:id -> bodyHtml/bodyText). Reading only `body`
returned '' for all 5 info@ drafts with a 200 OK.
- 'Wrote a file' was being counted as 'saved'. An empty body now counts as a
failure, so the report cannot read green while capturing nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
20c1dc8 · 2026-09-10 · draft-viewer: make the board honest — verify triage against live Gmail — TK-11231
The board was serving a frozen 2026-09-04 snapshot and had started to LIE: one
listed draft (info@ 'Newmor 2026 Cost List') had already been permanently
deleted by com.steve.george-drain-old-drafts, but rendered as still actionable.
refresh.mjs was broken two ways: it called /api/gmail/list (no such route — the
real ones are /api/search and /api/drafts) and grepped GEORGE_BASIC_AUTH_PASS
out of secrets-manager/.env, where that key does not exist (verified) — hence
the 401 the prior session hit and could not explain.
It also had a design flaw worth more than the bugs: it rebuilt drafts.json from
a flat API list, which would have OVERWRITTEN the READY-vs-DELETE triage with
raw data. That classification is judgement and is not derivable from Gmail — it
is the only thing the viewer is for. Now it PRESERVES the triage and refreshes
LIVENESS instead, and on a fetch failure it exits without touching the file
rather than marking everything gone (a false all-clear beats no board — never
show a false empty).
Viewer renders x.live===false as a struck-through, dimmed card with a GONE
badge, plus a 'verified <time>' stamp — and says NOT VERIFIED in red when the
data has never been checked, so staleness is visible rather than implied.
Verified live: 5 ready, 21 delete, 1 GONE, auth gate returns 401 unauthenticated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTxE4MgnygQ9EY2rPZvtcK
e93ef88 · 2026-09-04 · Draft triage viewer — 5 ready to send, 21 to delete, deep-linked to Gmail
Basic-auth board over the unsent agent-composed drafts found in TK-11231.
Green = ready to send (with the catalog gap each one closes), red = delete,
amber = the 13 stale customer replies. Density slider + created-time chip per
the standing admin-card rules. Snapshot in data/drafts.json; refresh.mjs will
repopulate once George's list endpoint auth is sorted (currently 401).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwSKeavk6pXdx4CymWBXmz