Skip to content

Fix Optimize Earth root row showing zero delay metrics#81

Merged
mikepsinn merged 1 commit into
mainfrom
feature/optimize-earth-root-delay-stats
May 16, 2026
Merged

Fix Optimize Earth root row showing zero delay metrics#81
mikepsinn merged 1 commit into
mainfrom
feature/optimize-earth-root-delay-stats

Conversation

@mikepsinn
Copy link
Copy Markdown
Owner

@mikepsinn mikepsinn commented May 14, 2026

Summary

  • Root Optimize Earth managed task was missing dueAt, so getTaskDelayStats returned currentDelayDays = 0 and the /tasks row showed $0 wasted / 0 deaths-from-delay even though the per-day rates were wired correctly.
  • Set dueAt = 2024-12-31 to match END_WAR_AND_DISEASE_TASK_ID so parent and child agree on "we should be done by now."
  • Added optimize-earth-task-tree.test.ts as a data-shape regression guard.

Bundled

  • TODO entries from this triage cycle: share-templates.ts as the canonical source for all reminder copy; ICEWADIC2EWD rename plan; impact-inheritance design decision (don't inherit by default — inheritance creates double-counting when aggregating); column hiding on task tables when no row has a value; unify "Your Tasks" empty state with the task-row component.
  • pr-comment-triager agent: post per-comment replies on bot threads instead of one summary, so it's obvious every bot comment was addressed when scrolling the PR.

Test plan

  • pnpm --filter @optimitron/db test — 137/137 passing (12 files; new test file included).
  • After preview deploys, visit /tasks and confirm the Humanity's Tasks → Optimize Earth row shows non-zero "Wasted By Delay" and "Deaths From Delay".

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests

    • Added tests guarding task root/due-date behavior and redirect regressions.
  • Bug Fixes

    • Root task due date set so delay/cost metrics display correctly.
  • New Features

    • Smart copy-preview to regenerate only affected pages.
    • Permanent redirects for legacy /find-trials traffic.
  • UI

    • Voting flow simplified (aggregate counts removed).
    • Sign-in wording changed to “sign-in link”.
    • Email font size and signature avatar updated; “direct reports” relabeled “employees”.
  • Chores

    • Added developer hooks, pre-commit checks, and many planning/ops docs.

Review Change Stack

Copilot AI review requested due to automatic review settings May 14, 2026 17:26
@vercel
Copy link
Copy Markdown

vercel Bot commented May 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
optimitron-web Ready Ready Preview, Comment May 16, 2026 7:02pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR updates agent and CLAUDE guidance, adds local hook scripts and dev-server checks, improves copy-preview tooling, adjusts seed data and tests (Optimize Earth and legacy grant keys), simplifies a referendum vote component, adds host-scoped redirects with tests, and expands TODOs and plan documents.

Changes

Primary changes

UI copy & small component edits

Layer / File(s) Summary
Email styles & avatars, promotion copy, signin page, dashboard header
packages/web/src/components/adaptive/email-styles.ts, packages/web/src/lib/email/wishonia-signature.ts, packages/web/src/lib/humanity-manager-promotion-content.tsx, packages/web/src/app/auth/signin/page.logged-out.md, packages/web/src/components/dashboard/EarthOptimizationDashboardClient.tsx
Increase email small-muted paragraph font-size to 14px; swap Wishonia avatar to happy-smile.png; rename “direct reports” → “employees” in promotion/email copy and fixtures; add logged-out signin markdown; simplify dashboard header and adjust useSession import.

Plans & TODOs

Layer / File(s) Summary
Deploy smoke-tests plan
.claude/plans/smoke-tests-preview-and-prod.md
Adds a deploy-smoke plan: decision summary, ASCII diagrams, step list, risks, and Codex critique for preview/prod post-deploy checks.
Printable posters plan
.claude/plans/printable-signs-posters.md
Adds /poster printable campaign plan with routing, QR/OG reuse, print/CSS decisions, implementation checklist, and critique.
Apocalypse framing standardization
.claude/plans/apocalypse-framing-standardization.md
Expands research, proposed shared-prose module shape, replacement table, step list, and Codex critique/decisions.
Task impact backfill plan
.claude/plans/task-impact-backfill.md
Detailed backfill proposal with diagrams, steps, test guidance, risks, and extensive Codex critique.
Email template audit plan
.claude/plans/email-template-audit.md
Adds audit/migration plan to centralize share templates in SHARE_TEMPLATES, with step list, files-to-touch, and critique.

Estimated code review effort: 🎯 3 (Moderate) | ⏱️ ~20 minutes

"I hopped through docs and hooks tonight,
made codex pause and plans take flight.
I checked the files and citation trails,
then softly blocked the hasty sails.
A rabbit cheers as linting wins the fight." 🐇✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/optimize-earth-root-delay-stats

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes delay-metric rendering for the root “Optimize Earth” managed task by ensuring it has a non-null dueAt, so delay-derived stats (wasted-by-delay, deaths-from-delay) no longer compute to zero on /tasks.

Changes:

  • Set a concrete dueAt on the Optimize Earth root managed task to make it “overdue” for delay-metric calculations.
  • Added a regression test to guard the managed-task data shape for the Optimize Earth root.
  • Updated internal triage documentation and the repository TODO list with follow-up items.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
TODO.md Adds triage-cycle TODOs and a rename plan note.
packages/db/src/managed-data/optimize-earth-task-tree.ts Sets dueAt on the Optimize Earth root task (and documents the motivation).
packages/db/src/managed-data/optimize-earth-task-tree.test.ts New regression test asserting the root task exists and has an overdue dueAt.
.claude/agents/pr-comment-triager.md Updates bot-comment triage instructions to reply per-thread/per-comment.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/db/src/managed-data/optimize-earth-task-tree.ts Outdated
Comment thread packages/db/src/managed-data/optimize-earth-task-tree.ts Outdated
Comment thread packages/db/src/managed-data/optimize-earth-task-tree.test.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/db/src/managed-data/optimize-earth-task-tree.test.ts (1)

19-22: ⚡ Quick win

Consider checking exact dueAt value instead of using Date.now().

While the current check is unlikely to be flaky (the date is well in the past), testing guidelines discourage using Date.now() in assertions. A more explicit check against the expected value would be more robust and self-documenting.

♻️ Proposed refactor
-  it("has an overdue dueAt so the root row shows non-zero cost of delay", () => {
-    expect(root?.dueAt).toBeInstanceOf(Date);
-    expect(root?.dueAt!.getTime()).toBeLessThan(Date.now());
+  it("has dueAt set to 2024-12-31 (overdue) so the root row shows non-zero cost of delay", () => {
+    expect(root?.dueAt).toEqual(new Date("2024-12-31T00:00:00.000Z"));
   });

This verifies both that the date exists AND that it's the expected value, making the test more precise.

As per coding guidelines, tests should avoid Date.now() in assertions to prevent flakiness.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/src/managed-data/optimize-earth-task-tree.test.ts` around lines
19 - 22, The test currently asserts root?.dueAt is in the past using Date.now(),
which is discouraged; instead assert the exact expected timestamp/value for
root?.dueAt to make the test deterministic—locate the assertion in
optimize-earth-task-tree.test.ts that references root?.dueAt and replace the
Date.now() comparison with a check against the known expected Date or timestamp
(e.g., compare to a specific Date string or numeric epoch value) while still
ensuring the value is an instance of Date via the existing
expect(root?.dueAt).toBeInstanceOf(Date) check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/db/src/managed-data/optimize-earth-task-tree.ts`:
- Around line 66-72: The comment above the hard-coded dueAt date incorrectly
references END_WAR_AND_DISEASE_TASK_ID; update the comment to reference
TREATY_PARENT_TASK_ID (which contains the matching 2024-12-31 dueAt) so the
explanation correctly points to the matching task; ensure you keep the existing
rationale about getTaskDelayStats/currentDelayDays and that the date matches
TREATY_PARENT_TASK_ID.

---

Nitpick comments:
In `@packages/db/src/managed-data/optimize-earth-task-tree.test.ts`:
- Around line 19-22: The test currently asserts root?.dueAt is in the past using
Date.now(), which is discouraged; instead assert the exact expected
timestamp/value for root?.dueAt to make the test deterministic—locate the
assertion in optimize-earth-task-tree.test.ts that references root?.dueAt and
replace the Date.now() comparison with a check against the known expected Date
or timestamp (e.g., compare to a specific Date string or numeric epoch value)
while still ensuring the value is an instance of Date via the existing
expect(root?.dueAt).toBeInstanceOf(Date) check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b44ad747-9c88-41dd-b7c9-513b077a2dcd

📥 Commits

Reviewing files that changed from the base of the PR and between 48352f9 and b72009f.

📒 Files selected for processing (4)
  • .claude/agents/pr-comment-triager.md
  • TODO.md
  • packages/db/src/managed-data/optimize-earth-task-tree.test.ts
  • packages/db/src/managed-data/optimize-earth-task-tree.ts

Comment thread packages/db/src/managed-data/optimize-earth-task-tree.ts
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 14, 2026

Preview deploy — one-click review links

Latest preview: https://optimitron-bvvwyorlm-mike-p-sinns-projects.vercel.app

Page State What changed
/ logged-out components/landing/TreatyPostVoteShareFlow.tsx, components/landing/TreatyVoteFlow.test.tsx, components/landing/TreatyVoteFlow.tsx, components/landing/TreatyVoteSection.tsx (+2 more)
/about logged-out app/about/page.tsx
/agencies logged-out app/agencies/page.tsx
/auth/signin logged-out app/auth/signin/page.tsx
/court logged-out app/court/page.tsx
/dashboard demo logged-in components/dashboard/DashboardShareCard.tsx, components/dashboard/EarthOptimizationDashboardClient.tsx, components/dashboard/HumanityManagerStatusPanel.test.tsx, components/dashboard/HumanityManagerStatusPanel.tsx (+1 more)
/declaration logged-out app/declaration/page.tsx
/donate logged-out app/donate/page.tsx, components/donate/DonationCalculationNarrative.tsx, components/donate/DonationImpactCalculator.tsx
/endorse logged-out app/endorse/page.tsx
/fund logged-out app/fund/page.tsx
/governments logged-out app/governments/page.tsx
/humanity-v-government logged-out app/humanity-v-government/page.tsx
/organizations demo logged-in app/organizations/[id]/page.tsx, app/organizations/page.tsx
/people logged-out app/people/[id]/page.tsx, app/people/page.tsx
/plaintiffs logged-out app/plaintiffs/page.tsx
/plaintiffs/manage demo logged-in app/plaintiffs/manage/page.tsx
/poster logged-out app/poster/page.tsx
/scoreboard logged-out app/scoreboard/page.tsx
/search logged-out app/search/page.tsx
/signatories logged-out app/signatories/page.tsx
/survey logged-out app/survey/[organizationSlug]/page.tsx
/treaty logged-out components/referendum/ReferendumSignatureBox.test.tsx, components/referendum/ReferendumSignatureBox.tsx, components/referendum/ReferendumStepper.tsx, components/referendum/ReferendumStepperPage.tsx (+5 more)
/vote logged-out components/referendum/ReferendumSignatureBox.test.tsx, components/referendum/ReferendumSignatureBox.tsx, components/referendum/ReferendumStepper.tsx, components/referendum/ReferendumStepperPage.tsx (+1 more)

?login=demo signs you in as the demo user; ?logout=1 clears the session. Updated automatically when this PR's preview deploys.

@claude
Copy link
Copy Markdown

claude Bot commented May 14, 2026

Code review

Two CLAUDE.md violations found:

1. Flaky test: real wall clock in assertion

File: packages/db/src/managed-data/optimize-earth-task-tree.test.ts, line 21

Date.now() is banned in assertions per CLAUDE.md Testing Rules:

No real wall clock — inject now or use vi.setSystemTime
No Math.random, Date.now, crypto.randomUUID in assertions

Fix: replace Date.now() with a fixed reference date:

expect(root?.dueAt!.getTime()).toBeLessThan(new Date("2026-01-01").getTime());

2. Magic number: inline date literal duplicated without a named constant

File: packages/db/src/managed-data/optimize-earth-task-tree.ts, lines 72 and 273

new Date("2024-12-31T00:00:00.000Z") is hardcoded twice as a string literal. Per CLAUDE.md Self-Review:

Magic numbers — named constants citing the paper.

Fix: extract to a named constant at the top of the file (e.g. const TREATY_OVERDUE_SINCE = new Date("2024-12-31T00:00:00.000Z")) and reference it in both places.

@argos-ci
Copy link
Copy Markdown

argos-ci Bot commented May 14, 2026

The latest updates on your projects. Learn more about Argos notifications ↗︎

Awaiting the start of a new Argos build…

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/db/src/managed-data/managed-seed-data.ts (1)

1280-1285: ⚡ Quick win

Document the deliberate icewadIC2EWD split.

The ["ice", "wad"].join("") trick is meaningful — it preserves the legacy icewad-* / icewad:* DB keys (existing rows, idempotent upserts) while letting the new TypeScript identifiers move to IC2EWD_* as part of the bundled rename plan. Without a one-line comment that intent is invisible: the next reader will assume the array-join is accidental and "fix" it back to a string literal, which would re-introduce the very identifier the rename is removing.

Also consider hoisting IC2EWD_GRANT_DALYS_PER_USD / IC2EWD_GRANT_ECON_VALUE_PER_USD to module scope (they're pure constants and the description prose at line 1361–1364 quotes the same 565 DALYs / $1 figure — co-locating them keeps the number and the marketing copy from drifting).

♻️ Suggested clarification
-  const IC2EWD_GRANT_DALYS_PER_USD = 564.972;
-  const IC2EWD_GRANT_ECON_VALUE_PER_USD = IC2EWD_GRANT_DALYS_PER_USD * 150_000;
-  const legacyCampaignKeyStem = ["ice", "wad"].join("");
-  const legacyGrantTaskIdPrefix = `${legacyCampaignKeyStem}-grant`;
-  const legacyGrantTaskKeyPrefix = `${legacyCampaignKeyStem}:grant`;
-  const legacyGrantMethodologyKey = `${legacyCampaignKeyStem}-one-dollar-grant`;
+  // Legacy DB key stem — kept as runtime-constructed "icewad" so existing
+  // task ids, taskKeys, interestTags, and methodologyKey strings round-trip
+  // unchanged across the ICEWAD → IC2EWD identifier rename (see TODO.md).
+  // Do not collapse to a string literal — that re-introduces the identifier
+  // the rename is intentionally removing.
+  const legacyCampaignKeyStem = ["ice", "wad"].join("");
+  const legacyGrantTaskIdPrefix = `${legacyCampaignKeyStem}-grant`;
+  const legacyGrantTaskKeyPrefix = `${legacyCampaignKeyStem}:grant`;
+  const legacyGrantMethodologyKey = `${legacyCampaignKeyStem}-one-dollar-grant`;

As per coding guidelines: "Replace magic numbers with named constants citing the paper" — the named-constant half is now satisfied; a one-line citation to manual.warondisease.org/knowledge/economics/1-pct-treaty-impact.html next to IC2EWD_GRANT_DALYS_PER_USD = 564.972 would close the loop.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/src/managed-data/managed-seed-data.ts` around lines 1280 - 1285,
Add a one-line comment explaining that legacyCampaignKeyStem =
["ice","wad"].join("") intentionally preserves existing DB keys
(icewad-*/icewad:*) while new TypeScript identifiers use the IC2EWD_* naming;
place this comment adjacent to legacyCampaignKeyStem and the related
legacyGrantTaskIdPrefix / legacyGrantTaskKeyPrefix / legacyGrantMethodologyKey
declarations so future editors don't “simplify” the join. Also hoist
IC2EWD_GRANT_DALYS_PER_USD and IC2EWD_GRANT_ECON_VALUE_PER_USD to module scope
(they are pure constants) and add a short citation comment
(manual.warondisease.org/knowledge/economics/1-pct-treaty-impact.html) next to
IC2EWD_GRANT_DALYS_PER_USD to document the source of the 564.972 value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/hooks/dev-server-check.mjs:
- Around line 33-36: The curl call uses a Windows-only "-o NUL"; update the
execSync invocation in dev-server-check.mjs (the const out = execSync(...)
block) to compute a platform-aware null device (e.g. const nullDevice =
process.platform === "win32" ? "NUL" : "/dev/null" or obtain platform via
node:os) and substitute that value into the curl command instead of the literal
"NUL" so output is discarded correctly on Unix/macOS and Windows.

In `@CLAUDE.md`:
- Around line 51-52: Trim the snapshot rule in CLAUDE.md to remove the
parenthetical implementation details: keep the core instruction that developers
must not hand-edit page.logged-out.md / *.email.md snapshots and that they
should run the commands `pnpm --filter `@optimitron/web` copy:preview` (or
`copy:preview:all` / `email:preview-md` for emails) to regenerate; delete the
explanatory parenthetical mentioning scripts/affected-routes.mjs and the
static-import walker so the rule is concise and follows the "minimum words"
guideline.

---

Nitpick comments:
In `@packages/db/src/managed-data/managed-seed-data.ts`:
- Around line 1280-1285: Add a one-line comment explaining that
legacyCampaignKeyStem = ["ice","wad"].join("") intentionally preserves existing
DB keys (icewad-*/icewad:*) while new TypeScript identifiers use the IC2EWD_*
naming; place this comment adjacent to legacyCampaignKeyStem and the related
legacyGrantTaskIdPrefix / legacyGrantTaskKeyPrefix / legacyGrantMethodologyKey
declarations so future editors don't “simplify” the join. Also hoist
IC2EWD_GRANT_DALYS_PER_USD and IC2EWD_GRANT_ECON_VALUE_PER_USD to module scope
(they are pure constants) and add a short citation comment
(manual.warondisease.org/knowledge/economics/1-pct-treaty-impact.html) next to
IC2EWD_GRANT_DALYS_PER_USD to document the source of the 564.972 value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ee7c9705-6604-46f3-a095-3b254c60d8b0

📥 Commits

Reviewing files that changed from the base of the PR and between b72009f and 365539d.

📒 Files selected for processing (19)
  • .claude/codex-delegation.md
  • .claude/hooks/block-codex-rescue-agent.mjs
  • .claude/hooks/block-snapshot-handedit.mjs
  • .claude/hooks/dev-server-check.mjs
  • .claude/settings.json
  • .husky/pre-commit
  • CLAUDE.md
  • TODO.md
  • packages/db/src/__tests__/seed.integration.test.ts
  • packages/db/src/managed-data/managed-seed-data.ts
  • packages/web/package.json
  • packages/web/scripts/copy-preview-smart.mjs
  • packages/web/scripts/soft-delete-funding-tasks.ts
  • packages/web/src/app/humanity-v-government/HumanityVGovernmentVerdictVote.test.tsx
  • packages/web/src/app/humanity-v-government/HumanityVGovernmentVerdictVote.tsx
  • packages/web/src/app/humanity-v-government/page.logged-out.md
  • packages/web/src/app/humanity-v-government/page.tsx
  • packages/web/src/lib/__tests__/redirects.test.ts
  • packages/web/src/lib/redirects.js
💤 Files with no reviewable changes (4)
  • packages/web/src/app/humanity-v-government/HumanityVGovernmentVerdictVote.test.tsx
  • packages/web/src/app/humanity-v-government/page.tsx
  • packages/web/src/app/humanity-v-government/page.logged-out.md
  • packages/web/src/app/humanity-v-government/HumanityVGovernmentVerdictVote.tsx
✅ Files skipped from review due to trivial changes (2)
  • .claude/settings.json
  • packages/web/scripts/soft-delete-funding-tasks.ts

Comment thread .claude/hooks/dev-server-check.mjs
Comment thread CLAUDE.md
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
TODO.md (2)

299-317: ⚡ Quick win

Missing cross-reference to email-template-audit plan.

Lines 299-317 describe the share-templates.ts canonical source directive and the audit task for email modules, but the PR also includes .claude/plans/email-template-audit.md which covers this exact migration.

📝 Recommended cross-reference
 ### `share-templates.ts` is the source of truth for ALL reminder copy
 
 - `packages/web/src/lib/tasks/share-templates.ts` is the canonical voice-variant
   registry: ~26 named templates (Trump versions, office memo, performance
   review, polite reminder, etc.) keyed by `recipientModes`
   (`leader | humanity | one_human | peer`) with token-based interpolation.
 - Today only `TreatyReminderComposer` reads from it. `monthly-chain-digest`,
   `post-vote-share`, `referral-first-conversion`, and `task-comment-notification`
   emails hand-roll their own reminder copy — confirmed for monthly-chain-digest,
   audit needed for the others.
 - Migration: every email module that includes reminder/share copy should pull
   recipient-appropriate templates from `share-templates.ts` (filtered by the
   email's `recipientModes`), interpolate via `renderTemplate`, and pick a
   default variant. Hand-rolled copy stays only when no template fits AND a new
   template would be too narrow to reuse.
-- Audit task: grep all `packages/web/src/lib/email/*.ts` and
-  `*-react-email.tsx` for hardcoded "Sign now"/"Vote"/"You haven't voted yet"-
-  shaped prose and replace with template lookups.
+- Full migration plan at `.claude/plans/email-template-audit.md`.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@TODO.md` around lines 299 - 317, The TODO entry describing share-templates.ts
as the canonical source and the email audit should be updated to reference the
existing audit plan file (.claude/plans/email-template-audit.md); edit the
paragraph that mentions the "Audit task" to add a brief cross-reference pointing
to that plan and note it covers migration steps for modules like
TreatyReminderComposer, monthly-chain-digest, post-vote-share,
referral-first-conversion, and task-comment-notification; mention that modules
should use share-templates.ts (filtered by recipientModes and rendered with
renderTemplate) and defer to the email-template-audit plan for the detailed
migration checklist.

79-216: ⚡ Quick win

Verify cross-reference accuracy for the apocalypse framing plan.

Lines 159-215 describe the "apocalypse" framing standardization work in detail, including candidate phrasings and surface locations. This duplicates content that should live in the plan document at .claude/plans/apocalypse-framing-standardization.md.

The PR includes .claude/plans/apocalypse-framing-standardization.md, which covers the same scope. Keeping parallel copies in both TODO and the plan increases maintenance cost and drift risk.

📝 Recommended consolidation

Replace lines 159-215 with a brief directive pointing to the plan:

-- **Standardize "apocalypse" framing across the project.** Ivy (real-
-  user feedback) said *"a hundred of them ends civilization is a
-  confusing sentence."* The word "apocalypse" treats civilization-
-  ending event as a countable unit, and "122 apocalypses" / "trade
-  one apocalypse" doesn't land for people who haven't been told the
-  causal chain (~100 warheads → nuclear winter → food system collapse
-  → civilizational collapse; we stockpiled ~12,200 → 122x overkill).
-  Pick ONE standardized phrasing, parameter-back it, sweep all
-  surfaces.
-  - **User-facing surfaces to update (one consistent phrasing):**
-    [... 40 more lines ...]
+- **Standardize "apocalypse" framing across the project.** Ivy feedback:
+  "a hundred of them ends civilization" is confusing. Implementation
+  plan at `.claude/plans/apocalypse-framing-standardization.md`.

Keep detailed surface lists and candidate phrasings only in the plan document.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@TODO.md` around lines 79 - 216, Duplicate "Standardize 'apocalypse' framing"
content in the TODO should be consolidated: remove the detailed block that
duplicates the dedicated plan and replace it with a one-line pointer referencing
the separate apocalypse-framing plan (keep candidate labels A/B/C and surface
lists only in that plan), and ensure the TODO contains a short directive like
"See apocalypse-framing-standardization plan for full details" so future readers
are guided to the single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/plans/apocalypse-framing-standardization.md:
- Around line 171-200: The core templates use camelCase tokens (e.g.
NUCLEAR_OVERKILL_FRAMING_TEMPLATES.coreFull with {overkillLayers},
{spareOverkillLayers}, {globalWarheads}) while share-templates.ts and
ShareTokenKey use snake_case, which will break interpolation; fix by making
token casing consistent—preferably convert all template tokens in
NUCLEAR_OVERKILL_FRAMING_TEMPLATES.coreFull and the listed replacement strings
(Footer.tsx, donate/page.tsx, endorse/page.tsx,
DonationCalculationNarrative.tsx, TreatyVoteFlow.tsx,
TreatyPostVoteShareFlow.tsx, managed-task-triggers.ts, managed-grandma-kay.ts,
TreatyTradeThesis.tsx, site.ts keys, routes.ts templates, war-on-disease.json,
one-percent-treaty.ts, SignatoriesLeaderboard.tsx, RepresentedPersonForm.tsx,
ManageRepresentedPeopleClient.tsx, humanity-manager-promotion-content.tsx,
ProgramTaskSection.tsx, share-templates.ts) to snake_case (e.g.
{overkill_layers}, {spare_overkill_layers}, {global_warheads},
{winter_threshold_warheads}, {dfda_years}, {status_quo_years},
{trial_capacity_multiplier}), or alternatively implement a single conversion in
renderNuclearOverkillTemplate to map camelCase→snake_case before rendering;
choose one approach and update tests (one-percent-treaty.test.ts) and regenerate
any generated files instead of hand-editing.

In @.claude/plans/email-template-audit.md:
- Around line 179-253: The plan defers choosing between
`lumbergh-one-human`/`lumbergh` for monthly digest reminders without a decision
criterion; update the checklist in the migration entry for
`monthly-chain-digest-react-email.tsx`/`monthly-chain-digest-email.ts`/`monthly-chain-digest.server.ts`
to either (A) select the variant now (e.g., use `lumbergh-one-human` for
employee reminders and `lumbergh` for president reminders) and note why, or (B)
add a concrete pre-deploy verification step that programmatically checks the
available token set (e.g., via `loadOverduePresidentSnapshot()` or a small
token-building helper) and defines a deterministic fallback to a lower-token
registry variant when required tokens are missing; include the verification task
and expected pass/fail behavior in the checklist so implementers have a clear
rule to follow.

In @.claude/plans/login-form-ux-fixes.md:
- Around line 283-293: Update the verification step to require explicit mobile
viewport dimensions to test the proposed compact spacing in AuthForm.tsx and its
callers (TreatyVoteFlow.tsx and HumanityVGovernmentVerdictVote.tsx);
specifically capture before/after screenshots at these viewports: 360x800 (small
Android), 375x812 (iPhone X/11 Pro), 390x844 (iPhone 12/13), 412x915 (larger
Android), and 768x1024 (portrait tablet) and confirm the submit button remains
above the fold (also note if py-6 sm:py-8 is needed in TreatyVoteFlow.tsx or
mt-4 in HumanityVGovernmentVerdictVote.tsx); include pass/fail result per
viewport in the plan.

In @.claude/plans/task-impact-backfill.md:
- Around line 144-145: Update the task description to explicitly state that only
hierarchy-based inheritance should be removed: say "disable or remove
buildParentInheritedImpactFrame (hierarchy/tree parent inheritance) so tasks
without a direct current estimate render no selected frame", and clearly note
that buildDownstreamUnlockedImpactFrame (edge-based causal modeling using
edge.probabilityDeltaBase and edge.timeDeltaDaysBase) must be preserved and kept
separate; ensure the task text references both functions by name
(buildParentInheritedImpactFrame and buildDownstreamUnlockedImpactFrame) and
instructs verifying that any retained buildDownstreamUnlockedImpactFrame logic
only reflects explicit task edges, not parent hierarchy.

---

Nitpick comments:
In `@TODO.md`:
- Around line 299-317: The TODO entry describing share-templates.ts as the
canonical source and the email audit should be updated to reference the existing
audit plan file (.claude/plans/email-template-audit.md); edit the paragraph that
mentions the "Audit task" to add a brief cross-reference pointing to that plan
and note it covers migration steps for modules like TreatyReminderComposer,
monthly-chain-digest, post-vote-share, referral-first-conversion, and
task-comment-notification; mention that modules should use share-templates.ts
(filtered by recipientModes and rendered with renderTemplate) and defer to the
email-template-audit plan for the detailed migration checklist.
- Around line 79-216: Duplicate "Standardize 'apocalypse' framing" content in
the TODO should be consolidated: remove the detailed block that duplicates the
dedicated plan and replace it with a one-line pointer referencing the separate
apocalypse-framing plan (keep candidate labels A/B/C and surface lists only in
that plan), and ensure the TODO contains a short directive like "See
apocalypse-framing-standardization plan for full details" so future readers are
guided to the single source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2be0036b-2f21-4cfe-8ae8-3f0fec4413c9

📥 Commits

Reviewing files that changed from the base of the PR and between 365539d and e55b344.

📒 Files selected for processing (11)
  • .claude/codex-delegation.md
  • .claude/hooks/codex-dispatch-blather.mjs
  • .claude/hooks/enforce-codex-protocol.mjs
  • .claude/plans/README.md
  • .claude/plans/anonymized-db-preview.md
  • .claude/plans/apocalypse-framing-standardization.md
  • .claude/plans/email-template-audit.md
  • .claude/plans/login-form-ux-fixes.md
  • .claude/plans/task-impact-backfill.md
  • .claude/settings.json
  • TODO.md
✅ Files skipped from review due to trivial changes (1)
  • .claude/plans/README.md

Comment thread .claude/plans/apocalypse-framing-standardization.md
Comment thread .claude/plans/email-template-audit.md
Comment thread .claude/plans/login-form-ux-fixes.md
Comment thread .claude/plans/task-impact-backfill.md
@mikepsinn
Copy link
Copy Markdown
Owner Author

Re: claude[bot] code review flagging @/components/shared/ParameterTemplate as missing — stale. That review was against commit 5ee4534; the component was added in b0e336c (commit immediately after). Verified packages/web/src/components/shared/ParameterTemplate.tsx exists on the current HEAD (d6888f8) and the five importing files resolve. core-validate is now green; web-validate still building on the same head.

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review

Found 7 issues: 1 config defect, 2 test-rule violations, 3 type-safety violations, and 1 style migration violation.

Checked for bugs and CLAUDE.md compliance.

Comment thread .gitignore Outdated
Comment thread packages/db/src/managed-data/optimize-earth-task-tree.test.ts Outdated
Comment thread packages/web/src/lib/jobs/refresh-user-downstream-cache.server.test.ts Outdated
Comment thread packages/web/src/lib/jobs/refresh-user-downstream-cache.server.ts Outdated
Comment thread packages/web/src/lib/dashboard.server.ts Outdated
Comment thread packages/web/src/app/poster/page.tsx Outdated
Comment thread packages/web/src/components/auth/AuthForm.tsx Outdated
mikepsinn added a commit that referenced this pull request May 15, 2026
- Drop unsafe widening cast in dashboard.server.ts; `findUnique` with
  `include` already returns all User scalars including
  `downstreamConversionCount`, so the cast was both unnecessary and a
  type-system lie (it claimed the field might be absent when in fact it
  is present and typed as `number`).
- Export `DownstreamCacheClient` / `DownstreamCacheTransaction` so the
  test can declare its mock against the real interface instead of
  reaching for `as never`. The test's `$queryRaw` is now a typed generic
  method on the mock, no `any` and no `as never`.
- Drop the `as unknown as DownstreamCacheClient` double-cast in the
  source by typing the local `db` variable as the interface directly;
  PrismaClient assigns to it structurally.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
mikepsinn added a commit that referenced this pull request May 15, 2026
The "overdue dueAt" regression test compared `dueAt.getTime()` to
`Date.now()`, which violates the testing rule against real wall-clock
in assertions. The dueAt is a fixed 2024-12-31 anchor; use a fixed
2025-01-01 reference so the assertion can't drift if time freezes,
travels backwards, or the runner clock skews.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

test

@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

Code review

No bugs found. Three CLAUDE.md compliance issues flagged.


Issue 1 — packages/web/src/components/auth/AuthForm.tsx lines 88, 91, 104

Hardcoded color tokens carried forward on modified lines.

These lines change only padding/margin values but carry border-black, bg-white, text-black, and border-neutral-950 forward without migrating to semantic tokens. The new compact branch (line 90) already correctly uses border-foreground bg-background — making the omission in adjacent branches directly visible by contrast.

Per CLAUDE.md Visual Style Rules:

"When touching public UI, remove neobrutalist styling instead of copying it forward."
"Never use: Hardcoded bg-white / text-blackbg-background, text-foreground"

: isDocument
? "w-full border border-black bg-white p-4 text-black shadow-none"
: compact
? "w-full border border-foreground bg-background p-4 shadow-none sm:p-5"
: "w-full border border-neutral-950 bg-white p-5 shadow-none sm:p-6";
const titleWrapperClassName = compact ? "mb-3 text-center" : "mb-4 text-center";

Suggested fix for lines 88–91:

    ? "w-full border border-foreground bg-background p-4 text-foreground shadow-none"
    : compact
    ? "w-full border border-foreground bg-background p-4 shadow-none sm:p-5"
    : "w-full border border-foreground bg-background p-5 shadow-none sm:p-6";

Line 104 (referralClassName) also carries text-black on a modified line (mb-4mb-3) — migrate to text-foreground.


Issue 2 — CLAUDE.md gstack section (line ~259 in PR)

Enforcement language stripped from the gstack rule.

The section was condensed from:

"## gstack (REQUIRED — global install)
If ~/.claude/skills/gstack/bin is missing, STOP and tell the user to install (see SETUP.md or https://github.com/garrytan/gstack). Do not skip skills, ignore gstack errors, or work around missing gstack."

to:

"## gstack
Use gstack skills for generic work: ... If ~/.claude/skills/gstack/bin is missing, see SETUP.md."

The "STOP" imperative, the install URL, and the explicit prohibition on workarounds are all removed — replaced with a soft redirect. Per CLAUDE.md's own meta-rule (line 3):

"Edits to this file and AGENTS.md: minimum words to convey the rule."

The removed text is the rule (stop, don't work around it). Condensing it away removes the behavioral constraint, not just verbose expression of it.


Issue 3 — CLAUDE.md Papers (algorithm source of truth) table

Normative section deleted with no replacement.

The entire ## Papers (algorithm source of truth) table was removed — the canonical map from each package to its governing algorithm spec (optimizer → dfda-spec, wishocracy → wishocracy spec, opg, obg, Welfare, Treasury). No replacement, no forwarding pointer.

Without it, agents implementing these packages have no CLAUDE.md pointer to the papers that define what they should compute. If this content moved elsewhere, a pointer should be added here.

@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

Code review

Three CLAUDE.md compliance issues found in new files:


1. Hardcoded hex colors in poster-client.tsx (L20-21)

CLAUDE.md: "Never use: Hardcoded hex (#ef4444, #666, #f5f5f5) → CSS custom properties. Exception: emails/ may use inline hex."

poster-client.tsx is not under emails/. qrcode.react accepts CSS named colors, which satisfies the rule while keeping the QR scannable:

bgColor="white"
fgColor="black"

2. /poster page missing routes.ts entry and getRouteMetadata() (page.tsx L1-5)

CLAUDE.md: "packages/web/src/lib/routes.ts is the single source of truth for page titles + descriptions. Pages use getRouteMetadata(link) from @/lib/metadata.ts."

The /poster route has no NavItem in routes.ts and no export const metadata / generateMetadata call. Every comparable new public page (e.g. humanity-v-government/page.tsx) derives metadata via getRouteMetadata(). Steps:

  1. Add a posterLink to packages/web/src/lib/routes.ts with label, description, emoji.
  2. Export metadata in poster/page.tsx via getRouteMetadata(posterLink).

3. Cron route test exercises only wiring (route.test.ts L1-52)

CLAUDE.md: "❌ Tests that mock the entire surface they're supposedly testing. Test the boundary, not the wiring."

Both collaborators (isAuthorizedCronRequest and refreshUserDownstreamCache) are mocked. The route is three lines of conditional logic; every assertion verifies that the route calls the mocks and passes their values through — that is wiring, not behavior. The auth-guard contract is already owned by isAuthorizedCronRequest's own tests, and the business logic is covered in refresh-user-downstream-cache.server.ts's suite. This file can be deleted.

@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

Code review

1 issue found.

/poster page missing from routes.ts — CLAUDE.md violation

File: packages/web/src/app/poster/page.tsx (new, 244 lines)

Rule: CLAUDE.md — "Page Metadata" section: packages/web/src/lib/routes.ts is the single source of truth for page titles + descriptions. Pages use getRouteMetadata(link) from @/lib/metadata.ts. Descriptions in Wishonia's voice.

Problem: The new /poster page has no generateMetadata export, no export const metadata, and no NavItem entry in routes.ts. routes.ts was not modified in this PR. The page will render with whatever Next.js default metadata is inherited from the layout.

Fix required (two files):

  1. Add a NavItem for /poster in packages/web/src/lib/routes.ts with label, description (in Wishonia voice), and emoji
  2. Add a generateMetadata function in poster/page.tsx that calls getRouteMetadata(posterLink) from @/lib/metadata.ts

Relevant code:

import { getServerSession } from "next-auth";
import Link from "next/link";
import { authOptions } from "@/lib/auth";
import { homeLink } from "@/lib/routes";
import { PosterPrintButton, PosterQrCode } from "./poster-client";


Checked and cleared:

  • Core bug fix (dueAt on optimize-earth root task) — correct and minimal
  • Regression test — uses fixed anchor date, not wall clock; compliant
  • NUCLEAR_OVERKILL_SPARE_LAYERS parameter — properly wired and exported
  • Legacy grant key construction (icewad:grant:*) — produces identical keys, test assertions correct
  • downstreamConversionCount migration — safe (non-null with default 0)
  • Cron route import (refresh-user-downstream-cache.server) — file exists in PR
  • Anonymization SQL scripts — idempotent, PII masked correctly, anon extension initialized before use
  • packages/data/src/campaign/nuclear-overkill-framing.ts — runtime-safe (no Prisma, no DB imports)
  • Hook files registered in settings.json — all present in PR
  • Treasury separation — no mixing of prize/IAB/WISH mechanisms

@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

Code review

One CLAUDE.md style issue found. No bugs or security issues.

packages/web/src/app/poster/poster-client.tsx lines 20–21 — hardcoded hex in a screen-rendered component

bgColor="#ffffff" / fgColor="#000000" are hardcoded hex values. CLAUDE.md Visual Style Rules state:

Never use: Hardcoded hex (#ef4444, #666, #f5f5f5) → CSS custom properties. Exception: emails/ may use inline hex.

The @media print block in page.tsx has a detailed inline comment explaining why it can't use CSS custom properties (print engines strip them). poster-client.tsx lacks that justification, even though the same constraint applies — qrcode.react's bgColor/fgColor props accept only strings, not var() references.

Fix: add a comment mirroring page.tsx's rationale, or move the constants to a shared PRINT_COLORS object alongside the @media print block:

// #ffffff / #000000: qrcode.react's bgColor/fgColor only accept
// plain strings — same rationale as @media print blocks in page.tsx.
<QRCodeSVG
  bgColor="#ffffff"
  fgColor="#000000"
  ...
/>

See:

<QRCodeSVG
bgColor="#ffffff"
fgColor="#000000"
includeMargin={false}
level="H"
size={600}
value={value}
/>
);

@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

Code review

Two CLAUDE.md violations found. Checked for bugs and CLAUDE.md compliance.


Issue 1 — Magic number: use existing named constant

File: packages/db/src/managed-data/optimize-earth-task-tree.ts L71-73

new Date("2024-12-31T00:00:00.000Z") is a raw date literal, but a named constant for this exact value already exists in the codebase:

// packages/web/src/lib/tasks/treaty-signer-network.ts (line 32)
const TREATY_DUE_AT = new Date("2024-12-31T00:00:00.000Z");

CLAUDE.md rule: "Magic numbers — named constants citing the paper." The same raw literal already appears twice in this file (lines 72 and 273), which is exactly the duplication risk the rule targets.

Fix: export TREATY_DUE_AT (or OPTIMIZE_EARTH_OVERDUE_SENTINEL) from a shared location in @optimitron/db and import it here instead of repeating the literal.


Issue 2 — Touched line retains hardcoded color tokens

File: packages/web/src/components/auth/AuthForm.tsx L85-92

The PR edits the isDocument branch (padding p-5p-4) but retains bg-white text-black border-black on the same line. The new compact branch added in the same hunk correctly uses semantic tokens (border-foreground bg-background), making the omission inconsistent.

CLAUDE.md rule: "When touching public UI, remove neobrutalist styling instead of copying it forward." + "Never use: Hardcoded bg-white / text-black / bg-blackbg-background, bg-foreground, text-foreground"

Fix:

- ? "w-full border border-black bg-white p-4 text-black shadow-none"
+ ? "w-full border border-foreground bg-background p-4 text-foreground shadow-none"

@mikepsinn
Copy link
Copy Markdown
Owner Author

Triaged the latest claude-bot review (#81 (comment)). Both findings declined as out-of-scope / architecturally wrong:

Issue 1 — magic date literal in optimize-earth-task-tree.ts (declined): the suggested fix is "export TREATY_DUE_AT from @optimitron/db", but the existing constant lives in packages/web/src/lib/tasks/treaty-signer-network.ts, and db cannot depend on web (architecture rule: library packages must be runtime-safe, no web imports). Two adjacent uses inside the same file with explicit narrative comments above each (lines 66-71, 270-272) explaining why 2024-12-31 — that comment block IS the "named constant citing the paper". Extracting a file-local constant for two co-located uses is the "domain narrative" magic-number case CLAUDE.md's slop rubric excludes.

Issue 2 — bg-white text-black border-black on isDocument branch in AuthForm.tsx (declined, out-of-scope): the PR's edit on this line was padding only (p-5p-4). The hardcoded tokens were already there. Fixing only line 88 leaves lines 100, 104, 107, 110, 113, 116, 119-120 in the same isDocument block using identical hardcoded bg-black/text-black/bg-white patterns — partial migration would leave the file inconsistent. A proper isDocument → semantic-token migration touches ~20 lines plus visual verification across signin, TreatyVoteFlow, ReferendumSignatureBox, TreatyNameSignatureBox, HumanityVGovernmentVerdictVote, and EndorseForm consumers. That's its own PR. CLAUDE.md: "Don't add features, refactor, or introduce abstractions beyond what the task requires."

No code changes pushed. CI is clean (9 pass / 5 skip), all 29 inline review threads already resolved, PR ready for Mike's merge.

Collapse PR #81 into a rebase-mergeable commit without changing the branch tree.

Includes the reviewed Optimize Earth dueAt fix, regression coverage, campaign UI/copy updates, validation hooks, preview smoke workflow, and associated generated snapshots already present in PR #81.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants