feat: FEAT-293 Standalone-practice discoverability + propatheia content fix - #219
Merged
Merged
Conversation
β¦nt fix
Narrowed from the original ACs after a 3-lens planning panel. AC1's "a Home
entry and/or a loop variation slot" was a material fork, not a stylistic hedge:
no variation slot exists (zero grep hits), adding one mutates a crisis- and
philosopher-reviewed config, and `daily_loop` is false in .env.production β so
that branch would have shipped invisible to every real user on merge day. Home
entry only; the loop slot is deferred.
WHAT SHIPS
- Home: a fixed-height "Practices / Explore" row BELOW checkInSection, not a
fifth CheckInCard. checkInSection is flex:1 and every card inside it is also
flex:1 with no ScrollView, so a fifth card squeezes all of them. The row also
survives FEAT-298 deleting the three time-of-day cards.
- New PracticeLibrary root screen. The sorting drill is featured and named by
principle (SPHERE SOVEREIGNTY / Control Sorting), carries the Enchiridion 1
framing and a "Read the full principle" link to Module 3 β the philosopher
requires no context-free launch, since the drill's answer key encodes a
counterintuitive doctrine that reads as arbitrary once Module 3's prose is out
of view. Practices group under THEIR OWN principle: breathing and body scan
are the Aware Presence limb and are never labelled Stoic; the reserve clause
is hypexhairesis and stays with Sphere Sovereignty.
- The launch switch moved out of PracticeTab into a pure `resolvePracticeRoute`,
so Learn and the library launch through identical code rather than two
switches that can drift.
- SortingPractice's `scenarios` param is now optional, resolved by a wrapper
that self-loads module content when the caller has none. This also repairs the
pre-existing `/sorting` deep link, which could never have supplied an array.
- No score, tally, streak or badge anywhere; the signed feedback copy and
VIRTUE_CHECK_FEEDBACK are untouched. The featured citation is IMPORTED from
PRACTICE_QUOTES rather than retyped β a hand-typed second copy is exactly how
the citation drift FEAT-268 cleaned up would recur.
CONTENT SAFETY FIX (philosopher-blocking, and live in Learn today)
`medical-test-anxiety` marked "Your anxiety about an upcoming medical test
result" as in-control, explaining the anxiety itself is up to you. That
conflates propatheia β the involuntary first movement, which classical Stoicism
holds is NOT up to us β with assent. Promoted to a primary surface without
Module 3's prose it tells a user with elevated GAD-7 that their anxiety is their
own doing, and flags "Not Quite" when they disagree.
The card now sorts the RESPONSE, with the first wave of fear moved to
notInControl. The philosopher's review of that rewrite then found the fix had
made the rest of the deck inconsistent with its own new standard, so four more
cards are corrected: `political-response` (its explanation contradicted its own
notInControl list on the same screen), `traffic-cutoff`, `event-interpretation`
(the highest-risk one β it stated the conflation as doctrine on the card most
likely to be loaded with a real difficult event), and `vacation-weather` (listed
an outcome, "finding enjoyment", as a controllable). Two avoidance-shaped
inControl items on the medical card were also replaced.
TESTS
AC3 ("no regression to existing Learn-launched entry points") had NO mechanical
pin β zero tests referenced PracticeTab. 13 new cases lock the resolver's output
param-for-param to the original inline switch, including its default durations,
plus: the drill's citation must resolve to Epictetus and not silently fall back
to the breathing quote; every catalog entry must be filed under its own
principle (a mislabel would propagate into the Insights engagement chart). One
case added to RootCrisisButton.test.tsx pinning that PracticeLibrary keeps the
overlay in standard mode β unknown routes fall through to standard, but safe-by-
accident is not a contract.
Verification: npm run precommit exit 0 (safety 108, clinical 106, unit 581,
privacy 51); npm run test:accessibility 87 passed; lint baseline improved
557 -> 555.
π€ Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦ssion) SortingPracticeRoute is now the rendered component for the pre-existing `SortingPractice` route, so a bug in it breaks the Learn-launched sorting practice that shipped long before FEAT-293. That risk is invisible to the Maestro safety gate: crisis-button-reachability deliberately does not walk practice flows (they need the long check-in preamble), so no on-device gate exercises this path. The unit tests added with the feature covered the pure route resolver, not the wrapper's rendering. Six cases, the load-bearing one being the Learn path: when the caller already holds the scenarios the wrapper must pass them straight through with NO module load and NO spinner frame β same render as before FEAT-293. Plus the standalone path (loads, then renders), and the three degradation paths that must never reach SortingPracticeScreen, which throws on a missing scenario at the current index: empty array, unknown practice id, and a rejected load. Also pins that a load resolving after unmount does not set state. Verification: npm run precommit exit 0 β safety 108, clinical 106, unit 587 (+6), privacy 51. π€ Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes FEAT-293
Standalone practices (breathing, body scan, reflection, and especially the Stoic control-sorting drill) were reachable only from deep inside Learn. This surfaces them from Home.
Scope narrowed from the original AC1. "A Home entry and/or a loop variation slot" was a material fork, not a hedge: no variation slot exists (zero grep hits for
variation;StepConfighas no affordance to host one, and adding it mutates a crisis- and philosopher-reviewed config), anddaily_loop:falsein.config/.env.productionmeans a loop-slot-only implementation would have been invisible to every real user the day it merged β making AC1's own words ("reachable from a primary surface") false in production. Loop slot deferred; Home entry ships.What ships
checkInSection, not a fifthCheckInCard.checkInSectionisflex:1and each card inside is alsoflex:1with no ScrollView, so a fifth card squeezes all of them. The row also survives FEAT-298 retiring the three time-of-day cards.PracticeLibraryroot screen. Sorting drill featured and named by principle, carrying the Enchiridion 1 framing and a "Read the full principle: Sphere Sovereignty" link to Module 3 β no context-free launch, since the drill's answer key encodes a counterintuitive doctrine that reads as arbitrary once Module 3's prose is out of view. Practices group under their own principle: breathing/body scan under Aware Presence (never labelled Stoic), reserve clause with Sphere Sovereignty (it is hypexhairesis).PracticeTabinto a pureresolvePracticeRoute, shared by Learn and the library rather than two switches that can drift.SortingPractice.scenariosis now optional, resolved by a wrapper that self-loads module content. This also repairs the pre-existing/sortingdeep link, which could never have supplied a scenarios array.VIRTUE_CHECK_FEEDBACKuntouched. The citation is imported fromPRACTICE_QUOTES, not retyped.Content safety fix β 5 cards, live in Learn today
medical-test-anxietymarked "Your anxiety about an upcoming medical test result" as in-control, explaining the anxiety itself is up to you. That conflates propatheia β the involuntary first movement, which classical Stoicism holds is not up to us β with assent. On a primary surface without Module 3's prose it tells a user with elevated GAD-7 that their anxiety is their own doing, and flags "Not Quite" when they disagree.Rewritten to sort the response, first wave of fear moved to
notInControl. The philosopher's review of that rewrite found it had made the rest of the deck inconsistent with its own new standard:medical-test-anxietyinControlitems replacedpolitical-responseexplanationcontradicted its ownnotInControllist β both render in one viewporttraffic-cutoffevent-interpretationvacation-weatherfriend-no-replywas already correct and served as the model; six other cards verified clean.Tests
AC3 ("no regression to existing Learn-launched entry points") had no mechanical pin β zero tests referenced
PracticeTab. Added:resolvePracticeRouteparam-for-param to the original inline switch, including its default durations; plus pins that the drill's citation resolves to Epictetus rather than silently falling back to the breathing quote, and that every catalog entry is filed under its own principle (a mislabel would propagate into the Insights engagement chart).SortingPracticeRoute, which is now the rendered component for the pre-existingSortingPracticeroute. The Maestro suite deliberately does not walk practice flows, so this path had no on-device gate. Load-bearing case: the Learn path passes scenarios through with no module load and no spinner frame.RootCrisisButton.test.tsxpinning thatPracticeLibrarykeeps the overlay instandardmode β unknown routes fall through to standard, but safe-by-accident is not a contract.Verification
Follow-up (not in this PR)
Philosopher sequencing note:
medical-test-anxietyis card 3 of 12. On a wrong answer the announcement lands hard for a user with a real pending result. Recommend re-ordering it later in the deck, or excluding it from the first-served set on a Home cold-start.π€ Generated with Claude Code