Skill dashboard v1 — "Where you stand" in Settings / Account
Source: Sarah's direction of 2026-10-03 (journal entry 20261003-191238): the skill log belongs in Settings / Account, the only area that talks about the SAT directly. The player should see where they are strong, what they are not practicing at all, and where they keep making mistakes. They should be able to drill into the specific items they got wrong and generate a gameplay plan (which cases to work, which games to play) aimed at weak and unpracticed areas.
Research for this plan (2026-10-04) covered the app's result data, the corpus skill vocabulary and the Settings screen. The findings that shape it are listed first.
What already exists
-
A canonical skill spine. The corpus defines eight College Board codes in
guides/peregrine/schema-extensions.json(skill_code) and asskill-<code>entries inguides/sat-traps/:info-and-ideas,craft-and-structure,expression-of-ideas,standard-english,algebra,advanced-math,problem-solving-data,geometry-trig. Under them sit 23question_typeentries. About 1,060 of 1,372 Peregrine entries carryskill_code. -
The export drops it from most banks. Only
target-practice.json(skillCode) andgenerated-questions.json(skill) keep it. The Wager and Lineup banks (vigilance-bank, generated-vigilance-bank), Go Undercover and Red String drop it. Red Flag and Split Decision export their own vocabularies (9 Red Flag skills, 10 Split Decision decks), even though every corpus entry behind them has askill_code. -
Results by store:
-
DrillResult(Beat the Shakedown, The Make, Kingpin, Forensics) links aQuestionthat carriesskill(a canonical code) andtype. The miss reason is inresolution. -
VigilanceResult(Wager, Lineup, Clear the Room, Casing, Target Practice, Rematch) carriessection,conIDanditemID. Only Target Practice items resolve to a skill code. Wager does not store the choice picked. -
PhoneGameResult(the four Phone games) carries a game-levelskilland a miss diagnosis. -
PrimeSuspectRunstores per-evidence attempts inside a blob. Evidence has only in-storycategorytext (~50 values) and no skill. - Nothing per item: Red String, Go Undercover, and the Phone apps' graded rounds.
-
-
Reports that already work:
TrapAtlas(per-con tallies, mastery, calibration),Patterns.compute(per question type over DrillResults),PhoneSkillReport. There are also unreachableReportViewandLogViewscreens behind the orphanedHomeView. -
Designs that already point here:
-
The v4 credential mockup (
docs/mockups/peregrine-credential-v4.html) has an unbuilt section, "What you've earned on the test, in plain words". It shows badges that name the skill ("On the test: Command of Evidence"). -
The Get Out of Town briefing (handoff spec §9.6, Slice 9 of
.claude/plans/peregrine-v4-non-game-screens.md) is a fiction-free "Where you stand" screen. It shows domains with percentages over 14 days. - Spec v2 rules that a readiness view must never claim readiness that hasn't been shown.
-
The v4 credential mockup (
-
Settings rules:
YouViewis paper (Desk tokens, PGFont). "Flavor never carries a rule": headings may be in-world, but row labels stay plain. YouView pushes with closure links, because it is reached from both the Desk's typed stack and the Phone's untyped stack.
Design
1. One skill spine, two grains
-
Top grain: the eight codes, grouped by section (Reading & Writing: four codes; Math: four
codes). A new
SATSkillenum in PeregrineCore holds the code, the College Board name and the section. -
Fine grain: a
subskillstring per attempt. It usesquestion_typewhere content has one, and otherwise the game's own unit ("subject-verb-agreement", "reflect.xAxis", "comma deck"). Subskills sit under exactly one code. -
Mapping tables in PeregrineCore cover game-local vocabularies:
-
The 9 Red Flag skills map to
standard-english. - The 10 Split Decision decks map per the corpus: transitions → expression-of-ideas, word-duel → craft-and-structure, supports-contradicts → info-and-ideas, the other seven → standard-english.
- Generated content (ruled 2026-10-04): Linear / Exponential → advanced-math, Equivalent? → algebra, Coordinate Drop → geometry-trig, Odd One Out → advanced-math.
- A test asserts that every Red Flag skill and every Split Decision deck in the bundled banks has a mapping, so new content can't silently fall out of the dashboard.
-
The 9 Red Flag skills map to
2. A skill ledger over every store (no new stored table)
SkillLedger (pure, PeregrineCore) reads the existing stores and produces one SkillAttempt value per item. It holds: code, subskill, game, date, correct, miss reason, seconds (where known), and an item reference for drill-down.
| Source | Code from | Miss reason from | Item reference |
|---|---|---|---|
| DrillResult | question.skill / type | resolution (dodged, called his number, missed…) | the Question |
| VigilanceResult, Target Practice | bank skillCode | conID / outcome cell | bank id |
| VigilanceResult, Wager / Lineup / Clear / Casing / Rematch | bank skillCode once exported (phase 2); until then section only, shown as "not yet sorted by skill" | conID, trap codes | bank id |
| PhoneGameResult | mapping table | outcome (unreflected, false alarm, time up…) | bank id or stored prompt |
| PrimeSuspectRun attempts | phase 5 mapping | the evidence's wrong log | case + evidence id |
Computing on read keeps one source of truth. It needs no migration, and it picks up history that already exists. Profile stores are one player's history, so a full fetch is cheap. The code already fetches whole tables everywhere because of a documented SwiftData predicate crash.
3. What the dashboard shows
All of it is derived from the ledger by a pure SkillDashboard model with unit tests.
- Where you're strong: codes with accuracy ≥ 80% over at least 15 attempts in the window.
- Not practiced: codes with fewer than 10 recorded attempts. The universe is all eight codes, so an untouched skill shows up even though it has no rows.
- Needs practice: codes with at least 10 attempts but none in the last 14 days.
- Keeps catching you: the top recurring miss reasons, each with the skill it hits and a count. Examples: "Leaves the point unreflected · Geometry & Trig · 6 of 9 misses" and "Echo (mirror) · Information and Ideas · 11 times".
- Per code: attempts, accuracy, last practiced, a 14-day versus prior-14-day trend, and its subskills sorted weakest first.
-
Honesty rules (spec v2):
- No predicted score.
- Below 5 attempts, a code shows a count and "too few to read", not a percentage.
- Accuracy uses the raw rate. Weakness ranking uses a smoothed rate (2 phantom right and 2 phantom wrong), so one miss can't put a skill at the top.
4. Drill-down
- Dashboard → code → subskill → missed items → item.
- The item screen re-renders the content read-only: prompt, choices or tokens, the right answer, the player's answer where stored, the rule or why line, and the game and date.
-
Resolvers per source:
- a Question (text and screenshot)
-
Wager and Lineup bank items, via a new id index over
VigilanceBank.withGenerated() - Target Practice claims
- Red Flag sentences
- Split Decision cards
- Coordinate Drop: the stored prompt and the landing point
- Prime Suspect evidence (phase 5)
-
Gaps the item screen shows plainly:
- Wager does not store the player's pick, so it shows the right answer and the con that caught them.
- Odd One Out does not store the impostor's index. A one-line logging change in phase 4 fixes that going forward.
5. Gameplay plan
A rule-based PracticePlanner in PeregrineCore:
- Score each code's need. Weakness (1 − smoothed accuracy) is weighted by recency. Neglect rises with days since last practice and is highest at zero attempts. Strengths are excluded.
- Pick 3–4 target codes, highest need first. At least one comes from neglect when any code is unpracticed, so the plan doesn't only chase misses.
-
Pick 1–2 games per target code from a
GameSkillCatalog. The catalog is built once from the bundled banks: each game's content is counted by skill code, so the catalog matches what the game actually deals, not a hand-written claim. Games that play the player's own captured questions (The Make, Beat the Shakedown, Forensics) qualify only when the store holds captured questions with that code. - Pick a case when phase 5 has mapped Prime Suspect evidence, choosing the case with the most evidence in the target codes.
- Write each line plainly, with its reason and where to find the game. For example: "Red Flag · Standard English Conventions · 6 of your last 10 subject-verb calls missed · Phone › Games." Another example: "Coordinate Drop, Reflect deck · Geometry & Trig · never practiced."
The plan is computed when the screen opens, with a "New plan" button that reshuffles among equally needy options. It is not stored and not graded. A rule-based planner works offline, costs nothing per use and can be unit-tested. A Claude-written plan could replace the wording later without changing the ranking.
6. Where it sits
- YouView gets a new group above "Your record", headed "Where you stand". It holds a summary card (the strong / not practiced / keeps catching you lines, three at most each) and rows pushing to "All skills", "Gameplay plan" and "Missed items".
-
Screens are pushed with closure links, like
CasesClosedView, so the same hierarchy works from the Desk and from the Phone's Settings row. They use Desk tokens, PGFont and YouView'sgroup/card/rowContentpatterns. Those patterns are private today, so they move into a shared file. - Copy uses the College Board domain names ("Standard English Conventions"). Headings may be in-world; labels and numbers stay literal.
- The summary model is shared with the planned Get Out of Town briefing (Slice 9), so the two screens can't disagree.
Phases and tasks
Phase 1 — Skill spine and ledger (PeregrineCore, no UI)
-
Add
SATSkill(8 codes, names, sections) and the subskill mapping tables for Red Flag, Split Decision, Coordinate Drop, Odd One Out and the two generated Split Decision decks -
Add
SkillLedgeradapters for DrillResult, VigilanceResult (Target Practice skill codes; section fallback for the rest), and PhoneGameResult -
Add
SkillDashboard(strong, not practiced, recurring misses, per-code and per-subskill stats, 14-day trend, sample-size rules) - Add a bank-id index for Wager / Lineup items and resolvers that turn an attempt's item reference into displayable content
- Unit tests: mapping completeness against the bundled banks, ledger rows per store, dashboard thresholds, smoothing, the eight-code universe
Phase 2 — Skill codes for the Wager / Lineup / Undercover / Red String banks
-
Add
skillCodeto the vigilance, undercover and red-string projections in the exporter (PressRaven/tools/export-machine.py) and re-export (cross-repo; see question 5) -
Decode
skillCodein the Swift bank models and switch the ledger off the section fallback -
Fix the stale four-deck
split-decisionenum inschema-extensions.jsonvia/cr-corpus
Phase 3 — Dashboard screens
-
Move YouView's
group/card/rowContenthelpers into a shared Desk component file without changing their look - Add the "Where you stand" group and summary card to YouView
- Build the All skills screen (eight codes by section) and the per-code screen (subskills weakest first, trend, recurring misses)
- Build the Missed items list (filterable by code and game) and the read-only item screen
- UI tests: reach the dashboard from the Desk gear and from the Phone's Settings row, drill to an item; screenshot check on iPhone SE
Phase 4 — Gameplay plan
-
Build
GameSkillCatalogfrom the bundled banks (content counted by skill code per game) -
Build
PracticePlanner(need scoring, target picking, game picking, plain-language lines) with unit tests - Build the Gameplay plan screen with "New plan"
- Log Odd One Out's impostor index and Wager's chosen choice so the item screen can show the player's answer
Phase 5 — Prime Suspect cases in the ledger and the plan
-
Tag Prime Suspect evidence with
skill_codein the corpus via/cr-corpus, export it, and decode it - Add a ledger adapter for PrimeSuspectRun attempts and let the planner recommend cases
Deferred, recorded so it isn't lost
- Per-item logging for Red String, Go Undercover and the Phone apps' graded rounds. Until it lands, the dashboard lists them under "not counted yet" so the coverage numbers are not silently low.
- Launching a recommended game straight from the plan. It crosses the Desk / Training / Phone stacks, and it waits on question 3.
Decisions (Sarah, 2026-10-04)
- Placement: a summary card on YouView plus pushed screens, as designed.
-
Codes for the generated games:
- Coordinate Drop → Geometry and Trigonometry
- Odd One Out → Advanced Math
- Split Decision's Linear / Exponential deck → Advanced Math
- Split Decision's Equivalent? deck → Algebra
- Plan actions: launching the game is the goal. For v1, each line says where the game lives.
-
Two separate states:
- Not practiced: fewer than 10 recorded attempts on a skill, all-time.
- Needs practice: at least 10 attempts, but none in the last 14 days.
- "Not practiced" takes precedence. Weakness ("needs work") is a third, separate state.
-
Exporter edit: undecided. Recommendation: edit the projection code in
PressRaven/tools/export-machine.pydirectly. It is tooling, and the skill codes are already in the corpus entries./cr-corpusis for staging content changes. This is needed before phase 2, not phase 1.
Final review
Strengths
- It reuses the corpus's existing skill spine instead of inventing one, so content already tagged flows straight in.
- Computing on read means no migration, and history played before this ships shows up on day one.
- Every number on screen comes from a pure, unit-tested model. The sample-size rules keep it inside spec v2's honesty ruling.
Weaknesses and edge cases
- Until phase 2 lands, Wager / Lineup / Clear / Casing / Rematch count only by section. That is the bulk of a typical player's history, so the dashboard will look Phone-heavy at first. Phase 2 is the highest-value follow-up.
-
The con taxonomy doesn't map one-to-one onto skill codes (
invertspans math and writing). So "keeps catching you" lists cons with the skill of the item they caught, not a con-to-skill rule. -
A player who only uses captured screenshots may have Questions with empty
skill(the analyzer leaves some untagged). Those count under section only. - Strong / weak thresholds (80%, 15 attempts, 5 attempts) are judgment calls. Phase 1 puts them in one tuning struct so they are easy to change after a playtest.
- Recency-weighted need can make the plan swing day to day. "New plan" reshuffles only among options of equal need, which bounds the swing.
Adjustments worth considering
-
Fold the orphaned
ReportView/LogViewlogic (Patterns,ReportBuilder) intoSkillDashboardand delete the dead screens, so there is one report path. - The credential mockup's badge row ("On the test: …") could be fed from the same "strong" list later.
Confidence: 78/100. The data path and the honesty rules are solid. The open risks are the cross-repo export in phase 2 and how the planner's ranking feels in practice. Ranking feel can't be settled until real history exists.