Skip to content

Sprint 1 — cleanup pass: feedback, legacy onboarding, test-utils, v33 fixture, playtest, BUDGETS#74

Merged
KevinBigham merged 7 commits into
mainfrom
feature/sprint-1-cleanup
May 14, 2026
Merged

Sprint 1 — cleanup pass: feedback, legacy onboarding, test-utils, v33 fixture, playtest, BUDGETS#74
KevinBigham merged 7 commits into
mainfrom
feature/sprint-1-cleanup

Conversation

@KevinBigham
Copy link
Copy Markdown
Owner

Summary

Sprint 1 of a multi-sprint plan from a deep-dive audit. Six focused cleanup slices, no end-user behavior change beyond the removed feedback button.

  • 🔪 Remove mailto feedback widget — destination feedback@mrbaseballdynasty.com is not a mailbox we own. Cleaner to delete than fall back.
  • 🔪 Delete orphaned legacy OnboardingPage.tsx + only-used-by-it useOnboardingState.ts. The router only mounts RevisedOnboardingPage at /onboarding. Shared onboarding components stay in tree pending Sprint 2's revised-onboarding canonicalization pass.
  • 🔪 Remove empty @mbd/test-utils packagesrc/index.ts was export {}; with no consumers.
  • Add native v33 save fixture + round-trip tests — the chain ended at v32 even though CURRENT_GAME_SNAPSHOT_VERSION = 33. New tests assert (a) v33 parses without migration and (b) JSON round-trip is identity.
  • Add pnpm playtest:calibrate + surface pnpm playtest / pnpm playtest:sample at the workspace root. New tests/calibrationDump.generate.ts (env-gated by MBD_PLAYTEST_DUMP=1, same convention as the existing narrative dump) writes a markdown summary of league-wide batting/payroll/win metrics.
  • 📦 Migrate worker-chunk lift journal to apps/web/docs/BUDGETS.mdbundleConfig.ts shrinks 325 → 161 lines. Full lift policy + 24-entry timeline preserved as a table; exported constants untouched.

Verification

Local from workspace root:

pnpm install
pnpm verify

Results on this branch:

  • pnpm typecheck — 9/9 tasks clean
  • pnpm test — 97 web / 137 sim-core / 1 contracts files, 2,248 tests passing (was 2,247; +2 v33, +1 calibration dump, −3 feedback assertions removed)
  • pnpm build — clean, 118-entry PWA precache, every chunk under ceiling
  • Browser smoke — Save Hub renders, no Send Feedback button, New Dynasty wizard opens to the 32-team selector with real worker-backed previews

Schema: still v33. No save shape change. No RNG touched. No new dependencies.

Test plan

  • CI gate (Typecheck → Test → Build) goes green on the branch
  • Manual smoke at pnpm dev: confirm /settings About panel no longer shows "Send Feedback"
  • pnpm playtest:calibrate writes packages/sim-core/playtest-output/calibration.md with sensible numbers (default seed 44001 gives ~.250/.315/.392 slash, 81-win average, $5.83M avg salary)
  • Confirm pnpm playtest / pnpm playtest:sample from root still produce the canonical sample-dynasty dump

🤖 Generated with Claude Code

claude added 7 commits May 14, 2026 16:33
The widget routed to feedback@mrbaseballdynasty.com, which is not a
mailbox we own or monitor. Removing the dead destination is cleaner
than wiring a fallback in v1.

- Delete apps/web/src/features/feedback/ (button, form, mailto helper, tests)
- Pull FeedbackButton import + render from SettingsPage About section
- Drop the matching SettingsPage feedback test

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The legacy procedural onboarding wizard at /onboarding was replaced by
RevisedOnboardingPage in the wire-everything-sweep. The legacy route
file still lives in tree but no router entry imports it.

- Delete apps/web/src/features/onboarding/routes/OnboardingPage.tsx
- Delete the only-used-by-it hook apps/web/src/features/onboarding/hooks/useOnboardingState.ts
- Remove the now-empty hooks/ directory

Shared onboarding components (AGMPanel, AssessmentPanel, ChapterProgress,
ChoiceSelector, OnboardingComplete, and the eight chapter views) stay
in tree pending the revised-onboarding canonicalization pass — they
likely get reused or replaced in that sprint.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
packages/test-utils/src/index.ts was literally `export {};` — the
package contributed nothing and had zero workspace consumers. Dropping
it shrinks the workspace surface area and removes a dead entry from
knip's project map.

