feat: implement AI Guilt-O-Meter (Phase 3 PRD #2)#106
Conversation
Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/26d4dab7-c844-4225-b1f6-3530f6167a53 Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/26d4dab7-c844-4225-b1f6-3530f6167a53 Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughI pity the fool — Adds an "AI Guilt-O-Meter": new GUILT_LABELS and getGuiltLabel in core, a client guilt-meter module with UI and styles, badge integration, build ordering adjustments, docs entry, and unit tests for label behavior. Changes
Sequence Diagram(s)sequenceDiagram
participant Page as Page (UI)
participant Core as DeathClockCore
participant State as State Module
participant Badges as Badges System
participant Share as Share Popup
Page->>State: init (imports GUILT_LABELS, getGuiltLabel)
Page->>Page: render guilt meter elements
Page->>Page: setInterval every 1s -> updateGuiltMeter()
loop every 1s
Page->>State: compute elapsed pct
State->>Core: getGuiltLabel(pct)
Core-->>State: label (icon,text)
State->>Page: update progress value, aria, label text
alt pct >= 20
Page->>Page: show share button
end
alt pct == 100 and not awarded
State->>Badges: award('certified_hypocrite')
end
end
Page->>Share: on share click -> openSharePopup(constructed text)
Share-->>Page: popup opened
Page->>Badges: award('spreading_doom')
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
I pity the fool who don't review this carefully! 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #106 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 1 1
Lines 256 263 +7
Branches 112 113 +1
=========================================
+ Hits 256 263 +7
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/js/22-guilt-meter.js (1)
32-34: Don’t bail out the whole meter when share button is missing — keep rendering alive, sucker.At Line 33, returning early blocks initial meter render (
updateGuiltMeter) if only the button is absent. Make the click wiring conditional, not the whole init.♻️ Proposed refactor
function initGuiltMeter() { const shareBtn = document.getElementById('guiltShareBtn'); - if (!shareBtn) return; - - shareBtn.addEventListener('click', () => { - const elapsed = Date.now() - pageLoadTime; - const mins = Math.floor(elapsed / 60000) || 1; - const labelEl = document.getElementById('guiltMeterLabel'); - const labelText = labelEl ? labelEl.textContent : ''; - const shareText = - '\uD83D\uDE2C I\u2019ve been watching AI consume tokens for ' + - mins + ' minute' + (mins !== 1 ? 's' : '') + - ' and done absolutely nothing about it.' + - ' My guilt level: ' + labelText + - '. Are you as bad as me?\n\u2192 ' + SITE_URL + - ' `#TokenDeathClock` `#CertifiedHypocrite`'; - openSharePopup(shareText); - awardBadge('spreading_doom'); - }); + if (shareBtn) { + shareBtn.addEventListener('click', () => { + const elapsed = Date.now() - pageLoadTime; + const mins = Math.floor(elapsed / 60000) || 1; + const labelEl = document.getElementById('guiltMeterLabel'); + const labelText = labelEl ? labelEl.textContent : ''; + const shareText = + '\uD83D\uDE2C I\u2019ve been watching AI consume tokens for ' + + mins + ' minute' + (mins !== 1 ? 's' : '') + + ' and done absolutely nothing about it.' + + ' My guilt level: ' + labelText + + '. Are you as bad as me?\n\u2192 ' + SITE_URL + + ' `#TokenDeathClock` `#CertifiedHypocrite`'; + openSharePopup(shareText); + awardBadge('spreading_doom'); + }); + } // Render initial state updateGuiltMeter(); }Also applies to: 51-53
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/js/22-guilt-meter.js` around lines 32 - 34, The current early return when document.getElementById('guiltShareBtn') is falsy prevents the rest of the meter initialization (including updateGuiltMeter) from running; instead, remove the return and make the click wiring conditional: find the shareBtn via document.getElementById('guiltShareBtn') and if (shareBtn) attach the event listener and any share-specific logic, but always continue to run the remainder of the init so updateGuiltMeter still executes. Apply the same change to the similar block around lines referenced (the other getElementById check at 51-53) so missing elements only skip their event wiring and do not abort the entire setup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/LEARNINGS.md`:
- Line 146: Update the heading "#### PR — feat: implement AI Guilt-O-Meter
(Phase 3 PRD `#2`)" to include the concrete PR ID `#106` (e.g., append " (`#106`)")
so it matches surrounding log format and aids traceability; while here also
verify the entry follows the repo's learning pattern by confirming it has a
category header, concise description, a link/reference to the PR, and that any
Categorised Learnings tables are updated accordingly (search for the heading
text to locate the entry).
In `@src/js/22-guilt-meter.js`:
- Around line 13-15: Negative elapsed values from system clock jumps must be
clamped to zero before deriving progress and minutes: replace the direct
subtraction used to compute elapsed in the guilt meter (where elapsed is set
from Date.now() - pageLoadTime) with a non-negative clamp (e.g., elapsed =
Math.max(0, Date.now() - pageLoadTime)) and use that clamped elapsed when
computing pct (with GUILT_DURATION_MS) and mins; update any other places that
compute elapsed (the second occurrence around mins) to use the same clamped
value so getGuiltLabel(pct) and the minutes display never receive negative
inputs.
---
Nitpick comments:
In `@src/js/22-guilt-meter.js`:
- Around line 32-34: The current early return when
document.getElementById('guiltShareBtn') is falsy prevents the rest of the meter
initialization (including updateGuiltMeter) from running; instead, remove the
return and make the click wiring conditional: find the shareBtn via
document.getElementById('guiltShareBtn') and if (shareBtn) attach the event
listener and any share-specific logic, but always continue to run the remainder
of the init so updateGuiltMeter still executes. Apply the same change to the
similar block around lines referenced (the other getElementById check at 51-53)
so missing elements only skip their event wiring and do not abort the entire
setup.
🪄 Autofix (Beta)
✅ Autofix completed
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 386c2143-4b38-4b72-9809-ae632685c159
📒 Files selected for processing (10)
death-clock-core.jsdocs/LEARNINGS.mdindex.htmlscripts/build-js.jssrc/js/00-state.jssrc/js/14-badges.jssrc/js/22-guilt-meter.jssrc/js/23-boot.jsstyles/features.csstests/death-clock.test.js
|
@coderabbitai apply |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain
🏁 Script executed: Length of output: 55701
🏁 Script executed: Length of output: 2327 🏁 Script executed: Length of output: 1847
🧠 Learnings used
|
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. Fixes Applied SuccessfullyFixed 2 file(s) based on 2 unresolved review comments. Files modified:
Commit: The changes have been pushed to the Time taken: |
Fixed 2 file(s) based on 2 unresolved review comments. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/js/22-guilt-meter.js`:
- Around line 31-33: In initGuiltMeter(), stop bailing out when
document.getElementById('guiltShareBtn') is missing; instead remove the early
"if (!shareBtn) return" and conditionally attach the click handler only when
shareBtn exists (e.g., if (shareBtn) { shareBtn.addEventListener(...) }), then
always call updateGuiltMeter() so the meter renders/updates regardless of the
button. Apply the same change to the other occurrence noted around lines 51-52
(replace early return with conditional handler attachment and always call
updateGuiltMeter()).
🪄 Autofix (Beta)
✅ Autofix completed
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 871312bb-e878-48e3-aaa4-f4b512aa0c86
📒 Files selected for processing (2)
docs/LEARNINGS.mdsrc/js/22-guilt-meter.js
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/LEARNINGS.md
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. ❌ Cannot run autofix: This PR has merge conflicts. Please resolve the conflicts with the base branch and try again. Alternatively, use |
Signed-off-by: RB <7775707+nitrocode@users.noreply.github.com>
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. Fixes Applied SuccessfullyFixed 1 file(s) based on 1 unresolved review comment. Files modified:
Commit: The changes have been pushed to the Time taken: |
Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>


Summary
Implements the AI Guilt-O-Meter — the next unimplemented low-effort/high-impact Phase 3 PRD. A
<progress>bar fills 0→100% over 5 minutes of page time, cycling through 6 increasingly panicked guilt labels. At 100% the visitor earns thecertified_hypocritebadge. A share button appears at ≥20% fill.Changes
GUILT_LABELSconstant andgetGuiltLabel(pct)pure function todeath-clock-core.js; export bothcertified_hypocritebadge toBADGE_DEFSinsrc/js/14-badges.jssrc/js/22-guilt-meter.js:initGuiltMeter()(share button wiring) +updateGuiltMeter()(called on 1s interval)22-boot.js→23-boot.jsto preserve strict numeric file ordering; wireinitGuiltMeter()+updateGuiltMeter()into bootscripts/build-js.jsPARTS array for new file order<section id="guilt-meter-section">toindex.htmlwith<progress>element, full ARIA attributes, and share buttonstyles/features.css— includes WebKit/Firefox progress pseudo-elements andprefers-reduced-motionoverridessrc/js/00-state.jsdestructuring to includeGUILT_LABELS,getGuiltLabelGUILT_LABELSandgetGuiltLabelintests/death-clock.test.jsdocs/LEARNINGS.mdAgent Checklist
npm run test:cipasses (all unit tests green, coverage not decreased)npm run build && npm run test:e2epasses (all E2E tests green)script.js,styles.css,*-data.js)innerHTMLvalues pass throughescHtml()death-clock-core.jsuses:pins use a full commit SHA + inline semver commentfeat:,fix:,docs:,chore:, etc.)project-stats.yamlupdated if this session merges one or more PRsdocs/LEARNINGS.md(new pattern or lesson learned)Summary by CodeRabbit
New Features
Styles
Tests
Documentation