Tier deferrals (manual passes owed)
Acceptance criteria that no automated tier in this repository can physically observe. Each is registered here with a named owner and a status; a PENDING entry does not block a merge, but it does mean a human owes a manual pass that nothing will fail if they skip.
Source: docs/tier-deferrals/*.md.
PASS-382 — the LIVE rollback drill against production
One deferred acceptance criterion from PASS-382 (Production topology: ECS Fargate, RDS PostgreSQL, S3/CloudFront). The tier's rollback is scripted and its script is reviewed; what has not been recorded is a run of it against the real account.
- Criterion:
Scenario: Rollback restores the previous task-definition revision
— as a LIVE drill against wp-prod: deploy a known-good release, deploy a
newer one, run scripts/ecs-rollback.sh, and confirm from /api/version
that the older commit is serving again.
-
Unobservable because: it requires two real releases in ECR and a deliberate rollback of the production service, which no automated tier in this repository performs. The drill log table in
docs/runbook.md(Drilling rollback on AWS) is where the live date lives; no row there means it has never been drilled live. -
Owner: Anthony Graca.
What IS reviewed
scripts/ecs-rollback.shnever rebuilds or re-registers: it points the service at a task-definition revision ECS already holds, refuses a target carrying the same image digest as what is running, and ends by fetching/api/versionand matching the commit.- The schema caveat is documented in
docs/runbook.md: rolling back across a migration that dropped or renamed something the old code still maps is refused by the schema guard, and the deployment circuit breaker restores the newer revision. That is AWS's documented platform behaviour, not an observation of this account, which is exactly what the live drill would turn it into.
The Lambda tier this record once covered as a second row, together with its
rollback script and the hermetic drill against fake aws doubles, was removed
in PASS-733.
PENDING does not block the merge. It does mean the production rollback is owed one recorded live run by a named human, and that no automated tier will notice if that run never happens.
PASS-385 — a retracting URL bar leaves no band under the sheet
One deferred acceptance criterion from PASS-385 (Sign-in overscroll exposes the theme surface behind the fixed blue/white front door — give the app its own scroll container). Every other criterion in that story is gated by a test that reds under a named revert; this is the only one no available tier can observe.
- Criterion:
Scenario: A retracting URL bar leaves no band under the sheet Given the sign-in content is shorter than the viewport And the mobile browser's URL bar is visible When the student scrolls and the URL bar retracts Then the sheet's bottom edge stays flush with the bottom of the viewport throughout And no band of any third colour appears between the sheet and the bottom of the viewport
-
Unobservable because: the criterion is about the divergence between the small viewport (
100svh, URL bar showing) and the large viewport (100lvh, URL bar retracted), and about the live transition between them. Headless Chromium — the only browser tier this repository has — renders no browser chrome at all, so100svh,100lvhand100dvhall resolve to the same number and there is no bar to retract. The scenario's own binding (test_app_shell_scroll_container_bdd.py, step "the mobile browser's URL bar is visible") probes those two units at runtime and fails on their equality, which is what the deferral rests on: not an opinion that the test is hard to write, but a measured fact about what this browser can produce. Playwright'sset_viewport_sizedoes not substitute — it resizes the layout viewport, sosvhandlvhsimply both change to the new value and stay equal. -
Observing tier: a real mobile browser on a real handset, with visible chrome that retracts on scroll — Safari on iOS and Chrome on Android are the two that matter for this app's students. Per CLAUDE.md's mobile-first rule and PASS-385's own VERIFICATION section: 360px, 390px and 430px, in both a light and a dark semester theme, with the URL bar cycled.
-
Owner: Anthony Graca
-
Status: PENDING
-
Evidence: the owner will open
/(sign-in) on a physical iOS Safari and a physical Android Chrome at each of the three widths, in thecsubandharry-potterthemes, scroll to make the URL bar retract and then reverse to bring it back, and record for each combination whether any band of a colour other than the sheet's#ffffffappears between the bottom of the sheet and the bottom of the viewport at any point during the transition — including mid-animation, which is where advh-versus-container mismatch shows most clearly. Screen recordings, not stills, since the criterion says "throughout". The recorded result replaces Status above withPASSED <ISO date>orFAILED <ISO date>.
What is already gated, and what this does not excuse
The app-shell change that this criterion is about is gated, twice over, by tests that do red under a revert:
app_shell_scroll_container.featurescenario 8 fails if any full-height screen is sized in a viewport unit while#rootis sized byinset: 0— which is the structural cause of the band. Reverting one route'smin-height: 100%to100dvhreds it.- Scenarios 1, 2, 3 and 7 drive a real compositor with elastic overscroll on and read the resulting pixels, so the general claim "no gesture uncovers the page canvas at either edge" is measured rather than argued.
What remains unobserved is narrower than the scenario text suggests: whether a
real URL-bar retraction, specifically, can still open a band. The app shell
removes the mechanism that produced it (nothing inside #root is sized in a
viewport unit any more, and #root itself is inset: 0 on a position: fixed
frame), but "the mechanism is gone" is a reading of the code, not an
observation of a device, and this file exists so that distinction is not
quietly lost.
PENDING does not block the merge. It does mean this story ships with a manual pass owed to a named human, and that no automated tier will notice if that pass is never done. Nothing in the test suite asserts on this file: writing it is what would make such an assertion pass, so it would gate nothing.
PASS-464 — obtaining SHS's ratification of the RPO/RTO figures
One deferred acceptance criterion from PASS-464 (Bind the stated RPO/RTO to measured behavior). Every other criterion in that story is gated by a test that reds under a named revert; this is the only one no available tier can observe.
- Criterion:
Also record the ratification status of both figures with SHS once obtained.
The recording half is gated — see
each_recovery_objective_records_its_ratification_status_with_shs in
backend/tests/test_backups_verified_restore_bdd.py, which asserts
docs/runbook.md carries a recognized RPO ratification status: /
RTO ratification status: line for each figure. What is deferred here is
narrower: the obtaining — SHS actually reviewing and agreeing to the 24h
RPO / 60-minute RTO figures.
-
Unobservable because: SHS's assent to a specific number is a fact about an external human's decision, communicated outside this repository (an email, a meeting, a signed document) — no test in this suite, or any tier available to it, has anything to read until that communication happens and someone transcribes its outcome. A test cannot query SHS's agreement any more than it can query whether a meeting occurred.
-
Observing tier: a named human confirming directly with SHS (email thread or meeting) and recording the outcome.
-
Owner: Anthony Graca
-
Status: PENDING
-
Evidence: once SHS provides written sign-off (an email or meeting notes agreeing to the 24-hour RPO and 60-minute RTO figures, or naming different ones), the owner will: (1) update
docs/runbook.md's two... ratification status:lines fromPENDINGtoRATIFIED(or update the RPO/RTO figures themselves, plusbackend/tests/backup_restore_conventions.py'sRPO/RTOconstants, if SHS asks for different numbers), and (2) replace Status above withPASSED <ISO date>, citing the email thread or meeting notes as the record consulted.
What is already gated, and what this does not excuse
Both figures are gated on everything a test can observe without SHS's involvement:
schedule_fits_rpo()(bound by "the deployed backup cadence fits the stated data-loss window") checks the deployedk8s/backup-cronjob.yamlschedule's own computed gap against RPO directly — no longer against the independent MAX_BACKUP_INTERVAL constant that merely happened to agree.restore_fits_rto()(bound by "the measured restore fits the stated time-to-restore budget",requires_tooling) times a real restore drill end to end and checks the measured wall-clock elapsed time against RTO.missing_ratification_statuses()(bound by "each recovery objective records its ratification status with SHS") checks the runbook records a recognized status word for each figure —PENDINGtoday.
PENDING does not block the merge. It does mean this story ships with a
manual pass owed to a named human, and no automated tier will notice if SHS
is never actually asked. Nothing in the test suite asserts on this file or
on the runbook's specific status word beyond "is it a recognized one" —
writing RATIFIED into the runbook without SHS's actual agreement would
satisfy the test but not the criterion, which is exactly why the obtaining
itself is deferred to a named human rather than encoded as a passing
assertion.
PASS-525 — the first full-recovery exercise against production
One deferred acceptance criterion from PASS-525 (Name and document the BCP and DRP around the existing recovery machinery): "The first full-recovery exercise is performed against the production topology once it exists (see PASS-382) and its date recorded."
- Criterion:
The first full-recovery exercise is performed against the production topology once it exists (see PASS-382) and its date recorded.
PASS-382/US-86 deployed the production topology on 2026-08-30
(docs/aws-production-deployment-log.md), so the "once it exists"
precondition is met and the exercise is owed now. What is deferred here is
narrower: performing the exercise itself and recording a real
PASSED <date> or FAILED <date> outcome — see
docs/continuity-and-recovery-plan.md's "First full-recovery exercise"
section, currently PENDING.
-
Unobservable because: no CI tier in this repository holds
wp-prodcredentials — the same structural reasonscripts/publish-frontend.shis operator-run rather than CI-run. Beyond credentials, there is currently no supported observability path into the production database at all:docs/aws-production-deployment-log.md's §2.19 records thatpsqlfrom a laptop is refused (PubliclyAccessible: false, isolated subnets, zero NAT gateways), ECS Exec is disabled (enableExecuteCommand: false, nossmmessagesendpoint), and the admin console is reachable only by a real CSUB SSO identity (there is no local login or break-glass account). The one working route — a hand-issuedRunTaskoverride on the migrate task definition — is an interactive operator action by construction, not something an unattended CI job can invoke. -
Observing tier: a named human, running the documented restore procedure (
docs/runbook.md's Backup and restore section) against the real production database (via theRunTaskroute above, or onceenableExecuteCommandlands — see §2.19's "Proposed fix, not yet done"), and recording the outcome. -
Owner: Anthony Graca
-
Status: PENDING
-
Evidence: once the exercise is performed, the owner will: (1) update
docs/continuity-and-recovery-plan.md's "First full-recovery exercise" status line fromPENDINGtoPASSED <ISO date>orFAILED <ISO date>and its date line to the ISO date the exercise was run, (2) record what was verified (a real production-shaped restore, checked by row value and count, not merely table names — the same bartest_backups_verified_restore_bdd.py's ephemeral-container drill already holds itself to), and (3) replace Status above with the same outcome, citing the exercise record consulted.
What is already gated, and what this does not excuse
Everything a test can observe without production credentials is gated by
test_continuity_and_recovery_plan_bdd.py:
- the plan document exists, names a real owner, and records a recognized
exercise-status word (
plan_owner()/exercise_status()); - every dependency it names resolves to a real, deployed stack
(
dependency_stack_problems()); - its RPO/RTO figures and ratification status agree with the CI-enforced
constants and the runbook (
declared_plan_objectives()); - its stated objectives are pinned to the deployed single-AZ database
configuration (
infra_is_single_az()/plan_states_single_az()); - every loss scenario cites a runbook procedure and script that are
actually real (
loss_scenario_problems()); - the recurring restore test it points to still exists and is still wired
into CI (
restore_drill_scenario_exists()/restore_drill_wired_in_ci()).
PENDING does not block the merge. It does mean this story ships with a
manual pass owed to a named human, and no automated tier will notice if the
exercise is never actually performed. Nothing in the test suite asserts on
this file or on the plan's specific status word beyond "is it a recognized
one" — writing PASSED into the plan without actually performing the
exercise would satisfy the test but not the criterion, which is exactly why
the exercise itself is deferred to a named human rather than encoded as a
passing assertion. test_continuity_and_recovery_plan_bdd.py's "The first
full-recovery exercise is recorded" scenario is xfail(strict=False) for
the same reason: it asserts the real claim (a dated PASSED/FAILED
outcome) and is expected to fail until that claim is true, rather than
being written to pass on a PENDING placeholder.