- Delete packages/test-utils/
- Remove the test-utils workspace entry from knip.json

The pnpm-workspace.yaml glob is `packages/*`, so removal happens
automatically once the directory is gone.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The save fixture chain previously ended at v32, even though
CURRENT_GAME_SNAPSHOT_VERSION is 33. v32 -> v33 migration was tested
by promoting the v32 fixture, but no fixture exercised v33 directly.

This adds:
- packages/contracts/tests/fixtures/save/v33/core.json
  (the v32 fixture with schemaVersion bumped to 33 — v32 -> v33 is
   an additive enum expansion only, no field changes)
- A test that parsing a v33 fixture preserves the current schema
  without invoking a migration step.
- A test that the parsed snapshot round-trips through JSON without
  drift, defending against future migration regressions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Wires the existing sim-core calibration harness (runSeasonCalibration +
summarizeSeasonCalibration) into a one-command developer workflow:

- packages/sim-core/tests/calibrationDump.generate.ts
  Gated by MBD_PLAYTEST_DUMP=1 (same convention as the existing
  playtestNarrativeDump.generate.ts). Writes a markdown summary of
  league-wide batting line, payroll, win distribution, and per-season
  metrics for the given seed.
- packages/sim-core/package.json adds `playtest:calibrate`.
- Root package.json surfaces three passthroughs:
  - `pnpm playtest`           — full narrative dump
  - `pnpm playtest:sample`    — canonical sample-dynasty dump
  - `pnpm playtest:calibrate` — calibration metrics dump

Env vars accepted by the calibrate script (all optional):
  PLAYTEST_SEED, PLAYTEST_YEARS, PLAYTEST_OUT

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
bundleConfig.ts had accumulated ~80 lines of inline comments
documenting every worker-chunk ceiling lift from 406 KB / 124 KB up to
the current 443 KB / 143 KB. The narrative was valuable but buried the
actual exported constants.

- Move the per-slice lift rationale into apps/web/docs/BUDGETS.md.
- Preserve the lift policy (smallest safe lift, CI vs local terser
  drift, route-before-lift discipline).
- Preserve the 24-entry timeline as a table.
- Replace the in-source journal with a single pointer comment.

bundleConfig.ts: 325 -> 161 lines. No exported constants moved.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drops the test-utils workspace entry from the lockfile. No package
versions change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@KevinBigham KevinBigham merged commit 1eb4271 into main May 14, 2026
1 check passed
@KevinBigham KevinBigham deleted the feature/sprint-1-cleanup branch May 14, 2026 21:43
KevinBigham pushed a commit that referenced this pull request May 14, 2026
Goal Packet v2.0 format. Single-mission contract for Codex.

Mission: refactor RevisedOnboardingPage to drive the AGM-based revised
onboarding flow (getAGMCandidates / getRevisedOnboardingData /
applyStaffHires / applyScoutingHire / completeRevisedOnboarding) instead
of the Day-One worker surface it currently uses. Then decide what to do
with the orphaned Day-One worker methods.

Read-first, allowed-write, protected scope, non-negotiables, milestone
loop, validation loop, evaluator-visible proof, pause conditions, done
criteria, and final report all encoded inline so the slash command can
stay thin.

