Skip to content

Requirements traceability matrix

Every requirement tag on a Gherkin feature file becomes a row here, mapped to the stories tagged on that feature, its scenarios, the test modules that bind it, and the diagrams named after its stories. The Gaps section lists what the repository structure cannot vouch for.

Requirement Story Feature (scenarios) Test module(s) Diagrams Tier deferrals
DOC-A UC-1, UC-2, UC-3, UC-5, UC-7, UC-8, UC-10, UC-11, US-52, US-53, US-54, US-55, US-56, US-57, US-58, US-59 backfill_assessment_scoring.feature — The shipped feature is reviewed; Scoring and override are documented; Each shipped story is traced to its requirements; The reflection and quiz surfaces are realigned to the design; backfill_authentication_enrollment.feature — The shipped feature is reviewed; The feature has 4+1 documentation; Each shipped story is traced to its requirements; The sign-in and enroll surfaces are realigned to the design; backfill_challenge_builder.feature — The shipped feature is reviewed; The feature has a data-model and authoring documentation; Each shipped story is traced to its requirements; backfill_live_event_operations.feature — The shipped feature is reviewed; Override-with-audit and the live dashboard are documented; Each shipped story is traced to its requirements; The live dashboard surface is realigned to the design; backfill_passport_progress.feature — The shipped feature is reviewed; The feature has 4+1 documentation; Each shipped story is traced to its requirements; The passport and prize surfaces are realigned to the design; backfill_qr_checkin.feature — The shipped feature is reviewed; The core loop has a sequence diagram with exception paths; Each scenario is traced; The scan / check-in surface is realigned to the design; backfill_reporting_prize_export.feature — The shipped feature is reviewed; The reporting suite is documented; Each shipped story is traced to its requirements; backfill_wellness_guide.feature — The shipped safety feature is reviewed; Crisis routing is documented as code-driven; Each scenario is traced; The guide surface is realigned to the design test_backfill_assessment_scoring_bdd.py, test_backfill_authentication_enrollment_bdd.py, test_backfill_challenge_builder_bdd.py, test_backfill_live_event_operations_bdd.py, test_backfill_passport_progress_bdd.py, test_backfill_qr_checkin_bdd.py, test_backfill_reporting_prize_export_bdd.py, test_backfill_wellness_guide_bdd.py activity/pass63_eligibility_gate.puml, activity/pass64_view_passport_offline.puml, activity/pass65_checkin_exceptions.puml, activity/pass66_challenge_authoring.puml, activity/pass69_report_generation.puml, activity/pass70_manual_override_audit.puml, class/pass20_guide_seam.puml, class/pass56_data_model.puml, component/pass64_passport_read_path.puml, component/pass65_checkin_service.puml, component/pass69_reports_service.puml, sequence/pass20_guide_conversation.puml, sequence/pass56_ai_scoring.puml, sequence/pass56_qr_checkin.puml, sequence/pass56_sso_sign_in.puml, sequence/pass63_enrollment.puml, sequence/pass68_mcq_auto_scoring.puml, sequence/pass70_live_event_dashboard.puml, sequence/pass71_reskin_config.puml, state/pass56_challenge_lifecycle.puml, usecase/pass56_use_cases.puml
DOC-B UC-1, UC-2, UC-3, UC-5, UC-7, UC-8, UC-10, UC-11, US-52, US-53, US-54, US-55, US-56, US-57, US-58, US-59 backfill_assessment_scoring.feature — The shipped feature is reviewed; Scoring and override are documented; Each shipped story is traced to its requirements; The reflection and quiz surfaces are realigned to the design; backfill_authentication_enrollment.feature — The shipped feature is reviewed; The feature has 4+1 documentation; Each shipped story is traced to its requirements; The sign-in and enroll surfaces are realigned to the design; backfill_challenge_builder.feature — The shipped feature is reviewed; The feature has a data-model and authoring documentation; Each shipped story is traced to its requirements; backfill_live_event_operations.feature — The shipped feature is reviewed; Override-with-audit and the live dashboard are documented; Each shipped story is traced to its requirements; The live dashboard surface is realigned to the design; backfill_passport_progress.feature — The shipped feature is reviewed; The feature has 4+1 documentation; Each shipped story is traced to its requirements; The passport and prize surfaces are realigned to the design; backfill_qr_checkin.feature — The shipped feature is reviewed; The core loop has a sequence diagram with exception paths; Each scenario is traced; The scan / check-in surface is realigned to the design; backfill_reporting_prize_export.feature — The shipped feature is reviewed; The reporting suite is documented; Each shipped story is traced to its requirements; backfill_wellness_guide.feature — The shipped safety feature is reviewed; Crisis routing is documented as code-driven; Each scenario is traced; The guide surface is realigned to the design test_backfill_assessment_scoring_bdd.py, test_backfill_authentication_enrollment_bdd.py, test_backfill_challenge_builder_bdd.py, test_backfill_live_event_operations_bdd.py, test_backfill_passport_progress_bdd.py, test_backfill_qr_checkin_bdd.py, test_backfill_reporting_prize_export_bdd.py, test_backfill_wellness_guide_bdd.py activity/pass63_eligibility_gate.puml, activity/pass64_view_passport_offline.puml, activity/pass65_checkin_exceptions.puml, activity/pass66_challenge_authoring.puml, activity/pass69_report_generation.puml, activity/pass70_manual_override_audit.puml, class/pass20_guide_seam.puml, class/pass56_data_model.puml, component/pass64_passport_read_path.puml, component/pass65_checkin_service.puml, component/pass69_reports_service.puml, sequence/pass20_guide_conversation.puml, sequence/pass56_ai_scoring.puml, sequence/pass56_qr_checkin.puml, sequence/pass56_sso_sign_in.puml, sequence/pass63_enrollment.puml, sequence/pass68_mcq_auto_scoring.puml, sequence/pass70_live_event_dashboard.puml, sequence/pass71_reskin_config.puml, state/pass56_challenge_lifecycle.puml, usecase/pass56_use_cases.puml
DOC-C UC-1, UC-2, UC-3, UC-5, UC-7, UC-8, UC-10, UC-11, US-52, US-53, US-54, US-55, US-56, US-57, US-58, US-59 backfill_assessment_scoring.feature — The shipped feature is reviewed; Scoring and override are documented; Each shipped story is traced to its requirements; The reflection and quiz surfaces are realigned to the design; backfill_authentication_enrollment.feature — The shipped feature is reviewed; The feature has 4+1 documentation; Each shipped story is traced to its requirements; The sign-in and enroll surfaces are realigned to the design; backfill_challenge_builder.feature — The shipped feature is reviewed; The feature has a data-model and authoring documentation; Each shipped story is traced to its requirements; backfill_live_event_operations.feature — The shipped feature is reviewed; Override-with-audit and the live dashboard are documented; Each shipped story is traced to its requirements; The live dashboard surface is realigned to the design; backfill_passport_progress.feature — The shipped feature is reviewed; The feature has 4+1 documentation; Each shipped story is traced to its requirements; The passport and prize surfaces are realigned to the design; backfill_qr_checkin.feature — The shipped feature is reviewed; The core loop has a sequence diagram with exception paths; Each scenario is traced; The scan / check-in surface is realigned to the design; backfill_reporting_prize_export.feature — The shipped feature is reviewed; The reporting suite is documented; Each shipped story is traced to its requirements; backfill_wellness_guide.feature — The shipped safety feature is reviewed; Crisis routing is documented as code-driven; Each scenario is traced; The guide surface is realigned to the design test_backfill_assessment_scoring_bdd.py, test_backfill_authentication_enrollment_bdd.py, test_backfill_challenge_builder_bdd.py, test_backfill_live_event_operations_bdd.py, test_backfill_passport_progress_bdd.py, test_backfill_qr_checkin_bdd.py, test_backfill_reporting_prize_export_bdd.py, test_backfill_wellness_guide_bdd.py activity/pass63_eligibility_gate.puml, activity/pass64_view_passport_offline.puml, activity/pass65_checkin_exceptions.puml, activity/pass66_challenge_authoring.puml, activity/pass69_report_generation.puml, activity/pass70_manual_override_audit.puml, class/pass20_guide_seam.puml, class/pass56_data_model.puml, component/pass64_passport_read_path.puml, component/pass65_checkin_service.puml, component/pass69_reports_service.puml, sequence/pass20_guide_conversation.puml, sequence/pass56_ai_scoring.puml, sequence/pass56_qr_checkin.puml, sequence/pass56_sso_sign_in.puml, sequence/pass63_enrollment.puml, sequence/pass68_mcq_auto_scoring.puml, sequence/pass70_live_event_dashboard.puml, sequence/pass71_reskin_config.puml, state/pass56_challenge_lifecycle.puml, usecase/pass56_use_cases.puml
DOC-D PASS-383, PASS-384, PASS-472, PASS-479, UC-1, UC-2, UC-3, UC-7, UC-8, UC-11, US-52, US-53, US-54, US-56, US-57, US-59 backfill_assessment_scoring.feature — The shipped feature is reviewed; Scoring and override are documented; Each shipped story is traced to its requirements; The reflection and quiz surfaces are realigned to the design; backfill_authentication_enrollment.feature — The shipped feature is reviewed; The feature has 4+1 documentation; Each shipped story is traced to its requirements; The sign-in and enroll surfaces are realigned to the design; backfill_live_event_operations.feature — The shipped feature is reviewed; Override-with-audit and the live dashboard are documented; Each shipped story is traced to its requirements; The live dashboard surface is realigned to the design; backfill_passport_progress.feature — The shipped feature is reviewed; The feature has 4+1 documentation; Each shipped story is traced to its requirements; The passport and prize surfaces are realigned to the design; backfill_qr_checkin.feature — The shipped feature is reviewed; The core loop has a sequence diagram with exception paths; Each scenario is traced; The scan / check-in surface is realigned to the design; backfill_wellness_guide.feature — The shipped safety feature is reviewed; Crisis routing is documented as code-driven; Each scenario is traced; The guide surface is realigned to the design; design_of_record.feature — The design of record is imported and documented; A divergence inventory exists; Design tokens feed the frontend theme; Realignment work is routed to feature stories; first_party_default_theme.feature — The default skin renders CSUB's identity on a cold start; The CSUB theme is a first-class skin; Every shipped theme block declares where its values came from; The retired theme is gone from the frontend; The retired theme is gone from the backend; The retired theme is not a servable theme on a freshly seeded database; An existing database is migrated, not orphaned; The migration is safe on a database that already holds an admin-authored CSUB theme; The migration does not crash when both the retired and CSUB rows already exist; A freshly seeded database resolves the demo challenge's theme; Current-state documentation describes the shipped theme; loading_state_fade_through.feature — Data arriving before the reveal delay elapses never paints the loading state; A slow fetch fades the loading state in; Motion tokens exist as tokens, not inline values; Reduced motion still suppresses the flicker; Reduced motion collapses the fade but not the reveal delay; With motion allowed the same clock positions are still mid-fade; Button feedback is unaffected; An applied theme is remembered; A reload resumes on the remembered skin; A first-ever load still falls back to the default; The server remains the authority; Storage failure degrades quietly; The loading state never displaces the content it covers; The sign-in card is unchanged by a remembered non-default skin; No screen's loading branch paints a full-bleed slab; week_sheet_checkin_cta.feature — The week detail sheet restores the "Check in at event" CTA; The restored CTA reintroduces no self-service completion path; The CTA's scan path still completes the week; The CTA keeps a reachable touch target on a mobile viewport; The missed-week CTA uses the design's distinct "Catch up" label and icon test_backfill_assessment_scoring_bdd.py, test_backfill_authentication_enrollment_bdd.py, test_backfill_live_event_operations_bdd.py, test_backfill_passport_progress_bdd.py, test_backfill_qr_checkin_bdd.py, test_backfill_wellness_guide_bdd.py, test_design_of_record_bdd.py, test_first_party_default_theme_bdd.py, test_loading_state_fade_through_bdd.py, test_week_sheet_checkin_cta_bdd.py, frontend/src/components/LoadingScreen/LoadingScreen.test.tsx, frontend/src/theme/ThemePersistence.crossrunner.test.tsx activity/pass384_theme_id_migration.puml, activity/pass63_eligibility_gate.puml, activity/pass64_view_passport_offline.puml, activity/pass65_checkin_exceptions.puml, activity/pass70_manual_override_audit.puml, class/pass20_guide_seam.puml, class/pass383_motion_tokens_and_theme_storage.puml, class/pass384_theme_provenance.puml, class/pass56_data_model.puml, component/pass383_frame_sampler_tier.puml, component/pass472_overlay_mount_gate.puml, component/pass479_clock_probe_seam.puml, component/pass64_passport_read_path.puml, component/pass65_checkin_service.puml, sequence/pass20_guide_conversation.puml, sequence/pass383_loading_fade_through.puml, sequence/pass383_theme_bootstrap_persistence.puml, sequence/pass472_deterministic_overlay_probe.puml, sequence/pass479_reduced_motion_clock_probe.puml, sequence/pass56_ai_scoring.puml, sequence/pass56_qr_checkin.puml, sequence/pass56_sso_sign_in.puml, sequence/pass63_enrollment.puml, sequence/pass68_mcq_auto_scoring.puml, sequence/pass70_live_event_dashboard.puml, usecase/pass56_use_cases.puml
FR-A1 sign_in_fixed_csub_identity.feature — Sign-in's hero and CTA use fixed CSUB tokens, never the semester theme's; The sheet and its captions use a fixed neutral surface, not the theme surface; Sign-in renders fixed institutional copy, not useThemeCopy(); The installed PWA identity and the sign-in hero agree test_sign_in_fixed_csub_identity_bdd.py
FR-A2 sign_in_fixed_csub_identity.feature — Sign-in's hero and CTA use fixed CSUB tokens, never the semester theme's; The sheet and its captions use a fixed neutral surface, not the theme surface; Sign-in renders fixed institutional copy, not useThemeCopy(); The installed PWA identity and the sign-in hero agree test_sign_in_fixed_csub_identity_bdd.py
FR-A4 UC-1 role_based_access_control.feature — Student is denied access to the admin builder; Admin reaches admin surfaces; Direct API access is authorized by role test_role_based_access_control_bdd.py
FR-B1 admin_topbar_responsive.feature — The topbar wraps instead of overflowing at phone widths; Every topbar control keeps a 44x44px touch target; The topbar's flex children are allowed to shrink and wrap; The topbar fits the viewport and the page does not scroll horizontally; challenge_builder_date_field_overflow.feature — Every two-up date field row clears the default min-width floor; The date field rows and the modal that holds them both bound their grid track minimums; Window start, Window end, Start date, and End date all keep a 44px touch target; The Window start / Window end and Start date / End date rows do not overlap or overflow the modal on a real phone viewport test_admin_topbar_responsive_bdd.py, test_challenge_builder_date_field_overflow_bdd.py
FR-B4 PASS-383, PASS-384, PASS-472, PASS-479, UC-2, UC-5 first_party_default_theme.feature — The default skin renders CSUB's identity on a cold start; The CSUB theme is a first-class skin; Every shipped theme block declares where its values came from; The retired theme is gone from the frontend; The retired theme is gone from the backend; The retired theme is not a servable theme on a freshly seeded database; An existing database is migrated, not orphaned; The migration is safe on a database that already holds an admin-authored CSUB theme; The migration does not crash when both the retired and CSUB rows already exist; A freshly seeded database resolves the demo challenge's theme; Current-state documentation describes the shipped theme; live_challenge_visibility.feature — The admin can see which published challenge students are seeing; Editing a challenge nobody is seeing says so; A campus resolves exactly one active challenge; loading_state_fade_through.feature — Data arriving before the reveal delay elapses never paints the loading state; A slow fetch fades the loading state in; Motion tokens exist as tokens, not inline values; Reduced motion still suppresses the flicker; Reduced motion collapses the fade but not the reveal delay; With motion allowed the same clock positions are still mid-fade; Button feedback is unaffected; An applied theme is remembered; A reload resumes on the remembered skin; A first-ever load still falls back to the default; The server remains the authority; Storage failure degrades quietly; The loading state never displaces the content it covers; The sign-in card is unchanged by a remembered non-default skin; No screen's loading branch paints a full-bleed slab; offline_themed_fonts.featurehistorical, superseded by PASS-221 (self_hosted_fonts.feature) — The themed display font renders with no connection; A missing font never blocks the passport; self_hosted_fonts.feature — The passport asks no third party for its type; A theme's display face renders before it has ever been seen; The passport survives a launch with no connection; The CSP names no outside origin for fonts; theme_applies_app_wide.feature — A signed-in student can resolve the active theme with no passport of their own; A signed-in admin can resolve the active theme too; A signed-in but non-current student still resolves the campus's theme; No session at all is refused, not served a themeless default; A campus with no active challenge resolves to the app default; Switching the active challenge's theme is reflected on the very next request; Sign-in's precondition (no session) is refused by the theme endpoint too test_first_party_default_theme_bdd.py, test_live_challenge_visibility_bdd.py, test_loading_state_fade_through_bdd.py, test_self_hosted_fonts_bdd.py, test_theme_applies_app_wide_bdd.py, frontend/src/components/LoadingScreen/LoadingScreen.test.tsx, frontend/src/theme/ThemePersistence.crossrunner.test.tsx activity/pass384_theme_id_migration.puml, class/pass383_motion_tokens_and_theme_storage.puml, class/pass384_theme_provenance.puml, component/pass383_frame_sampler_tier.puml, component/pass472_overlay_mount_gate.puml, component/pass479_clock_probe_seam.puml, sequence/pass383_loading_fade_through.puml, sequence/pass383_theme_bootstrap_persistence.puml, sequence/pass472_deterministic_overlay_probe.puml, sequence/pass479_reduced_motion_clock_probe.puml
FR-B5 PASS-379, UC-9 challenge_authoring_by_hand.feature — The challenge builder offers no document import; The import endpoint is gone; Hand-authoring a challenge is unaffected; Route resolution is undisturbed by the removal; No application code sends a document to a model test_challenge_authoring_by_hand_bdd.py, frontend/src/components/admin/ChallengeBuilder/ChallengeBuilder.test.tsx activity/pass66_challenge_authoring.puml, class/pass56_data_model.puml
FR-B6 UC-5 duplicate_challenge.feature — Duplicate creates an editable draft; Editing the copy does not affect the original test_duplicate_challenge_bdd.py
FR-B7 PASS-390, UC-21 staff_notification_queue.feature — A proposed notification is not sent until staff act; Staff send a proposed notification; Staff skip a proposed notification; Staff edit the copy before sending; Staff compose a broadcast to students with an incomplete week; A challenge with notifications disabled sends nothing; A student cannot reach the notification queue; Every send decision is attributable test_staff_notification_queue_bdd.py activity/pass390_broadcast_audience.puml, class/pass390_notification_queue_model.puml, component/pass390_queue_authoring_seam.puml, sequence/pass390_staff_decision.puml, state/pass390_notification_decision_lifecycle.puml
FR-C1 UC-2, UC-5 installed_app_exits.feature — An un-enrolled student launches the installed app; The way out survives having no browser chrome; Nothing published is still not a dead end; A student already in the challenge is not asked to join again; live_challenge_visibility.feature — The admin can see which published challenge students are seeing; Editing a challenge nobody is seeing says so; A campus resolves exactly one active challenge test_installed_app_exits_bdd.py, test_live_challenge_visibility_bdd.py
FR-C2 UC-2 missed_weeks_stay_open.feature — A week I missed stays open instead of locking; Missing a week does not lock the weeks after it; A week whose window has not opened is still locked; Catching up requires the same evidence as any check-in; A catch-up completion counts toward the prize; Catching up cannot be done from the passport alone; passport_scan_fab_signout_overlap.feature — The Scan FAB's fixed offset clears the sign-out bar's tallest possible band, computed for wrapped pills; The screen's own bottom padding clears the full fixed-chrome stack; The Scan FAB and Sign out both keep a 44x44px touch target; The Scan FAB and the sign-out bar do not overlap in a real browser test_missed_weeks_stay_open_bdd.py, test_passport_scan_fab_signout_overlap_bdd.py
FR-C4 PASS-9, PASS-385, PASS-388, PASS-442, UC-2, UC-21 app_shell_scroll_container.feature — Overscrolling past the top of sign-in never reveals the theme surface; Overscrolling past the bottom of sign-in never reveals the theme surface; The seam does not return under a different semester theme; A retracting URL bar leaves no band under the sheet; The browser chrome matches the front door; Full-height routes still scroll their content to the end; An inner scroller does not chain its scroll to the document; No full-height stylesheet mixes dynamic and static viewport units against the same root; app_update_activation.feature — A returning student is not left on a stale shell; An update arriving mid-session is announced, not silently applied; Accepting the update actually applies it; The service worker prompts before activating a new version; installed_app_exits.feature — An un-enrolled student launches the installed app; The way out survives having no browser chrome; Nothing published is still not a dead end; A student already in the challenge is not asked to join again; offline_themed_fonts.featurehistorical, superseded by PASS-221 (self_hosted_fonts.feature) — The themed display font renders with no connection; A missing font never blocks the passport; pwa_browser_coverage.feature — Sign-in survives an active service worker; The app is installable in a real browser; Offline viewing serves the last-synced passport; A missing icon fails the browser tier; self_hosted_fonts.feature — The passport asks no third party for its type; A theme's display face renders before it has ever been seen; The passport survives a launch with no connection; The CSP names no outside origin for fonts; service_worker_push.feature — A push event renders a notification; Tapping a notification focuses an already-open app; Tapping with the app closed opens the passport; A payload naming a week deep-links to that week; The push handler ships without disturbing the update flow test_app_shell_scroll_container_bdd.py, test_app_update_activation_bdd.py, test_installed_app_exits_bdd.py, test_pwa_browser_coverage_bdd.py, test_self_hosted_fonts_bdd.py, test_service_worker_push_bdd.py, frontend/src/a11y.test.tsx, frontend/src/components/Passport/Passport.test.tsx, frontend/src/components/UpdateBanner/UpdateBanner.test.tsx, frontend/src/pwa/pushSw.test.tsx, frontend/src/pwa/useAppUpdate.test.tsx activity/pass385_overscroll_paint_path.puml, activity/pass388_notification_click_routing.puml, activity/pass442_update_wait_discipline.puml, class/pass9_update_surface.puml, component/pass385_app_shell_scroll_model.puml, component/pass385_overscroll_gate_seam.puml, component/pass388_push_sw_build_seam.puml, sequence/pass388_push_notification_click.puml, sequence/pass9_update_activation.puml docs/tier-deferrals/PASS-385-url-bar-retraction.md
FR-C5 UC-2 missed_weeks_stay_open.feature — A week I missed stays open instead of locking; Missing a week does not lock the weeks after it; A week whose window has not opened is still locked; Catching up requires the same evidence as any check-in; A catch-up completion counts toward the prize; Catching up cannot be done from the passport alone test_missed_weeks_stay_open_bdd.py
FR-C6 UC-2 missed_weeks_stay_open.feature — A week I missed stays open instead of locking; Missing a week does not lock the weeks after it; A week whose window has not opened is still locked; Catching up requires the same evidence as any check-in; A catch-up completion counts toward the prize; Catching up cannot be done from the passport alone test_missed_weeks_stay_open_bdd.py
FR-C7 PASS-387, PASS-389, UC-21 notification_preferences.feature — Reminders are off until I opt in; The pre-prompt precedes the browser prompt; Accepting the pre-prompt registers this device; The client can fetch the key it needs to subscribe; The key is withheld while the feature is dark; The preference categories are the ones the worker actually emits; I can keep new-week reminders and drop expiring ones; Turning reminders off stops delivery while permission remains granted; A blocked browser permission is explained, not retried; iOS in a browser tab is told to install first; The reminders control is usable on a phone; push_subscription_storage.feature — A signed-in student registers a device; Re-registering the same device does not duplicate it; A student cannot delete another student's subscription; The feature ships dark; Deleting a student removes their device subscriptions; The new routes are classified by the authorization sweep test_notification_preferences_bdd.py, test_push_subscription_storage_bdd.py, frontend/src/components/Reminders/Reminders.test.tsx activity/pass389_toggle_decision.puml, class/pass387_push_subscription_model.puml, class/pass389_notification_preference_seam.puml, component/pass389_preference_client_seam.puml, sequence/pass387_push_subscribe.puml, sequence/pass389_preprompt_opt_in.puml, state/pass389_reminder_permission_states.puml
FR-C8 PASS-388, PASS-391, PASS-392, UC-21 in_app_reminder_banner.feature — A student without push sees the reminder in the app; A skipped notification never appears in-app; Dismissal persists across reloads; Another student's challenge reminder is not shown to me; The banner does not crowd out the passport on a phone; notification_scheduling.feature — A new week proposes a reminder; An ending challenge proposes an expiry reminder; A draft challenge proposes nothing; A proposal is made once, not once per run; Dispatch reaches every opted-in device exactly once; An overlapping run cannot double-send; A gone device is garbage-collected; Students who never opted in receive nothing; The scheduled run is the command the cluster actually runs; The dispatch ships dark; service_worker_push.feature — A push event renders a notification; Tapping a notification focuses an already-open app; Tapping with the app closed opens the passport; A payload naming a week deep-links to that week; The push handler ships without disturbing the update flow test_in_app_reminder_banner_bdd.py, test_notification_scheduling_bdd.py, test_service_worker_push_bdd.py, frontend/src/a11y.test.tsx, frontend/src/components/Passport/Passport.test.tsx, frontend/src/components/ReminderBanner/ReminderBanner.test.tsx, frontend/src/pwa/pushSw.test.tsx activity/pass388_notification_click_routing.puml, activity/pass391_proposal_run.puml, activity/pass392_banner_visibility_decision.puml, class/pass391_notification_scheduling_model.puml, class/pass392_in_app_feed_model.puml, component/pass388_push_sw_build_seam.puml, component/pass391_notification_entrypoints.puml, component/pass392_fallback_channel_seam.puml, deployment/pass391_scheduler_topology.puml, sequence/pass388_push_notification_click.puml, sequence/pass391_dispatch_fanout.puml, sequence/pass392_in_app_banner_render.puml, state/pass391_notification_lifecycle.puml
FR-D1 UC-3 qr_event_binding.feature — Scanning a week's code credits exactly that week; A code from a previous challenge is rejected; A stale poster does not credit a replacement task; A legacy code without event identity is rejected; scanned_qr_only_checkin.feature — The passport offers no self-service completion; Scanning the live event QR still completes the week; A completion request carrying no scanned token is refused; A student cannot self-credit a week they did not attend; Staff verification remains available; An admin override remains available and audited; Reporting can trust the automatic bucket test_qr_event_binding_bdd.py, test_scanned_qr_only_checkin_bdd.py
FR-D2 UC-3 qr_event_binding.feature — Scanning a week's code credits exactly that week; A code from a previous challenge is rejected; A stale poster does not credit a replacement task; A legacy code without event identity is rejected test_qr_event_binding_bdd.py
FR-D3 UC-4 staff_scan_verification.feature — Attendant verifies a student for the active task; Attendant cannot verify a duplicate completion test_staff_scan_verification_bdd.py
FR-D4 UC-3, UC-4, UC-11 live_event_dashboard.feature — Generate the event QR; Live count updates as students check in; qr_event_binding.feature — Scanning a week's code credits exactly that week; A code from a previous challenge is rejected; A stale poster does not credit a replacement task; A legacy code without event identity is rejected; scanned_qr_only_checkin.feature — The passport offers no self-service completion; Scanning the live event QR still completes the week; A completion request carrying no scanned token is refused; A student cannot self-credit a week they did not attend; Staff verification remains available; An admin override remains available and audited; Reporting can trust the automatic bucket; staff_scan_verification.feature — Attendant verifies a student for the active task; Attendant cannot verify a duplicate completion test_live_event_dashboard_bdd.py, test_qr_event_binding_bdd.py, test_scanned_qr_only_checkin_bdd.py, test_staff_scan_verification_bdd.py
FR-D5 UC-3 rotating_qr_token.feature — Fresh token is accepted; Stale token is rejected; Forged or tampered token is rejected test_rotating_qr_token_bdd.py
FR-D6 UC-11 manual_override.feature — Admin manually marks a completion; Admin overrides an existing completion test_manual_override_bdd.py
FR-D7 UC-3, UC-10 manual_checkin_provenance.feature — The manual bucket separates audited overrides from legacy self-reports; scanned_qr_only_checkin.feature — The passport offers no self-service completion; Scanning the live event QR still completes the week; A completion request carrying no scanned token is refused; A student cannot self-credit a week they did not attend; Staff verification remains available; An admin override remains available and audited; Reporting can trust the automatic bucket; week_sheet_checkin_cta.feature — The week detail sheet restores the "Check in at event" CTA; The restored CTA reintroduces no self-service completion path; The CTA's scan path still completes the week; The CTA keeps a reachable touch target on a mobile viewport; The missed-week CTA uses the design's distinct "Catch up" label and icon test_manual_checkin_provenance_bdd.py, test_scanned_qr_only_checkin_bdd.py, test_week_sheet_checkin_cta_bdd.py
FR-E1 UC-6 post_checkin_tip.feature — Tip is shown after a check-in; Tip is personalized by progress; Model calls are server-side with no PHI test_post_checkin_tip_bdd.py
FR-E2 PASS-378, UC-7 guide_conversation.feature — Guide answers a wellness question from grounded content; Guide is skinned to the active theme; Conversations are minimally logged with no PHI; guide_dormant_for_pilot.feature — The wellness guide chat is dormant for the pilot; Crisis resources stay available with the guide disabled; The guide answers again when the flag is on test_guide_conversation_bdd.py, test_guide_dormant_for_pilot_bdd.py, frontend/src/App.test.tsx, frontend/src/components/BottomNav/BottomNav.test.tsx, frontend/src/components/Passport/KnowledgeCheck.test.tsx, frontend/src/components/admin/ChallengeBuilder/ScoreOverridePanel.test.tsx, frontend/src/theme/ThemePersistence.crossrunner.test.tsx, frontend/src/types/assessment.test.ts activity/pass378_guide_flag_gate.puml, class/pass378_reflection_review_seam.puml, sequence/pass378_reflection_review.puml
FR-E3 PASS-378, UC-7 guide_dormant_for_pilot.feature — The wellness guide chat is dormant for the pilot; Crisis resources stay available with the guide disabled; The guide answers again when the flag is on; guide_guardrails.feature — Out-of-scope medical request is declined; Crisis signal triggers immediate escalation; Responses stay grounded and refuse to invent test_guide_dormant_for_pilot_bdd.py, test_guide_guardrails_bdd.py, frontend/src/App.test.tsx, frontend/src/components/BottomNav/BottomNav.test.tsx, frontend/src/components/Passport/KnowledgeCheck.test.tsx, frontend/src/components/admin/ChallengeBuilder/ScoreOverridePanel.test.tsx, frontend/src/theme/ThemePersistence.crossrunner.test.tsx, frontend/src/types/assessment.test.ts activity/pass378_guide_flag_gate.puml, class/pass378_reflection_review_seam.puml, sequence/pass378_reflection_review.puml
FR-E4 UC-8 mcq_scoring.feature — Correct answer is scored instantly; Incorrect answer is scored instantly with feedback test_mcq_scoring_bdd.py
FR-E5 UC-8 scoredby_contract.feature — Every scorer value the API serves is one the contract admits; The frontend contract cannot carry a scorer it does not know test_scoredby_contract_bdd.py
FR-E6 PASS-378, PASS-393, UC-6, UC-7, UC-8, UC-21 guide_conversation.feature — Guide answers a wellness question from grounded content; Guide is skinned to the active theme; Conversations are minimally logged with no PHI; no_student_text_to_a_model.feature — A student can still write a free-text reflection; Submitting a reflection sends nothing to a third-party model; Staff review reflections without scoring them; A reviewed reflection records who reviewed it and when; Reflections do not distort learning-outcome means; Production boots without an Anthropic key; Production still refuses an unsafe configuration; The compliance record matches the runtime; post_checkin_tip.feature — Tip is shown after a check-in; Tip is personalized by progress; Model calls are server-side with no PHI; push_notification_privacy.feature — The subprocessor is disclosed; The no-subprocessor answer accounts for the push path; Notification payloads carry no student-identifying content; The device identifier has a stated retention rule; Every new requirement is traceable test_guide_conversation_bdd.py, test_no_student_text_to_a_model_bdd.py, test_post_checkin_tip_bdd.py, test_push_notification_privacy_bdd.py, frontend/src/App.test.tsx, frontend/src/components/BottomNav/BottomNav.test.tsx, frontend/src/components/Passport/KnowledgeCheck.test.tsx, frontend/src/components/admin/ChallengeBuilder/ScoreOverridePanel.test.tsx, frontend/src/theme/ThemePersistence.crossrunner.test.tsx, frontend/src/types/assessment.test.ts activity/pass378_guide_flag_gate.puml, class/pass378_reflection_review_seam.puml, component/pass393_payload_minimization_seam.puml, sequence/pass378_reflection_review.puml, sequence/pass393_push_egress_trust_boundary.puml
FR-F1 PASS-394, PASS-470, PASS-471, UC-10 aggregate_report_csv_export.feature — Each report can be downloaded as CSV; The CSV agrees with the dashboard; A suppressed cell exports blank, never zero; An unanswered outcome tag is distinguishable from a hidden one; An empty report still exports a header row; Attendance still exports its structural zero rows; Filenames identify the challenge; A student role cannot reach the exports; All four CSV download controls fit a phone screen; participation_report.feature — Report shows enrollment and per-week completion; Report reflects new check-ins; per_event_export.feature — Every event gets a row, including the ones nobody attended; Rows carry the event's format and venue; Per-event method counts reconcile with the event's completions; Totals reconcile with the attendance report; A high-interest low-turnout event is visible; Response latency is blank when it cannot be computed; A suppressed row hides its method columns too; A student role cannot reach the export; The per-event download control fits a phone screen; reporting_dashboard_auto_refresh.feature — Numbers update while staff simply watch the screen; The dashboard says how current its numbers are; A failed read ages the stamp instead of blanking the screen; A dashboard that has stopped updating says so; A dashboard nobody is looking at stops querying; Closing the dashboard stops the polling; The freshness stamp fits the title block on a phone test_aggregate_report_csv_export_bdd.py, test_participation_report_bdd.py, test_per_event_export_bdd.py, test_reporting_dashboard_auto_refresh_bdd.py, frontend/src/components/admin/Reports/Reports.autorefresh.test.tsx, frontend/src/components/admin/Reports/Reports.csvexport.test.tsx, frontend/src/components/admin/Reports/Reports.perevent.test.tsx activity/pass470_per_event_export.puml, activity/pass471_aggregate_csv_export.puml, component/pass394_gherkin_vitest_execution_binding.puml, pass27_small_cell_suppression.puml, pass69_reports_service.puml, sequence/pass394_reporting_autorefresh.puml, state/pass394_read_freshness.puml
FR-F2 PASS-470, PASS-471, UC-10 aggregate_report_csv_export.feature — Each report can be downloaded as CSV; The CSV agrees with the dashboard; A suppressed cell exports blank, never zero; An unanswered outcome tag is distinguishable from a hidden one; An empty report still exports a header row; Attendance still exports its structural zero rows; Filenames identify the challenge; A student role cannot reach the exports; All four CSV download controls fit a phone screen; attendance_report.feature — Attendance is broken down by method; Auto share is highlighted; per_event_export.feature — Every event gets a row, including the ones nobody attended; Rows carry the event's format and venue; Per-event method counts reconcile with the event's completions; Totals reconcile with the attendance report; A high-interest low-turnout event is visible; Response latency is blank when it cannot be computed; A suppressed row hides its method columns too; A student role cannot reach the export; The per-event download control fits a phone screen test_aggregate_report_csv_export_bdd.py, test_attendance_report_bdd.py, test_per_event_export_bdd.py, frontend/src/components/admin/Reports/Reports.csvexport.test.tsx, frontend/src/components/admin/Reports/Reports.perevent.test.tsx activity/pass470_per_event_export.puml, activity/pass471_aggregate_csv_export.puml, pass27_small_cell_suppression.puml, pass69_reports_service.puml
FR-F3 PASS-470, PASS-471, UC-10 aggregate_report_csv_export.feature — Each report can be downloaded as CSV; The CSV agrees with the dashboard; A suppressed cell exports blank, never zero; An unanswered outcome tag is distinguishable from a hidden one; An empty report still exports a header row; Attendance still exports its structural zero rows; Filenames identify the challenge; A student role cannot reach the exports; All four CSV download controls fit a phone screen; engagement_report.feature — Report shows content views and guide usage; per_event_export.feature — Every event gets a row, including the ones nobody attended; Rows carry the event's format and venue; Per-event method counts reconcile with the event's completions; Totals reconcile with the attendance report; A high-interest low-turnout event is visible; Response latency is blank when it cannot be computed; A suppressed row hides its method columns too; A student role cannot reach the export; The per-event download control fits a phone screen test_aggregate_report_csv_export_bdd.py, test_engagement_report_bdd.py, test_per_event_export_bdd.py, frontend/src/components/admin/Reports/Reports.csvexport.test.tsx, frontend/src/components/admin/Reports/Reports.perevent.test.tsx activity/pass470_per_event_export.puml, activity/pass471_aggregate_csv_export.puml, pass27_small_cell_suppression.puml, pass69_reports_service.puml
FR-F4 PASS-378, PASS-471, UC-8, UC-10 aggregate_report_csv_export.feature — Each report can be downloaded as CSV; The CSV agrees with the dashboard; A suppressed cell exports blank, never zero; An unanswered outcome tag is distinguishable from a hidden one; An empty report still exports a header row; Attendance still exports its structural zero rows; Filenames identify the challenge; A student role cannot reach the exports; All four CSV download controls fit a phone screen; learning_outcome_report.feature — Scores aggregate by outcome tag; Human-overridden scores are included; no_student_text_to_a_model.feature — A student can still write a free-text reflection; Submitting a reflection sends nothing to a third-party model; Staff review reflections without scoring them; A reviewed reflection records who reviewed it and when; Reflections do not distort learning-outcome means; Production boots without an Anthropic key; Production still refuses an unsafe configuration; The compliance record matches the runtime test_aggregate_report_csv_export_bdd.py, test_learning_outcome_report_bdd.py, test_no_student_text_to_a_model_bdd.py, frontend/src/App.test.tsx, frontend/src/components/BottomNav/BottomNav.test.tsx, frontend/src/components/Passport/KnowledgeCheck.test.tsx, frontend/src/components/admin/ChallengeBuilder/ScoreOverridePanel.test.tsx, frontend/src/components/admin/Reports/Reports.csvexport.test.tsx, frontend/src/components/admin/Reports/Reports.perevent.test.tsx, frontend/src/theme/ThemePersistence.crossrunner.test.tsx, frontend/src/types/assessment.test.ts activity/pass378_guide_flag_gate.puml, activity/pass471_aggregate_csv_export.puml, class/pass378_reflection_review_seam.puml, pass69_reports_service.puml, sequence/pass378_reflection_review.puml
FR-F5 UC-10 prize_export.feature — Export contains only prize-eligible students; Export reflects derived eligibility test_prize_export_bdd.py
FR-F6 PASS-470, UC-10 per_event_export.feature — Every event gets a row, including the ones nobody attended; Rows carry the event's format and venue; Per-event method counts reconcile with the event's completions; Totals reconcile with the attendance report; A high-interest low-turnout event is visible; Response latency is blank when it cannot be computed; A suppressed row hides its method columns too; A student role cannot reach the export; The per-event download control fits a phone screen; reporting_privacy.feature — Reports never contain PHI; Small aggregates respect privacy test_per_event_export_bdd.py, test_reporting_privacy_bdd.py, frontend/src/components/admin/Reports/Reports.perevent.test.tsx activity/pass470_per_event_export.puml, pass27_small_cell_suppression.puml, pass69_reports_service.puml
FR-F7 PASS-469, PASS-470, PASS-471, UC-10 aggregate_report_csv_export.feature — Each report can be downloaded as CSV; The CSV agrees with the dashboard; A suppressed cell exports blank, never zero; An unanswered outcome tag is distinguishable from a hidden one; An empty report still exports a header row; Attendance still exports its structural zero rows; Filenames identify the challenge; A student role cannot reach the exports; All four CSV download controls fit a phone screen; engagement_detail_export.feature — Enrolled students who did nothing appear with zeros; A partial completer is not excluded; Method columns reconcile with weeks completed; Reflections never contribute a score; Prize eligibility agrees with the prize export; Re-exporting the same challenge is byte-identical; The export carries no PHI and no name; Pulling the export is recorded; A student role cannot reach the export; A challenge from another campus is not exportable; Both export buttons fit a phone screen; per_event_export.feature — Every event gets a row, including the ones nobody attended; Rows carry the event's format and venue; Per-event method counts reconcile with the event's completions; Totals reconcile with the attendance report; A high-interest low-turnout event is visible; Response latency is blank when it cannot be computed; A suppressed row hides its method columns too; A student role cannot reach the export; The per-event download control fits a phone screen test_aggregate_report_csv_export_bdd.py, test_engagement_detail_export_bdd.py, test_per_event_export_bdd.py, frontend/src/components/admin/Reports/Reports.csvexport.test.tsx, frontend/src/components/admin/Reports/Reports.perevent.test.tsx activity/pass469_engagement_detail_export.puml, activity/pass470_per_event_export.puml, activity/pass471_aggregate_csv_export.puml, pass27_small_cell_suppression.puml, pass56_data_model.puml, pass69_reports_service.puml
INF-A1 architecture_diagrams.feature — All five 4+1 views are present as PlantUML sources; Sources follow the house convention and render cleanly; The scenarios view traces to the use cases test_architecture_diagrams_bdd.py
INF-A2 architecture_diagrams.feature — All five 4+1 views are present as PlantUML sources; Sources follow the house convention and render cleanly; The scenarios view traces to the use cases test_architecture_diagrams_bdd.py
INF-B1 docs_image_ci.feature — The docs image builds with Docker as the only toolchain; A regression inside the docs image fails the build loudly; The docker-only docs build has its own pipeline step; docs_render_fallback.feature — Render falls back to docker when java is absent but docker is present; Render prints clear guidance when neither java nor docker is available; Render falls back to docker when graphviz is absent on an otherwise-java host; Render prints clear guidance when graphviz is absent and docker is unavailable; docs_site_build.feature — One command renders diagrams and builds the site; Toolchain is pinned and consistent; Build artifacts are not committed; Local preview is available test_docs_image_ci_bdd.py, test_docs_render_fallback_bdd.py, test_docs_site_build_bdd.py
INF-B2 docs_nav_labels.feature — No nav label carries a story key; The gate flags a label that carries a story key; A diagram gaining a story key needs no nav edit; Provenance is recorded in the traceability matrix test_docs_nav_labels_bdd.py
INF-B3 PASS-485, PASS-487, PASS-489, PASS-494 convention_module_roots_stay_argument_derived.feature — A second existence gate re-added to any probe is invisible from a tmp tree carrying only the CLI; A path frozen at import time off the real repo would have hidden that gap; Every artifact those probes need still resolves to the committed file in the real tree; A frozen Path added tomorrow is discovered; The enumeration is derived and non-empty; Every discovered helper is callable, none silently dropped; cross_runner_render_seam_binding.feature — The Vitest render-seam proofs run under the same PR gate as the pytest suite; A hollowed-out render-seam proof fails the gate instead of passing silently; No pytest binding gates a render-seam proof on a Vitest test-name string; feature_file_bindings.feature — Every executable feature file has a binding module; The gate flags an unbound feature file that claims no successor; An archived feature names a successor that is itself bound; The gate flags an archive marker that has gone stale; An archived feature keeps its row in the traceability matrix; Every feature name the gate counts as bound resolves to a real feature file; The gate ignores a binding whose path resolves outside the features directory; The gate's own test modules contain no raw binding-call literal; require_assertions_roots_fail_loud.feature — A tree whose meta config and fixtures are gone fails instead of skipping; An absent Vitest binary is the only condition that still skips; The real meta config and fixtures still execute, so the honored-feature scenarios really run; tier_deferral_enforcement.feature — Every tier-deferral names an alternate enforcement artifact present in the tree; Every tier-deferral's alternate enforcement tier is invoked by a CI job; The require-assertions probe's frontend fallback exists and runs in the GitHub Actions workflow; tier_deferral_registry_completeness.feature — Every requires_* marker conftest.py defines has a tier deferral or allowlist entry; Every marker make test-api deselects has a tier deferral or allowlist entry; Every raw pytest.mark.skip call site has a tier deferral or allowlist entry; An allowlist entry without a justification is rejected; vitest_require_assertions_honored.feature — An assertion-free test body fails under the installed Vitest; A body asserting only through a third-party matcher still fails; A body with a real Vitest assertion passes under the same config; vitest_spec_binding_fails_loud.feature — A probe whose spec file no longer exists fails instead of skipping; An absent Vitest binary is the only condition that still skips; The unchanged spec still executes, so the Vitest-tier scenarios really run feature_binding_conventions.py, test_convention_module_roots_stay_argument_derived_bdd.py, test_cross_runner_render_seam_binding_bdd.py, test_feature_file_bindings_bdd.py, test_require_assertions_roots_fail_loud_bdd.py, test_tier_deferral_enforcement_bdd.py, test_tier_deferral_registry_completeness_bdd.py, test_vitest_require_assertions_honored_bdd.py, test_vitest_spec_binding_fails_loud_bdd.py activity/pass485_vitest_tier_skip_or_fail.puml, activity/pass487_require_assertions_roots_skip_or_fail.puml, activity/pass489_second_gate_observability.puml, activity/pass494_new_frozen_path_is_discovered.puml, component/pass485_vitest_tier_convention.puml, component/pass487_require_assertions_roots_parameterization.puml, component/pass489_convention_module_path_surface.puml, component/pass494_frozen_path_discovery_sweep.puml
INF-C1 container_images.feature — Each service has a Dockerfile that builds; The docs image builds hermetically; Images are tagged by commit test_container_images_bdd.py
INF-D1 k8s_manifests.feature — The full set applies from the kustomize base; Every managed Deployment is listed in the kustomization; The demo carries no real student data; Reachability is healthchecked test_k8s_manifests_bdd.py
INF-D2 k8s_manifests.feature — The full set applies from the kustomize base; Every managed Deployment is listed in the kustomization; The demo carries no real student data; Reachability is healthchecked test_k8s_manifests_bdd.py
INF-E1 PASS-302, PASS-307, PASS-318, PASS-325 publish_provenance.feature — Merge publishes docs and demo; The published site carries the merge provenance; Publication is verified at the edge; Rollout waits gate on managed Deployments only; pytest_marker_registration.feature — Every @pass-NNN tag in the feature files is a registered marker; Collecting the suite emits no unknown-mark warning for a pass_* tag; A newly added @pass-NNN tag needs no pyproject.toml edit; An in-process pytest session leaves the parent's marker-registration config intact; A session that configures but never unconfigures does not desync a later pair test_publish_provenance_bdd.py, test_pytest_marker_registration_bdd.py
INF-E2 PASS-302, PASS-307, PASS-318, PASS-325 publish_provenance.feature — Merge publishes docs and demo; The published site carries the merge provenance; Publication is verified at the edge; Rollout waits gate on managed Deployments only; pytest_marker_registration.feature — Every @pass-NNN tag in the feature files is a registered marker; Collecting the suite emits no unknown-mark warning for a pass_* tag; A newly added @pass-NNN tag needs no pyproject.toml edit; An in-process pytest session leaves the parent's marker-registration config intact; A session that configures but never unconfigures does not desync a later pair test_publish_provenance_bdd.py, test_pytest_marker_registration_bdd.py
INF-E3 PASS-399, PASS-416, PASS-420, PASS-423, PASS-442, PASS-485, PASS-487, PASS-489, PASS-494 bitbucket_pipelines.feature — Every PR runs the gate; The gate runs on shell runners; The gate is reproducible locally; Merge to the default branch builds, pushes, and deploys (gated); The deploy freeze switch fails safe; Secrets come from repository variables; A manual deploy/rollback path exists; browser_tier_pr_gate.feature — The PR gate runs the mobile layout tier; The gate unsets DOCKER_HOST before the docker-dependent layout tier runs; The layout tier selects exactly the mobile browser scenarios, and nothing heavier; A pipeline that only runs by hand does not count as automatic enforcement; The remaining heavy browser slice stays off the gate; The layout tier reports its skip reason instead of a bare "s"; The still-deferred nightly tiers name an owner and a policy for going red; ci_gate_visibility.feature — make test-api reports skip reasons like test-model and test-cluster; Every gated pytest target in the Makefile reports skip reasons; convention_module_roots_stay_argument_derived.feature — A second existence gate re-added to any probe is invisible from a tmp tree carrying only the CLI; A path frozen at import time off the real repo would have hidden that gap; Every artifact those probes need still resolves to the committed file in the real tree; A frozen Path added tomorrow is discovered; The enumeration is derived and non-empty; Every discovered helper is callable, none silently dropped; cross_runner_render_seam_binding.feature — The Vitest render-seam proofs run under the same PR gate as the pytest suite; A hollowed-out render-seam proof fails the gate instead of passing silently; No pytest binding gates a render-seam proof on a Vitest test-name string; docs_image_ci.feature — The docs image builds with Docker as the only toolchain; A regression inside the docs image fails the build loudly; The docker-only docs build has its own pipeline step; gate_duration_instrumentation.feature — Every command in the PR gate is timed, but the shell-mutating lines are not; The timing wrapper never changes whether a command passed; The wrapper records a command's real elapsed time; The report names every timed command, slowest first; Every dependency the PR gate installs has a declared cache; The declared Playwright cache is the directory Playwright really uses; The PR gate step actually emits the duration report, not just wraps commands; The wrapper never swallows a command's real exit code or output; The report still names a command that failed, and the code it failed with; require_assertions_roots_fail_loud.feature — A tree whose meta config and fixtures are gone fails instead of skipping; An absent Vitest binary is the only condition that still skips; The real meta config and fixtures still execute, so the honored-feature scenarios really run; tier_deferral_enforcement.feature — Every tier-deferral names an alternate enforcement artifact present in the tree; Every tier-deferral's alternate enforcement tier is invoked by a CI job; The require-assertions probe's frontend fallback exists and runs in the GitHub Actions workflow; tier_deferral_registry_completeness.feature — Every requires_* marker conftest.py defines has a tier deferral or allowlist entry; Every marker make test-api deselects has a tier deferral or allowlist entry; Every raw pytest.mark.skip call site has a tier deferral or allowlist entry; An allowlist entry without a justification is rejected; update_activation_wait_discipline.feature — A slow activation past the base deadline is waited out, not failed; A genuinely settled stale shell is reported without burning the ceiling; A never-settling activation gives up at the ceiling naming what it saw; A reload the page triggers under the poll counts as progress; A runner declared slower is given proportionally longer to activate; The scale the browser E2E pipeline step declares is what carries a slow activation past the base deadline; vitest_require_assertions_honored.feature — An assertion-free test body fails under the installed Vitest; A body asserting only through a third-party matcher still fails; A body with a real Vitest assertion passes under the same config; vitest_spec_binding_fails_loud.feature — A probe whose spec file no longer exists fails instead of skipping; An absent Vitest binary is the only condition that still skips; The unchanged spec still executes, so the Vitest-tier scenarios really run test_bitbucket_pipelines_bdd.py, test_browser_tier_pr_gate_bdd.py, test_ci_gate_visibility_bdd.py, test_convention_module_roots_stay_argument_derived_bdd.py, test_cross_runner_render_seam_binding_bdd.py, test_docs_image_ci_bdd.py, test_gate_duration_instrumentation_bdd.py, test_require_assertions_roots_fail_loud_bdd.py, test_tier_deferral_enforcement_bdd.py, test_tier_deferral_registry_completeness_bdd.py, test_update_activation_wait_discipline_bdd.py, test_vitest_require_assertions_honored_bdd.py, test_vitest_spec_binding_fails_loud_bdd.py activity/pass399_layout_tier_selection.puml, activity/pass416_gate_step_timing.puml, activity/pass420_gate_report_rendering.puml, activity/pass442_update_wait_discipline.puml, activity/pass485_vitest_tier_skip_or_fail.puml, activity/pass487_require_assertions_roots_skip_or_fail.puml, activity/pass489_second_gate_observability.puml, activity/pass494_new_frozen_path_is_discovered.puml, component/pass399_browser_tier_pr_gate.puml, component/pass416_gate_duration_instrumentation.puml, component/pass485_vitest_tier_convention.puml, component/pass487_require_assertions_roots_parameterization.puml, component/pass489_convention_module_path_surface.puml, component/pass494_frozen_path_discovery_sweep.puml
INF-F1 PASS-381, UC-19 no_live_model_tier.feature — No test is gated on model credentials; The default suite selector names no model tier; No test constructs a vendor SDK exception; The remaining deferral tiers still work; A genuine failure in the remaining suite still fails loud test_no_live_model_tier_bdd.py
INF-F2 PASS-381, UC-19 no_live_model_tier.feature — No test is gated on model credentials; The default suite selector names no model tier; No test constructs a vendor SDK exception; The remaining deferral tiers still work; A genuine failure in the remaining suite still fails loud test_no_live_model_tier_bdd.py
NFR-1 PASS-470, UC-10 per_event_export.feature — Every event gets a row, including the ones nobody attended; Rows carry the event's format and venue; Per-event method counts reconcile with the event's completions; Totals reconcile with the attendance report; A high-interest low-turnout event is visible; Response latency is blank when it cannot be computed; A suppressed row hides its method columns too; A student role cannot reach the export; The per-event download control fits a phone screen; reporting_privacy.feature — Reports never contain PHI; Small aggregates respect privacy test_per_event_export_bdd.py, test_reporting_privacy_bdd.py, frontend/src/components/admin/Reports/Reports.perevent.test.tsx activity/pass470_per_event_export.puml, pass27_small_cell_suppression.puml, pass69_reports_service.puml
NFR-2 UC-12 browser_deployment_path.feature — A student signs in through the campus IdP and reaches their passport; A deep route survives a hard refresh; A deep route opened cold is not bounced back to sign-in; deployment_path.feature — The SPA and API are served as one origin; An API miss is a JSON 404, never the app shell; An unconfigured deployment refuses to start; Data survives a redeploy test_browser_deployment_path_bdd.py, test_deployment_path_bdd.py
NFR-5 PASS-383, PASS-385, PASS-399, PASS-472, PASS-479 admin_topbar_responsive.feature — The topbar wraps instead of overflowing at phone widths; Every topbar control keeps a 44x44px touch target; The topbar's flex children are allowed to shrink and wrap; The topbar fits the viewport and the page does not scroll horizontally; app_shell_scroll_container.feature — Overscrolling past the top of sign-in never reveals the theme surface; Overscrolling past the bottom of sign-in never reveals the theme surface; The seam does not return under a different semester theme; A retracting URL bar leaves no band under the sheet; The browser chrome matches the front door; Full-height routes still scroll their content to the end; An inner scroller does not chain its scroll to the document; No full-height stylesheet mixes dynamic and static viewport units against the same root; browser_tier_pr_gate.feature — The PR gate runs the mobile layout tier; The gate unsets DOCKER_HOST before the docker-dependent layout tier runs; The layout tier selects exactly the mobile browser scenarios, and nothing heavier; A pipeline that only runs by hand does not count as automatic enforcement; The remaining heavy browser slice stays off the gate; The layout tier reports its skip reason instead of a bare "s"; The still-deferred nightly tiers name an owner and a policy for going red; challenge_builder_date_field_overflow.feature — Every two-up date field row clears the default min-width floor; The date field rows and the modal that holds them both bound their grid track minimums; Window start, Window end, Start date, and End date all keep a 44px touch target; The Window start / Window end and Start date / End date rows do not overlap or overflow the modal on a real phone viewport; loading_state_fade_through.feature — Data arriving before the reveal delay elapses never paints the loading state; A slow fetch fades the loading state in; Motion tokens exist as tokens, not inline values; Reduced motion still suppresses the flicker; Reduced motion collapses the fade but not the reveal delay; With motion allowed the same clock positions are still mid-fade; Button feedback is unaffected; An applied theme is remembered; A reload resumes on the remembered skin; A first-ever load still falls back to the default; The server remains the authority; Storage failure degrades quietly; The loading state never displaces the content it covers; The sign-in card is unchanged by a remembered non-default skin; No screen's loading branch paints a full-bleed slab; passport_scan_fab_signout_overlap.feature — The Scan FAB's fixed offset clears the sign-out bar's tallest possible band, computed for wrapped pills; The screen's own bottom padding clears the full fixed-chrome stack; The Scan FAB and Sign out both keep a 44x44px touch target; The Scan FAB and the sign-out bar do not overlap in a real browser test_admin_topbar_responsive_bdd.py, test_app_shell_scroll_container_bdd.py, test_browser_tier_pr_gate_bdd.py, test_challenge_builder_date_field_overflow_bdd.py, test_loading_state_fade_through_bdd.py, test_passport_scan_fab_signout_overlap_bdd.py, frontend/src/components/LoadingScreen/LoadingScreen.test.tsx, frontend/src/theme/ThemePersistence.crossrunner.test.tsx activity/pass385_overscroll_paint_path.puml, activity/pass399_layout_tier_selection.puml, class/pass383_motion_tokens_and_theme_storage.puml, component/pass383_frame_sampler_tier.puml, component/pass385_app_shell_scroll_model.puml, component/pass385_overscroll_gate_seam.puml, component/pass399_browser_tier_pr_gate.puml, component/pass472_overlay_mount_gate.puml, component/pass479_clock_probe_seam.puml, sequence/pass383_loading_fade_through.puml, sequence/pass383_theme_bootstrap_persistence.puml, sequence/pass472_deterministic_overlay_probe.puml, sequence/pass479_reduced_motion_clock_probe.puml docs/tier-deferrals/PASS-385-url-bar-retraction.md
NFR-6 PASS-383, PASS-384, PASS-472, PASS-479 first_party_default_theme.feature — The default skin renders CSUB's identity on a cold start; The CSUB theme is a first-class skin; Every shipped theme block declares where its values came from; The retired theme is gone from the frontend; The retired theme is gone from the backend; The retired theme is not a servable theme on a freshly seeded database; An existing database is migrated, not orphaned; The migration is safe on a database that already holds an admin-authored CSUB theme; The migration does not crash when both the retired and CSUB rows already exist; A freshly seeded database resolves the demo challenge's theme; Current-state documentation describes the shipped theme; loading_state_fade_through.feature — Data arriving before the reveal delay elapses never paints the loading state; A slow fetch fades the loading state in; Motion tokens exist as tokens, not inline values; Reduced motion still suppresses the flicker; Reduced motion collapses the fade but not the reveal delay; With motion allowed the same clock positions are still mid-fade; Button feedback is unaffected; An applied theme is remembered; A reload resumes on the remembered skin; A first-ever load still falls back to the default; The server remains the authority; Storage failure degrades quietly; The loading state never displaces the content it covers; The sign-in card is unchanged by a remembered non-default skin; No screen's loading branch paints a full-bleed slab; theme_applies_app_wide.feature — A signed-in student can resolve the active theme with no passport of their own; A signed-in admin can resolve the active theme too; A signed-in but non-current student still resolves the campus's theme; No session at all is refused, not served a themeless default; A campus with no active challenge resolves to the app default; Switching the active challenge's theme is reflected on the very next request; Sign-in's precondition (no session) is refused by the theme endpoint too test_first_party_default_theme_bdd.py, test_loading_state_fade_through_bdd.py, test_theme_applies_app_wide_bdd.py, frontend/src/components/LoadingScreen/LoadingScreen.test.tsx, frontend/src/theme/ThemePersistence.crossrunner.test.tsx activity/pass384_theme_id_migration.puml, class/pass383_motion_tokens_and_theme_storage.puml, class/pass384_theme_provenance.puml, component/pass383_frame_sampler_tier.puml, component/pass472_overlay_mount_gate.puml, component/pass479_clock_probe_seam.puml, sequence/pass383_loading_fade_through.puml, sequence/pass383_theme_bootstrap_persistence.puml, sequence/pass472_deterministic_overlay_probe.puml, sequence/pass479_reduced_motion_clock_probe.puml
NFR-8 UC-7 guide_guardrails.feature — Out-of-scope medical request is declined; Crisis signal triggers immediate escalation; Responses stay grounded and refuse to invent test_guide_guardrails_bdd.py
PR-A2 explicit_staff_role_mapping.feature — Mapped staff member receives the admin role; Unmapped affiliation values grant no privileges; Role map changes require no code change test_explicit_staff_role_mapping_bdd.py
PR-B1 UC-14 deploy_time_migration.feature — Kubernetes migrates before the app serves traffic; A developer can migrate a fresh checkout; The documented Run path works on a fresh checkout; production_database.feature — App runs against PostgreSQL; Schema changes are applied by migration; Startup does not mutate schema; schema_migrations.feature — A new column reaches a database that already exists; A database behind the code does not fail silently test_deploy_time_migration_bdd.py, test_production_database_bdd.py, test_schema_migrations_bdd.py
PR-B2 clean_production_data.feature — Production startup seeds nothing; Demo seeding requires an explicit dev flag; Reports contain no demo artifacts test_clean_production_data_bdd.py
PR-B3 PASS-38, UC-14 backups_verified_restore.feature — Backups run automatically; Restore drill is executed before launch; Recovery objectives are stated test_backups_verified_restore_bdd.py activity/pass38_restore_drill.puml, component/pass38_backup_tooling.puml, deployment/pass38_backup_restore_topology.puml
PR-C1 secrets_management.feature — Production refuses default secrets; Secrets come from the managed store; Exposed secrets are rotated and invalidated; Local secret files are ignored by git test_secrets_management_bdd.py
PR-C2 UC-2 self_hosted_fonts.feature — The passport asks no third party for its type; A theme's display face renders before it has ever been seen; The passport survives a launch with no connection; The CSP names no outside origin for fonts; web_session_hardening.feature — Session cookie is Secure and HttpOnly; HTTP requests are redirected to HTTPS; API docs are not public; Security headers are present test_self_hosted_fonts_bdd.py, test_web_session_hardening_bdd.py
PR-C3 rate_limiting.feature — Check-in endpoint throttles a hammering client; Auth callback is rate limited; Legitimate event bursts are not blocked test_rate_limiting_bdd.py
PR-D1 staging_deployment.feature — Containers build from the repository; Staging deploys from committed definitions; Production and staging match; Rollback is a defined operation; staging_rollback_drill.feature — Rollback restores the previous release on staging; A rollback that does not revert is caught by the drill; The rollback drill runs against a live staging cluster when enabled test_staging_deployment_bdd.py, test_staging_rollback_drill_bdd.py
PR-D2 monitoring_health_checks.feature — Downtime triggers an alert; Error-rate spike is visible; Logs are usable without exposing students test_monitoring_health_checks_bdd.py
PR-F1 accessibility_conformance.feature — Automated accessibility gate runs in CI; Manual assistive-technology pass is performed; ACR is produced test_accessibility_conformance_bdd.py
PR-F2 PASS-393, UC-21 push_notification_privacy.feature — The subprocessor is disclosed; The no-subprocessor answer accounts for the push path; Notification payloads carry no student-identifying content; The device identifier has a stated retention rule; Every new requirement is traceable; vendor_security_package.feature — HECVAT Lite is complete and current; Every citation resolves to the line it names; Every configuration fact carries a citation; Dependency audit gates CI; DAST baseline is triaged; Authorization sweep passes; Session-guarded sweep passes; Every row is classified as stating a live value or not; A row declared to state no live value cannot quietly start stating one test_push_notification_privacy_bdd.py, test_vendor_security_package_bdd.py component/pass393_payload_minimization_seam.puml, sequence/pass393_push_egress_trust_boundary.puml
PR-F3 event_scale_load_validation.feature — Event burst succeeds within targets; Reports remain responsive at scale; Load-test results are recorded test_event_scale_load_validation_bdd.py

