Simple buy card: clarify projected effect pills with live +Xs, streak, and per-source BP #227
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:open_issues
agents
agent:security_audit
agent:verify
area
timecurve
arena
arena-v2
audit
block:feature_review
block:security
bug
contracts
design
devops
docs
documentation
enhancement
epic
feature
frontend
indexer
low priority
megaeth
operations
ops
performance
QA
qa checklist
referrals
removal
security
smart-contracts
tech-debt
testing
time-arena
timecurve
visual-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/yieldomega#227
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
The Projected effects pill rail on the Simple buy card (
/timecurve) is hard to parse and does not reflect live timer pressure. Copy like “Hard-reset timer toward 15m” hides the actual seconds a buy would add; “+120s time-booster credit” duplicates the timer pill; BP bonuses are lumped into one vague chip; and defended-streak outcomes are ambiguous. Pills should tick with the hero countdown (especially under the 13-minute hard-reset band) and show one short, numeric chip per effect.What is wrong today
Implementation lives in
frontend/src/pages/timecurve/timeCurveBuyProjectedEffects.ts, rendered fromTimeCurveSimplePage.tsxviaTimeCurveBuyProjectedEffects.tsx.secondsRemaining < 780(13m): “Hard-reset timer toward 15m”. WhentimerExtensionPreview > 0: both+{n}s timerand+{n}s time-booster credit.actualSecondsAdded; the preview only needs one+{x}schip). Under 13m,xgrows every second as remaining falls (900 − remainingbefore cap) but the UI shows static prose instead.secondsRemaining < 900(15m): either “Continue your streak (N → N+1)” or “Start or break defended streak”.activeDefendedStreakonly; streak-break BP depends on_dsLastUnderWindowBuyer(internal, not exposed) perTimeCurve.sol_processDefendedStreak.docs/product/primitives.md): base 250, hard-reset 500, clutch 150 (remaining < 30s), streak-breakpriorActiveStreak × 100, ambush 200 (hard reset + streak break same tx). User wants one pill per source with exact amount + 1–2 word label.saleCountdownSecfromuseTimecurveHeroTimeralready recomputes every 1s;timerExtensionPreviewSecinuseTimeCurveSaleSessiondepends on it.Reference — onchain timer math (
TimeMath.extendDeadlineOrResetBelowThreshold):remaining ≥ 780: addmin(timerExtensionSec, timerCapSec − remaining)(canonical extension 120s, capped).remaining < 780: snap deadline towardnow + 900(15m remaining), capped bytimerCapSec;actualSecondsAdded = newDeadline − oldDeadline(typically900 − remainingwhen cap allows).Python mirror:
simulations/timecurve_sim/model.py(extend_deadline_or_reset_below_threshold,warbow_buy_bp_delta).Note: Arena buy hub is intended to share this helper (file comment / #191) but only Simple renders the rail today; keep Simple + Arena aligned when Arena adopts it.
Recommended fix
1. Shared pure preview helper (TS)
Add e.g.
previewBuyTimerSecondsAdded+previewBuyWarBowBpPillsin a small module underfrontend/src/lib/(or extendtimeCurveBuyProjectedEffects.ts) mirroring:TimeMath.extendDeadlineOrResetBelowThresholdfor+{x}sTimeCurve.buyBP branch order for pill listTimeCurvepublic getters already infrontend/public/abis/TimeCurve.json:WARBOW_BASE_BUY_BP,WARBOW_TIMER_RESET_BONUS_BP,WARBOW_CLUTCH_BONUS_BP,WARBOW_STREAK_BREAK_MULT_BP,WARBOW_AMBUSH_BONUS_BP,TIMER_RESET_BELOW_REMAINING_SEC,TIMER_RESET_TO_REMAINING_SEC,DEFENDED_STREAK_WINDOW_SECRead constants from chain in session (same pattern as
timerExtensionSecR) — do not hardcode 250/500/150 if deployment can differ.2. Timer pill — single
+{x}s+{n}s timerand+{n}s time-booster creditdual chips.x > 0:+{x}s(nothing else on that pill).remaining < 780, computexfrom hard-reset branch (nottimerExtensionPreviewalone).x === 0(timer at cap — seedescribeTimerPreview), omit timer pill or show a minimal “Timer capped” chip (product call).3. Realtime wiring
buildTimeCurveBuyProjectedEffectLines(or successor) receivessecondsRemainingthat updates every 1s — already available via hero timer; confirmuseMemodeps include it (they do on Simple; avoid latch freezing countdown during active sale except on brief RPC gaps).x, streak pills, and BP pills on each tick so crossing 780 → 779, 30 → 29, etc. updates pills without waiting for indexer poll.4. Defended streak — separate pills
When
remaining < 900(DEFENDED_STREAK_WINDOW_SEC):_dsLastUnderWindowBuyerequivalent andactiveDefendedStreak > 0Streak +1orContinue streak(short; optional(N→N+1)if space)activeDefendedStreak)Break streak +{prior×100} BPor split:Break streak+ BP pillStart streakStreak holder discovery (pick one):
TimeCurvefor_dsLastUnderWindowBuyer(small contract change + indexer optional), orrecentBuys/ indexer head whenactual_seconds_added > 0and buy was under 15m window — document staleness if no indexer.Do not show a generic “Start or break defended streak” combo pill.
5. BP — one pill per source
Replace combined BP chip with only the pills that apply to this hypothetical buy, e.g.:
+250 Base+500 Reset(when hard-reset branch)+150 Clutch(whenremaining < 30)+{prior×100} Streak break(when breaking another holder’s active streak)+200 Ambush(when hard reset and streak break in same tx)Omit zero amounts. Keep “Become latest buyer” (and WarBow flag pills) as separate non-BP chips.
6. Tests & docs
timeCurveBuyProjectedEffects.test.ts: hard-reset+300sat 600s remaining; no duplicate time-booster; BP decomposition at<30s+ hard reset; streak-break amount.TimeMath/ Python sim fixtures.docs/frontend/timecurve-views.md+ invariant row indocs/testing/invariants-and-business-logic.mdif warranted.Acceptance criteria
+{x}sonly (no “timer”, “time-booster”, or “hard reset toward 15m” prose on that pill).time-booster creditpill in projected effects (time-booster podium remains elsewhere).xincreases by ~1 each second as the hero countdown ticks (e.g. at 12:00 remaining,x ≈ 180; at 11:59,x ≈ 181).+120s(or cap-truncated value), updating if cap binds.Verification checklist
Manual (local stack —
docs/testing/qa-local-full-stack.md):SKIP_ANVIL_RICH_STATE=1+ bot swarm or manual buys: open/timecurvewith wallet connected duringsaleActive.remaining > 15m): projected effects show+120s(or cap-limited) single timer pill;+250 BaseBP pill; no time-booster duplicate.remainingis 779s → 778s; confirm timer pill switches from+120sto+{900−remaining}sand increments every second while watching hero digits.remaining < 30s, confirm+150 Clutchpill appears in addition to base/reset pills.remaining < 15m): after a buy establishes a streak, second wallet sees break copy ++{N×100} Streak breakBP pill; same wallet sees continue pill.timerCapSec, timer pill omits or shows capped state; no false+120s.Automated:
npm test -- timeCurveBuyProjectedEffects(and new helper tests) pass infrontend/.Related
docs/product/primitives.md— timer hard reset, defended streak, BP table.+Nsprecedent):TimeCurveSections.tsx/lastExtensionon Simple timer panel.Walked what's walkable on this pre-ship. Goal was to establish a clean baseline of current behavior before the refactor lands, and verify the items that don't require new code.
Automated tests (current code on main @
8fd0841):npm test -- timeCurveBuyProjectedEffects→ 4/4 PASS (existing test file, pre-refactor baseline)npm test(full suite) → 534/534 PASS across 93 filesSo the existing test surface is green going into the refactor.
Current-state baseline (production /timecurve, sale live with timer transitions captured):
Captured the pill rail at two timer states during the same session — calm timer (>13m remaining) and hard-reset band (<13m remaining). All four "what is wrong today" items from the issue body are visible and reproducible.
At 14:35 remaining (calm band, no throttling):
+9.029 CHARM·11.48 CL8Y spend·+120s timer·+120s time-booster credit·Start or break defended streak·+250 BP base·Become latest buyerAt 14:10 remaining (calm band, offline mode engaged with
prefers-reduced-motion: reduce): Same pill set, rendered cleanly under both emulations.At 11:33 remaining (after crossing 13:00 hard-reset threshold, offline still on):
+9.028 CHARM·11.48 CL8Y spend·Hard-reset timer toward 15m·+120s time-booster credit·Start or break defended streak·+250 BP + reset bonus·Become latest buyerConfirms each of the four points in the "What is wrong today" table:
+120s timer++120s time-booster creditship as two separate pills in the calm band. After crossing 13:00 the timer pill swaps toHard-reset timer toward 15mprose but the+120s time-booster creditpill stays as a second timer-related pill. Both states ship two pills covering the same mechanic.Hard-reset timer toward 15m— pure prose, no+{x}svalue. At 11:33 remaining the actual onchain hard-reset would add ~207s (900 − 693), invisible to the user.+250 BP + reset bonus— exact case from the issue body. Reset bonus is not surfaced as its own +{n} pill.Start or break defended streakcombined string visible in both timer states — exactly the string the acceptance criteria says should never appear.Acceptance criteria items walkable pre-ship:
prefers-reduced-motion: reduceengaged simultaneously with Network → Offline. Full pill rail rendered cleanly across both timer states (calm + hard-reset band). 2,626 console errors from offline RPC blackholing, no React error boundaries triggered, no missing components. Hero timer continued ticking client-side throughout.Acceptance criteria items NOT walkable pre-ship (blocked on dev refactor or live sale state):
+{900-remaining}sincrement-by-second behavior / hard-reset cap binding / streak continue-vs-break-vs-start distinct pills / BP one-pill-per-sourceThese all require the refactor to land first — they describe the target behavior, not current.
Verification checklist items walkable pre-ship:
Verification checklist items blocked pre-ship:
Notes for the refactor:
+250 Base,+500 Reset,+150 Clutch) should be templated as+{base} Baseetc. in the implementation so deployment-time values flow through.recentBuyshead) can be wrong when the latest qualifying buy isn't the actual current_dsLastUnderWindowBuyer(e.g. holder buys → someone else buys outside window → third party buys under window — the inference would tag the third party, not the original holder). Worth either surfacing staleness in the chip or blocking the streak-break chip when uncertain. Preferred path (small contract change to expose_dsLastUnderWindowBuyer) is more robust if low cost.Pre-ship baseline locked in. Ready to re-walk against the refactor when it lands.
marked the checklist item Reduced motion / offline: pills do not throw; latch behavior from #82 still prevents flicker on brief RPC gaps. as completed
mentioned in commit
b0d4f9067cImplementation landed on
main(b0d4f90)Refactored Simple Projected effects pills per #227.
What changed
timeCurveBuyPreview.tsmirroringTimeMath.extendDeadlineOrResetBelowThresholdand WarBow buy BP branches.+{x}spill (ticks with hero countdown; under 13m uses900 − remaining).time-booster creditpill andHard-reset timer toward 15mprose.-{3dp} CL8Y|ETH|USDM(e.g.-2.260 CL8Y).+{n} BP Base,Reset,Clutch,Streak break,Ambush.+1 streak (N),Break streak, orStart streak(holder inferred from indexerrecentBuyshead).Become Last Buyer.INV-FRONTEND-227-BUY-PROJECTED, timecurve-views §227.Automated tests
npm test -- timeCurveBuyPreview timeCurveBuyProjectedEffects— 14/14 PASSVerification checklist (please confirm on live or Anvil)
+120stimer pill;+250 BP Base; no time-booster duplicate+{900−remaining}sincrements each second with hero digits-2.260 CL8Y)+150 BP Clutchpill appearsTimer cappedor no false+120s@toddking — please verify on the next live sale window or local Anvil walk (
SKIP_ANVIL_RICH_STATE=1+ warp to 779s / <30s). Issue stays open until sign-off.mentioned in commit
3bd16a8068Re-ran the touched tests on QA server post-refactor (against
2c2948a):✓ src/lib/timeCurveBuyPreview.test.ts (8 tests)✓ src/pages/timecurve/timeCurveBuyProjectedEffects.test.ts (6 tests) 14 passedMatches your 14/14 from pre-merge. Shipped code is clean on the automated side.
Yesterday's pre-ship baseline (screenshots at 14:35 / 14:10 / 11:33 remaining capturing the 4 "what is wrong today" items) is now superseded by the refactor. Leaving the manual visual walk on the new pill rail to @totdking per your tag — the comparison against yesterday's baseline gives a clean before/after on this thread when he gets to it.