Commit Graph
9 Commits
Author SHA1 Message Date
timmy d9f82299d0 test: prove schema conformance and refusal with a committed vision corpus (#18)
Quality gates / quality (pull_request) Successful in 2m26s
The worker contract was only proven by one happy-path fixture and a handful of
inline assertions, so nothing continuously checked that a reply Timmy cannot use
is refused instead of guessed at.

Corpus: a CC0 synthetic corpus (stool, non-stool, blur, glare, empty bowl,
malformed response) generated deterministically by scripts/build_vision_corpus.py.
Every fixture records its sha256, provenance, licence, case class, the provider
reply it replays, and the outcome that reply must produce. loadVisionCorpus
refuses a fixture whose bytes no longer match the manifest, so the corpus cannot
be edited into a different test. No real medical imagery, camera, or third-party
content is involved.

Contract fixes the corpus exposed:
- A schema-valid reply with a null form and colour is now an abstention
  (abstainedFor: unusable_visual_fields) instead of a hard provider failure. The
  declared response schema permits those nulls, so treating the reply as an error
  was wrong; it now abstains calmly and still prefill nothing.
- Fail-closed replies carry a machine-readable code (invalid_json, invalid_fields)
  instead of prose matching, and visionFailureResponse() maps them to plain,
  user-safe copy with no provider text, image bytes, or credentials echoed. A
  running server now returns that copy for unparsable and out-of-range replies.

Evidence: unit corpus contract and hash integrity, corpus-wide conformance
through the real analysis path, the same corpus through a running server.mjs with
a stub worker (200 abstain vs 503 fail-closed, no leaked bytes), and a real
browser acceptance run for the refusal UI. The release demo replays three corpus
cases through the real code path so the video shows the status the server would
actually send, with the on-camera caption gated by the release builder.
2026-10-11 08:14:36 +00:00
timmy 4cc5f4f7b1 feat: user-reported hard-stool follow-up with deterministic red-flag handoff (#67)
Quality gates / quality (pull_request) Successful in 2m53s
Field finding #67: a hard/lumpy (Bristol 1-2) entry now asks a short follow-up
before saving — difficult to pass, soreness, visible red blood, truly
black/sticky/tarry versus dark brown, and dehydration. Every answer is
user-reported and starts unanswered; nothing is inferred from the photo, and
answering "dark brown" never silently escalates as black stool.

A confirmed red-flag answer writes the same symptom flag manual logging already
uses, so the existing deterministic escalation is the only escalation path.
Mild reports get concise non-diagnostic self-care that states the photo cannot
rule out bleeding, and it is withdrawn whenever a red flag is confirmed.

- src/followup.js: pure follow-up contract (9 unit tests, tests/followup.test.js)
- app.js + styles.css: follow-up block on the safety step for Type 1-2 entries only
- tests/followup.acceptance.mjs: browser acceptance incl. that the AI suggestion
  surface still contains no symptom wording
- CI + release builder gates: npm run test:followup, syntax checks, manifest gate
- scripts/record_release_demo.mjs: records the real follow-up, mild guidance, and
  the black/tarry alert handoff with synthetic data
2026-10-09 08:10:43 +00:00
timmy 5aee7436f2 feat: make AI suggestions visibly provisional and correction-first (#13)
Quality gates / quality (pull_request) Successful in 1m45s
Suggested, confirmed, and corrected AI states are now distinct in the log
sheet, and correcting a suggested value clears the AI-confirmed state while
keeping every user-entered field. Screen-reader copy states the AI confidence
and who is in control.

- src/suggestion.js: provenance state machine (pending/confirmed/corrected/manual)
- app.js: renders provenance on the scan result and log steps, tracks corrections
- tests/suggestion.test.js: unit coverage for the state machine and a11y copy
- tests/provisional-suggestion.acceptance.mjs: browser acceptance + screenshots
- record_release_demo.mjs: demo now reviews, confirms, and corrects the suggestion
- CI, release builder, and release notes gate the new contract
2026-10-08 08:09:10 +00:00
timmy dce668e72b feat: guarantee manual fallback and in-session draft recovery (#12)
Quality gates / quality (pull_request) Successful in 1m54s
Logging must never depend on AI availability, and an unsaved entry must not
disappear when the user navigates away mid-log.

- add src/vision-readiness.js so the photo flow consumes one readiness contract
- when the worker is offline/disabled/unknown, offer no AI action and no
  analysis-consent prompt, and keep manual Bristol entry one action away
- add src/draft.js and make the draft own the photo so a chosen photo and
  entered context survive a recoverable close or navigation, with a visible
  kept-draft summary and an explicit start over
- drafts stay in session memory only: a photo awaiting consent is never
  persisted, and reload starts clean
- service worker now refuses to cache image bodies in addition to analysis
  requests and no-store responses
- tests: 2 new unit files, 3 service-worker privacy assertions (1 hold-out),
  1 browser acceptance file, release-demo and CI/package assertions
- release demo now visibly replays the vision-offline pass and the retained
  draft with synthetic data and an in-script assertion
2026-10-07 08:12:43 +00:00
timmy 463dff7f22 feat: harden mobile capture recovery (#11)
Quality gates / quality (pull_request) Failing after 58s
2026-08-26 08:07:30 +00:00
timmy f8f01c4b2e feat: add hardened atomic staging deployment
Quality gates / quality (pull_request) Successful in 1m28s
2026-08-21 14:49:28 +00:00
timmy a50afa6722 feat: simplify Timmy and add secure Hermes chat
Quality gates / quality (pull_request) Successful in 1m24s
2026-08-20 16:21:00 +00:00
timmy 47eec47a31 ci: install pinned image test dependency
Quality gates / quality (pull_request) Successful in 1m12s
2026-08-19 08:14:43 +00:00
timmy 29ba8594b8 ci: enforce reproducible quality gates
Quality gates / quality (pull_request) Failing after 1m56s
2026-08-19 08:09:38 +00:00