Companion to Sprint 1 cleanup (PR #74).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
KevinBigham added a commit that referenced this pull request May 15, 2026
* docs(goal): add Sprint 2 mission contract — revised onboarding canonical

Goal Packet v2.0 format. Single-mission contract for Codex.

Mission: refactor RevisedOnboardingPage to drive the AGM-based revised
onboarding flow (getAGMCandidates / getRevisedOnboardingData /
applyStaffHires / applyScoutingHire / completeRevisedOnboarding) instead
of the Day-One worker surface it currently uses. Then decide what to do
with the orphaned Day-One worker methods.

Read-first, allowed-write, protected scope, non-negotiables, milestone
loop, validation loop, evaluator-visible proof, pause conditions, done
criteria, and final report all encoded inline so the slash command can
stay thin.

Companion to Sprint 1 cleanup (PR #74).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(onboarding): refactor /onboarding to drive AGM-based revised flow

The `/onboarding` route now loads the three fixed AGM candidates
(Marcus Chen, Walter Kowalski, Elena Vargas) through `getAGMCandidates`,
hydrates the chosen AGM via `getRevisedOnboardingData`, walks the
sim-core `REVISED_CHAPTER_ORDER` end-to-end, applies coaching hires via
`applyStaffHires`, applies the scouting director via `applyScoutingHire`,
completes via `completeRevisedOnboarding`, then exports the snapshot
and persists it through the existing IndexedDB save path before
navigating to `/dashboard`.

Component touch-ups:
- AssessmentPanel: accepts revised chapter IDs alongside legacy ones,
  reusing the same chapter views.
- ChapterProgress: accepts the revised chapter-order labels.

The test for the route was rewritten test-first and now covers AGM
selection, the staff-hiring step calling `applyStaffHires`, the
scouting-hiring step calling `applyScoutingHire`, and the completion
step calling `completeRevisedOnboarding`.

Save schema stays at v33. Sim-core onboarding modules untouched.

Co-Authored-By: Codex GPT-5 <noreply@openai.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(worker): remove orphaned Day-One onboarding surface

The Day-One web worker methods (getDayOneSession, advanceDayOneIntro,
chooseDayOneAGM, advanceDayOneOrgReview, setDayOneSeasonGoal,
setDayOneBudgetAllocation, setDayOneOpeningPlan,
setDayOneDevelopmentPlan, resolveDayOneCrisis, finishDayOne) had no
remaining UI callers after /onboarding switched to the AGM-based
revised flow.

Removed from:
- apps/web/src/workers/sim.worker.onboarding.ts (exported wrappers)
- apps/web/src/workers/sim.worker.ts (onboardingApi Comlink map)
- apps/web/src/shared/hooks/useWorker.ts (callbacks + mutationMethods)

The protected sim-core source at packages/sim-core/src/onboarding/dayOne.ts
is left untouched per GOAL.md scope rules. Any future code that wants
Day-One semantics can reach it through a new worker wrapper.

Grep evidence after removal:

    rg -n "getDayOneSession|advanceDayOneIntro|chooseDayOneAGM|advanceDayOneOrgReview|setDayOneSeasonGoal|setDayOneBudgetAllocation|setDayOneOpeningPlan|setDayOneDevelopmentPlan|resolveDayOneCrisis|finishDayOne" apps/web/src

returns no output.

sim.worker.onboarding.test.ts was rewritten to exercise the revised
AGM worker API in place of the removed Day-One paths.

Co-Authored-By: Codex GPT-5 <noreply@openai.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(app): set BrowserRouter basename to match Vite /MBD/ public base

Hard-reloads on nested routes (e.g. /MBD/dashboard) previously failed
with: "The server is configured with a public base URL of /MBD/ - did
you mean to visit /MBD/dashboard instead?". Vite served the right
index.html, but BrowserRouter had no basename and so could not match
the path against the route table.

This is the pause condition flagged in Sprint 2's first run:
RevisedOnboardingPage worked end-to-end and IndexedDB saved cleanly,
but a hard reload at /dashboard surfaced this pre-existing routing gap.

Fix: derive the basename from import.meta.env.BASE_URL (which Vite
statically injects from `base: '/MBD/'`), strip the trailing slash so
react-router accepts it, and pass it to BrowserRouter. The cast around
import.meta matches the existing pattern in TeamLogo because the web
tsconfig does not currently include vite/client types.

After this change a hard reload at /MBD/dashboard:
- Returns 200 text/html from the dev server (no Vite base-URL error)
- Resolves through react-router's basename strip into the /dashboard
  route
- Renders the dashboard when a save is initialized, or redirects to
  Save Hub via the AppLayout uninitialized-state guard

Verified via:
- pnpm typecheck (clean)
- pnpm --filter @mbd/web test src/app (28 tests passing)
- pnpm --filter @mbd/web dev + browser navigation to /MBD/dashboard

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(onboarding): Sprint 2 status report, progress log, and browser smoke screenshots

Captures the milestone-by-milestone audit trail Codex produced during
Sprint 2, the final Done-When-satisfied status report (updated after
the BrowserRouter basename fix unblocked the hard-reload pause), and
nine browser-smoke screenshots covering AGM selection, every revised
chapter, completion, dashboard, and reload behavior.

Files:
- .logs/goal-progress.md
- STATUS.md
- apps/web/docs/screenshots/sprint-2/01-save-hub-setup.png
- apps/web/docs/screenshots/sprint-2/02-agm-selection.png
- apps/web/docs/screenshots/sprint-2/03-owner-office.png
- apps/web/docs/screenshots/sprint-2/04-staff-hiring.png
- apps/web/docs/screenshots/sprint-2/05-scout-hiring.png
- apps/web/docs/screenshots/sprint-2/06-completion.png
- apps/web/docs/screenshots/sprint-2/07-dashboard-after-completion.png
- apps/web/docs/screenshots/sprint-2/08-dashboard-after-reload.png  (pre-fix, kept as historical evidence)
- apps/web/docs/screenshots/sprint-2/09-dashboard-after-savehub-reload-continue.png

Co-Authored-By: Codex GPT-5 <noreply@openai.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Codex GPT-5 <noreply@openai.com>
KevinBigham added a commit that referenced this pull request May 15, 2026
* docs(goal): add Sprint 3 mission contract — News inbox

Goal Packet v2.0 format. Single-mission contract for Codex.

Mission: build a /news route that surfaces the worker-backed news feed
(getNews / markNewsRead) the audit found unwired. Includes filter UI,
mark-read on view, Sidebar nav entry, and an unread badge in TopBar.

Read-first, allowed-write, protected scope, non-negotiables, milestone
loop, validation loop, evaluator-visible proof, pause conditions, done
criteria, and final report all encoded inline so the slash command can
stay thin.

Builds on Sprint 1 cleanup (PR #74) and Sprint 2 revised onboarding
canonicalization (PR #75), both merged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(news): add /news inbox surfacing worker-backed news feed

The audit found getNews(limit?) and markNewsRead(newsId) exposed in
useWorker() and powered by sim-core/narrative/newsFeed.ts, but no UI
consumed them. SettingsPage showed the unread count, full stop.

This adds:

- /news route lazy-loaded under AppLayout, wrapped in RouteErrorBoundary
  like every other feature route.
- NewsPage list rendering: headline, body excerpt, category badge,
  priority indicator, optional tag chip, timestamp (Season X · Day Y or
  Now), related team chips. Read items have a clear visual treatment.
- Filters: All / Unread toggle plus a category multi-select chip group.
  Filtering happens client-side over the worker's getNews(100) result.
- Mark-read on item open: calls markNewsRead(id), persists the active
  save through the existing IndexedDB save path, decrements the
  in-session unread count.
- Mobile-survivable at 375x667 — no horizontal overflow.
- Loading skeleton, empty-state panel, and error toast for worker
  failures.
- A small newsEvents helper module dispatches a "news-read" event so
  the TopBar unread chip can react across components without prop
  threading.

Tests: NewsPage.test.tsx (4 tests) covers list render, filter behavior,
mark-read flow, and worker mock surface.

Schema stays at v33. No sim-core or contracts edits.

Co-Authored-By: Codex GPT-5 <noreply@openai.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(layout): add News nav entry + unread badge in TopBar

- Sidebar: new NavItem { to: '/news', label: 'News', icon: <Inbox /> }.
  Newspaper icon stays with Press Room. Sidebar.test asserts the entry
  renders.
- TopBar: new unread chip that subscribes to news-read events and
  refetches worker getNews() to recompute the count after every read.
  Decrements as the user reads items. Match the existing TopBar density
  (small chip, no emoji, lucide-only).

A new TopBar.test.tsx covers the chip render, the count reflecting the
worker mock, and the post-read recompute.

Co-Authored-By: Codex GPT-5 <noreply@openai.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(news): Sprint 3 status report, progress log, and browser-smoke screenshots

Captures the milestone-by-milestone audit trail Codex produced during
Sprint 3, the final Sprint-3-complete status report (reframed to
distinguish the news inbox feature — which fully shipped — from the
hard-reload state-hydration issue, which is pre-existing app-wide
behavior that affects every in-game route and is now queued as Sprint
3.5), and six browser-smoke screenshots:

- 01-dashboard-after-month.png   Day 31 save context
- 02-news-inbox-unread.png       /MBD/news list with worker news
- 03-news-category-filter.png    Trade-category filter applied
- 04-news-item-read.png          Read state + TopBar chip decrement
- 05-news-mobile-375.png         375x667 viewport, no overflow
- 06-news-hard-reload-blocked.png  pre-existing app-wide behavior
                                   (documented, not a Sprint 3 regression)

IndexedDB save-state proof from save-slot-2: unread 580 -> 579 after
read and survives reload at the data layer (only the routing redirect
to Save Hub masks it visually).

Co-Authored-By: Codex GPT-5 <noreply@openai.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Codex GPT-5 <noreply@openai.com>
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