feat: garden review fixes — honest dose answer grows it, quiet after crisis, no-promise texts (ADR-015)
CI / ruff · pytest (pull_request) Successful in 2m21s
CI / ruff · pytest (pull_request) Successful in 2m21s
Refs #120 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ from sqlalchemy import select
|
||||
from app.config import Settings
|
||||
from app.core import clock
|
||||
from app.db import session
|
||||
from app.db.clinical import DailyCheckin, Dose
|
||||
from app.db.clinical import Alert, DailyCheckin, Dose
|
||||
from app.main import app
|
||||
from app.services.garden import compute, load_config
|
||||
from scripts.seed_demo import seed
|
||||
@@ -83,6 +83,50 @@ async def test_andrey_has_a_living_garden_that_grows_and_ignores_mood(client: As
|
||||
assert any(i["activity"] == "diary" for i in after["today"])
|
||||
|
||||
|
||||
async def test_honest_skip_grows_like_taken_and_missed_does_not(client: AsyncClient) -> None:
|
||||
"""#120: the garden rewards an honest answer, never a «taken» mark — otherwise it would push to false marks."""
|
||||
token = (await seed(12)).andrey_token
|
||||
url = f"/api/v1/me/{token}/garden"
|
||||
base = (await client.get(url)).json()["points"]
|
||||
async with session.get_clinical_session() as s:
|
||||
for d in (await s.scalars(select(Dose).where(Dose.token == token))).all():
|
||||
await s.delete(d)
|
||||
none = (await client.get(url)).json()["points"]
|
||||
|
||||
async def with_dose(status: str) -> int:
|
||||
async with session.get_clinical_session() as s:
|
||||
for d in (await s.scalars(select(Dose).where(Dose.token == token))).all():
|
||||
await s.delete(d)
|
||||
s.add(Dose(token=token, prescription_id=1, planned_at=clock.now(), status=status, answered_at=clock.now()))
|
||||
return (await client.get(url)).json()["points"]
|
||||
|
||||
assert await with_dose("taken") == await with_dose("skipped") > none
|
||||
assert await with_dose("missed") == none
|
||||
assert base >= none
|
||||
|
||||
|
||||
async def test_quiet_after_recent_high_alert(client: AsyncClient) -> None:
|
||||
"""#120: no celebration after a crisis signal from any source; an old or moderate alert does not silence it."""
|
||||
token = (await seed(12)).andrey_token
|
||||
url = f"/api/v1/me/{token}/garden"
|
||||
async with session.get_clinical_session() as s:
|
||||
for a in (await s.scalars(select(Alert).where(Alert.token == token))).all():
|
||||
await s.delete(a)
|
||||
assert (await client.get(url)).json()["quiet"] is False
|
||||
|
||||
def alert(level: str, hours_ago: int) -> Alert:
|
||||
ts = clock.now() - timedelta(hours=hours_ago)
|
||||
return Alert(token=token, ts=ts, level=level, code="test", reason="test", params={})
|
||||
|
||||
async with session.get_clinical_session() as s:
|
||||
s.add_all([alert("moderate", 1), alert("acute", 24 * 10)])
|
||||
assert (await client.get(url)).json()["quiet"] is False
|
||||
async with session.get_clinical_session() as s:
|
||||
s.add(alert("high", 2))
|
||||
quiet = (await client.get(url)).json()
|
||||
assert quiet["quiet"] is True and quiet["points"] > 0
|
||||
|
||||
|
||||
async def test_unknown_patient_404(client: AsyncClient) -> None:
|
||||
await seed(0)
|
||||
assert (await client.get("/api/v1/me/nobody/garden")).status_code == 404
|
||||
|
||||
Reference in New Issue
Block a user