Gaps

Derived, not asserted — each line is a missing tag, binding, or artifact:

  • FR-A3 appears in docs but no feature file carries its tag
  • FR-A5 appears in docs but no feature file carries its tag
  • FR-B2 appears in docs but no feature file carries its tag
  • FR-B3 appears in docs but no feature file carries its tag
  • FR-C3 appears in docs but no feature file carries its tag
  • NFR-4 appears in docs but no feature file carries its tag
  • PR-A1 appears in docs but no feature file carries its tag
  • PR-E1 appears in docs but no feature file carries its tag
  • PR-E2 appears in docs but no feature file carries its tag
  • PR-E3 appears in docs but no feature file carries its tag
  • SEC-5 appears in docs but no feature file carries its tag
  • offline_themed_fonts.feature is bound by no test module
  • diagram sources whose pass key matches no @pass-tagged feature, so no row claims them (add the @pass-NNN tag to the owning feature file, or a # diagrams: note): activity/pass8_installed_app_exits.puml, activity/pass27_small_cell_suppression.puml, activity/pass30_fail_closed_boot.puml, activity/pass31_boot_schema_guard.puml, activity/pass37_startup_seed_gating.puml, activity/pass40_secret_validation.puml, activity/pass52_a11y_conformance_process.puml, activity/pass53_vendor_security_package.puml, activity/pass54_load_validation.puml, activity/pass56_crisis_routing.puml, activity/pass61_deploy_gating.puml, activity/pass78_docs_image_gate.puml, activity/pass79_render_fallback.puml, activity/pass218_citation_anchor_check.puml, activity/pass248_boot_schema_check.puml, activity/pass270_catchup_gate.puml, activity/pass271_scan_only_checkin.puml, activity/pass280_manual_provenance_split.puml, activity/pass291_week_sheet_checkin_cta.puml, class/pass18_tip_seam.puml, class/pass171_scoredby_contract.puml, component/pass4_rbac_enforcement.puml, component/pass6_e2e_tier.puml, component/pass31_migration_toolchain.puml, component/pass52_a11y_toolchain.puml, component/pass53_security_toolchain.puml, component/pass56_codebase_organization.puml, component/pass56_system_components.puml, component/pass57_docs_toolchain.puml, component/pass58_container_images.puml, component/pass59_deploy_pipeline.puml, component/pass60_provenance_stamp.puml, component/pass61_bitbucket_pipeline.puml, component/pass71_design_of_record.puml, component/pass78_docs_image_ci.puml, component/pass221_font_asset_pipeline.puml, component/pass225_feature_archive.puml, component/pass248_migration_entrypoints.puml, component/pass322_week_cta_render_gate.puml, component/pass327_cross_runner_render_seam_binding.puml, component/pass339_require_assertions_meta_gate.puml, component/pass346_ci_gate_skip_visibility.puml, component/pass348_tier_deferral_enforcement.puml, component/pass352_tier_deferral_registry_completeness.puml, deployment/pass30_compose_stack.puml, deployment/pass36_production_database_topology.puml, deployment/pass45_staging_topology.puml, deployment/pass53_dast_scan_topology.puml, deployment/pass54_load_topology.puml, deployment/pass56_demo_topology.puml, deployment/pass59_k8s_topology.puml, deployment/pass61_ci_topology.puml, deployment/pass248_migration_topology.puml, sequence/pass4_role_denied_access.puml, sequence/pass6_signin_with_service_worker.puml, sequence/pass7_font_cache.puml, sequence/pass11_rotating_qr.puml, sequence/pass14_staff_scan_verification.puml, sequence/pass16_active_challenge_resolution.puml, sequence/pass18_post_checkin_tip.puml, sequence/pass23_override_labelling.puml, sequence/pass34_staff_role_mapping.puml, sequence/pass41_session_hardening.puml, sequence/pass42_rate_limiting.puml, sequence/pass46_monitoring_alerting.puml, sequence/pass60_publish_verification.puml, sequence/pass163_browser_signin_refresh.puml, sequence/pass221_self_hosted_fonts.puml, sequence/pass248_deploy_time_migration.puml, sequence/pass273_theme_bootstrap.puml, sequence/pass275_rollback_drill.puml, sequence/pass339_require_assertions_probe.puml