08.07 — Spec gaps (G-SPEC-1 to G-SPEC-3)#
Three gaps on business behavior vs the expected spec of a healthcare system.
G-SPEC-1 — History sorted by submission order, not by date#
Source#
// views/page_history.php
foreach ($_SESSION['history'] as $appointment) {
// ... render ...
}No usort. No sort. No sort step exists anywhere.
appointment.php pushes with array_push($_SESSION['history'], $_POST) — append to the end (it’s a pushback).
Unmet spec#
REQ-HIST-3 from the FRD:
Most recent calendar date first
(Reconstructed spec by AI — typical of a history system.)
Symptom#
Appointments appear in the order they were confirmed by the system, regardless of visit_date. A booking for 2026-12-31, submitted today (2026-05-22), and a booking for next week, submitted three days later (2026-05-25), end up displayed with the December booking above the next-week one.
Test#
# src/tests/scenarios/journey/history_ordering.py
"""History ordered most-recent calendar date first (REQ-HIST-3 / §9.8 gap).
Flow:
login → book #1 (visit_date = in 30 days) → book #2 (visit_date = tomorrow)
→ open history → verify card order: #2 above #1 (most recent first)
(intentional FAIL — CURA renders in submission order, §9.8 gap)
Pre-fragments: login_as_demo_user
Post-fragments: (none)
"""Intentionally failing test. Booking#1 (far date) then booking#2 (near date) should show #2 first. CURA shows them in insertion order — #1 on top. Documented failure.
G-SPEC-2 — Profile page = placeholder#
Source#
// views/page_profile.php
// renders the #profile section but contains no editable fields,
// no form, no API endpoint.
Symptom#
Logged-in users see “Profile” in the menu, navigate to it, and find an empty page. No form, no button, just text (placeholder).
Test#
# src/tests/scenarios/profile/view_profile.py
def scenario_view_profile(driver, logger):
on_profile = ProfilePage(driver=driver)
return [
drive_page(
act(on_profile, open_profile_page)...,
act(on_profile, verify_profile_is_placeholder)..., # PASS = documents the placeholder
),
]This test PASSES — it documents current behavior. Not a gap test; an exploratory trace.
If CURA ever adds a real profile page, verify_profile_is_placeholder breaks → revise the test.
G-SPEC-3 — Unauthorized access redirects to /, not to login#
Source#
// appointment.php
if (!$session_check) {
header("Location: " . SITE_URL); // ← redirects to /
exit;
}history.php does the same.
Expected spec#
Should redirect to /profile.php#login, not /. The user loses context (“I wanted my history”). Ergonomic flaw.
Symptom#
Unauthenticated user clicks a deep-link pointing at /appointment.php or /history.php → lands on the homepage → has to click “Make Appointment” again to reach the login page.
Test#
# src/tests/scenarios/login/unauthenticated_appointment_access.py
def scenario_unauthenticated_appointment_access(driver, logger):
on_appointment = AppointmentPage(driver=driver)
on_home = HomePage(driver=driver)
return [
drive_page(
act(on_appointment, open_appointment_page)...,
act(on_appointment, verify_redirected_to_home)..., # PASS = documents the behavior
),
drive_page(
act(on_home, verify_home_page)...,
),
]unauthenticated_appointment_access.py, unauthenticated_history_access.py, unauthenticated_profile_access.py.
All three tests PASS — they document exploration. With the FRD reconstructed and non-authoritative, we can’t call this a clear anomaly. We recommend and document.
Pattern: gap test vs exploratory pass#
Spec gaps are mostly exploratory-pass (documents current behavior) rather than intentional-fail (asserts a block that should exist but doesn’t).
| G-DATA-* | G-SPEC-* |
|---|---|
| “CURA accepts X, which it should reject” | “CURA does X instead of Y” |
| Gap test: assert rejection, intentional fail | Documentary test: assert current behavior, pass |
Assertive gap tests are reserved for journeys where a healthcare system should clearly reject the user. For minor spec divergences (history order, empty profile page, suboptimal redirect), document rather than assert.
The art of choosing#
CURA_TEST_STRATEGY.md:
When to add one [exploratory test]:
- A business-logic constraint is plausible but absent from the SFD (“can I book the same date twice in different slots?”).
- Decide before writing: is the current behaviour reasonable (→ exploratory / pass) or a gap (→ assertive / intentional fail)?
- Always pair with an SFD update.
Human decision before writing. No automatic toggle. That’s what keeps the strategy readable for a newcomer: every test sits in the category matching its intent.
IDENTIFIED_GAPS.md#
Every gap (DATA, SPEC, SEC) has an entry in IDENTIFIED_GAPS.md. Test name, docstring, and gap entry must be synchronized.
CLAUDE.md:
No SFD references outside
#comments. Test names, log messages, exception messages, docstrings — none containSFD §x.x. Those references belong inCURA_FRD.mdand in inline comments. The SFD number means nothing to someone reading a test report.
Test names are human-readable (Past date booking accepted, not Test_FRD_9_7). The §9.7 reference lives in code as a comment and in IDENTIFIED_GAPS.md.