Draft Viewer

repo: ~/Projects/draft-viewer · 7 commits · 0 in last 24h, 0 in last 7d ·

Search the build

7 commits indexed

  1. 955b609 2026-09-10 TK-11231: archive + clear the 7 superseded vendor drafts
  2. 584f7f4 2026-09-10 Prove the snapshot actually restores — restore.mjs, rehearsed end to end
  3. 3fb2245 2026-09-10 TK-11231: archive + delete the 13 stale customer replies per Steve's call
  4. f7ed61f 2026-09-10 Rebuild the board around Steve's 2026-09-10 decisions — send 7, keep 13, 7 inert
  5. b443b7c 2026-09-10 Snapshot every tracked draft body to disk — deletion is no longer irreversible
  6. 20c1dc8 2026-09-10 draft-viewer: make the board honest — verify triage against live Gmail — TK-11231
  7. e93ef88 2026-09-04 Draft triage viewer — 5 ready to send, 21 to delete, deep-linked to Gmail

Authors

Agents used

  • secrets-manager1

Skills used

  • /messages2
  • /drafts2
  • /claude2
  • /code2
  • /strong1
  • /archive1
  • /delete1
  • /info1
  • /gmail1
  • /list1
  • /search1

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

File tree

39 files tracked. Click any to browse the source at HEAD.

Other build journals

← Dot Palette  ·  all 4 projects  ·  Dtd Approval Viewer →

Export

commits.csv · feed.atom · project.json · commits.json

rendered in 1ms