Commit Graph
50 Commits
Author SHA1 Message Date
timmy b838beb548 feat: ground Timmy chat answers in cited ledger records (#37)
Quality gates / quality (pull_request) Failing after 2m50s
Chat now has to show its work. Every answer that states a count, a date, or a
visible form cites the confirmed records behind it, and following a citation
opens exactly that log. Questions the journal cannot answer (food safety,
medicine, what a symptom means) get boundary copy with no borrowed evidence,
and a sparse window refuses to describe a trend instead of naming one.

The Hermes path is held to the same rule: the server gives each ledger record a
positional ref, the prompt requires inline [entry:L<n>] citations, and the
browser resolves them against the ledger it sent. A ref that matches no record
is stripped and the answer is labelled unverified rather than rendered as a
source, so an invented citation cannot look like evidence.

The release recording now exercises the grounded local answer, its citation
sheet, the refusal, and a Hermes reply whose refs resolve, each asserted in the
browser with fictional logs.
2026-10-18 08:17:40 +00:00
rockachopa 3b267c0fff Merge pull request #77: fix: escalate the symptom phrasing people actually use, and never clear a reported symptom (#21) daily-2026-10-15 daily-2026-10-16 daily-2026-10-17 2026-10-15 12:03:03 +00:00
timmy b4be7049ea fix: escalate the symptom phrasing people actually use, and never clear a reported symptom (#21)
Quality gates / quality (pull_request) Successful in 2m38s
Deterministic escalation only fired on a narrow set of literal phrases, so real reports
like "there is blood when I wipe" or "I have tarry stools" reached the chat provider
without the fixed medical guidance. Expanding the suite found 18 of 18 checked clinical
phrasings missing.

- domain: cover bleeding reported by wiping/toilet paper/anatomy/mixed-in phrasing,
  black-tarry-dark-red stool, reported temperature and high temperature, abdominal-scoped
  severe pain in every natural word order, and past-tense/slang inability to pass gas.
  Near-miss wording that must stay quiet (paper cut, blood pressure, black beans, dark red
  wine, a normal temperature, knee or back pain, passed gas, no gas in the car) is pinned.
- domain: a symptom reported in any truthy shape (1, "yes", "true") now counts as reported.
  Reading only the literal boolean `true` silently cleared a symptom, which is the one
  direction this boundary may never fail in.
- hermes-agent-service: the gateway ledger sanitizer used the same strict check, so a
  browser-supplied ledger entry could have its symptom cleared before the escalation check.
- tests/escalation-regression.test.js: per-flag positive and negative language coverage,
  model output can neither set nor clear a symptom/urgency/discomfort/note, and the
  escalation copy is byte-identical for every flag and under a missing, throwing, or
  malicious provider. Registered in the default unit gate.
- scripts/record_release_demo.mjs: the recording now types the new bleeding and tarry
  phrasing, and seeds a fictional ledger whose note says "stool was tarry yesterday", then
  asserts in the browser that exactly one new Timmy bubble carries the app's own copy and
  that the turn never reaches Hermes. Three new captions are required release gates.

Boundary unchanged: no new inference, no diagnosis, no image claim. Escalation only ever
gets broader on user-reported symptoms.
2026-10-15 08:15:00 +00:00
rockachopa a033cb3ae9 Merge pull request 'feat: explainable longitudinal pattern summaries with cited records (#34)' (#76) from timmy/34-explainable-pattern-summaries into main daily-2026-10-14 2026-10-14 12:03:35 +00:00
timmy d670360560 feat: explainable longitudinal pattern summaries with cited records (#34)
Quality gates / quality (pull_request) Successful in 2m59s
The home insight card now reports the confirmed-log count and form
groupings for a window, every line names the exact confirmed records it
was built from, and following a citation opens those records. A window
below the minimum states that it is too sparse instead of describing a
trend, and a window with both firm and loose logs says it is mixed rather
than picking a winner. No line explains a cause, rules on food, or offers
a health verdict.

- src/summary.js: window filtering, insufficient-data guard, per-form
  lines, mixed-pattern line, boundary copy, record citations
- app.js: explainable home card plus a pattern-source sheet listing the
  cited records
- tests/summary.test.js, tests/pattern-summary.acceptance.mjs: unit and
  real-browser coverage, gated in CI and the release builder
- scripts/record_release_demo.mjs: fictional multi-day sample logs,
  citation follow-through, and the sparse-window refusal on camera
2026-10-14 08:13:02 +00:00
rockachopa 5744969faf Merge pull request 'feat: pin the worker container and gate readiness on the loaded model (#15)' (#75) from timmy/15-container-worker-receipts into main daily-2026-10-13 2026-10-13 12:05:19 +00:00
Timmy 46f961668f feat: pin the self-hosted worker container and gate readiness on the loaded model (#15)
Quality gates / quality (pull_request) Successful in 3m29s
A worker that answers /v1/models has not necessarily loaded its weights, so the app
was offering an AI control that could only fail after the upload. Readiness now
passes only once the pinned model is loaded, and the not-loaded state reaches manual
Bristol entry in one tap. Verified against the real pinned llama.cpp build: it serves
503 while loading and the gate reports the distinct not-loaded state.

Adds the reproducible container recipe (digest-pinned bases, pinned llama.cpp commit,
hash-verified read-only weights, unprivileged, loopback-only publish), one shared
post-load readiness gate used by the host bootstrap and the image healthcheck, and a
target-GPU benchmark that refuses to write a receipt it did not measure.

Refs #15
2026-10-13 08:20:21 +00:00
rockachopa 9cf23df448 Merge pull request #74: fix: fail closed when a filled-in visual field is out of range (#73)
Closes #73
daily-2026-10-12
2026-10-12 12:02:29 +00:00
timmy 5c759078c4 fix: fail closed when a filled-in visual field is out of range (#73)
Quality gates / quality (pull_request) Failing after 14s
The blank-first ordering let one blank field short-circuit the whole reply, so a
response carrying an impossible value came back as `unusable_visual_fields`:
the user was told the photo was unreadable when the model had in fact returned
something Timmy must never apply.

Blank fields still abstain and still prefill nothing. A filled-in field is a
claim, and a claim outside the contract now fails closed even when the other
field came back blank.

The corpus earns its label too. `out-of-range-fields` drops from confidence 1.4
to 0.9 so the case reaches the field-range check instead of dying at the
confidence gate, and a new `blank-plus-out-of-range` case covers the class the
old ordering let through. The release demo replays that case on camera and the
fail-closed 503 budget moves from one to two, so the scene cannot be dropped
silently.

Closes #73
2026-10-12 08:07:22 +00:00
rockachopa a1777a72e8 Merge pull request #72: test: prove schema conformance and refusal with a committed vision corpus (#18) daily-2026-10-11 2026-10-11 12:02:42 +00:00
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 Release Bot 58b7feddc8 ci: expire demo captions and span the whole recording in the contact sheet
Two defects found inspecting the first demonstration of this release:

- A caption stayed on screen until the next one replaced it, so the
  delete-data caption was still displayed over the home view after the
  navigation. Captions now fade and remove at the end of their stated
  duration, so no caption outlives the screen it describes.
- The contact sheet used a fixed 1/2 fps, so a 88s demo only showed its
  first 24s in the review sheet. The sheet rate is now derived from the
  probed duration and a missing sheet fails the build.
daily-2026-10-10
2026-10-10 12:11:11 +00:00
Timmy Release Bot d027a1e791 ci: state the release delta on camera and gate on an on-screen receipt
A documentation-only release previously recorded a demo captioned
'FEATURE DEMO', which implied a shipped feature that did not exist. The
demo now renders the builder-supplied release delta as its second
caption, and the builder refuses to publish unless the demo's own
machine-readable caption receipt proves that statement reached the
screen and every required feature caption did too.

The recording also shows the byte-bearing controls the photo data-flow
threat model governs (consent-gated upload, portable export, delete all
local data) using the app's real selectors, so a docs-only release
demonstrates the nearest real user-visible effect instead of inventing
UI.
2026-10-10 12:06:33 +00:00
rockachopa 503efaf959 Merge pull request 'docs: end-to-end photo data-flow threat model (#20)' (#71) from timmy/20-photo-dataflow-threat-model into main 2026-10-10 12:01:57 +00:00
timmy 29ea045671 docs: add end-to-end photo data-flow threat model (#20)
Quality gates / quality (pull_request) Successful in 2m4s
- docs/PHOTO-DATAFLOW-THREAT-MODEL.md: browser, API ingress, model worker,
  transient buffers, training opt-in store, logs, exports, and deletion,
  with trust boundaries and a numbered threat register
- every named abuse case (replay, oversized input, metadata leakage,
  poisoning, unauthorized training, operator access) carries a mitigation,
  an owner, a tracked follow-up ticket, and the artifact that will prove it
- tests/threat-model.test.js enforces diagram coverage, owner/follow-up
  presence against ROADMAP ticket numbers, and the non-diagnostic boundary
  with synthetic-only fixtures
- link the model from the accepted product decision record
2026-10-10 08:03:31 +00:00
rockachopa 5505f3c3ef Merge pull request 'Hard-stool follow-up: user-reported symptoms with deterministic red-flag handoff' (#70) from timmy/67-hard-stool-followup into main daily-2026-10-09 2026-10-09 12:01:54 +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
rockachopa 7c5c466b83 Merge pull request '#69' from timmy/13-provisional-suggestion-state
Make AI suggestions visibly provisional and correction-first (#13)

Closes #13
daily-2026-10-08
2026-10-08 12:02:33 +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
rockachopa 3e87f881c5 Merge pull request '#68' from timmy/12-manual-fallback-draft-recovery daily-2026-10-07 2026-10-07 12:02:30 +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 5dac04b1e6 Merge pull request 'Harden mobile camera and gallery recovery' (#66) from timmy/11-mobile-capture-recovery into main
Quality gates / quality (push) Successful in 1m56s
Merge nightly mobile capture recovery for issue #11 after exact-head review and green gates
daily-2026-08-26 daily-2026-08-27
2026-08-26 12:19:21 +00:00
timmy 87c7680aad ci: retry transient runner port collision
Quality gates / quality (pull_request) Successful in 1m26s
2026-08-26 08:10:55 +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 47294a98aa Merge pull request 'Make staging runtime configuration compatible with strict CSP' (#59) from timmy/58-strict-csp-runtime-config into main
Quality gates / quality (push) Successful in 1m56s
daily-2026-08-21.1 daily-2026-08-22 daily-2026-08-23 daily-2026-08-24 daily-2026-08-25
2026-08-21 15:04:43 +00:00
timmy 877b8a01f3 fix: make staging compatible with strict CSP
Quality gates / quality (pull_request) Successful in 1m37s
2026-08-21 15:01:05 +00:00
timmy 067afaed4c Merge pull request 'Hardened atomic private-staging deployment tooling' (#56) from timmy/55-staging-deployment-tooling into main
Quality gates / quality (push) Successful in 1m41s
2026-08-21 14:54:11 +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 fc763fb758 Merge pull request 'Private subpage staging foundation' (#54) from timmy/53-private-subpage-staging into main
Quality gates / quality (push) Successful in 2m7s
2026-08-21 14:16:15 +00:00
timmy 7e11154302 feat: add private subpage staging slice
Quality gates / quality (pull_request) Successful in 1m43s
2026-08-21 14:12:17 +00:00
timmy 11d1b364ab fix: gate bootstrap syntax in release build
Quality gates / quality (push) Successful in 1m45s
daily-2026-08-21
2026-08-21 12:56:48 +00:00
rockachopa 8e3c2f8889 Merge pull request #52 from timmy/10-reproducible-smolvlm-bootstrap
Quality gates / quality (push) Has been cancelled
Merge pull request #52: Package pinned self-hosted SmolVLM2 bootstrap
2026-08-21 12:55:18 +00:00
timmy 982fab273c feat: package pinned self-host vision bootstrap
Quality gates / quality (pull_request) Successful in 1m30s
2026-08-21 08:15:32 +00:00
timmy ca31e6d38b Merge pull request 'Hotfix: recognize past-tense vomiting in deterministic chat safety' (#51) from timmy/48-vomiting-phrase-hotfix into main
Quality gates / quality (push) Successful in 1m26s
daily-2026-08-20.3
2026-08-20 17:17:33 +00:00
timmy 0f3104ebde fix: recognize past-tense vomiting in chat safety
Quality gates / quality (pull_request) Successful in 1m21s
2026-08-20 17:14:20 +00:00
timmy cc1fc6ee36 Merge pull request 'Hotfix: enforce deterministic urgent-symptom override at the server boundary' (#50) from timmy/48-server-safety-override into main
Quality gates / quality (push) Successful in 1m24s
daily-2026-08-20.2
2026-08-20 16:48:02 +00:00
timmy 05b4bafd96 fix: enforce urgent chat override server-side
Quality gates / quality (pull_request) Successful in 1m25s
2026-08-20 16:41:35 +00:00
timmy 09f9528434 Merge pull request 'Sleek Timmy mobile shell and secure Hermes Agent chat' (#49) from timmy/47-sleek-hermes-agent into main
Quality gates / quality (push) Successful in 1m32s
daily-2026-08-20.1
2026-08-20 16:25:47 +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
rockachopa 930f156590 Merge pull request 'Document product boundary and release authority' (#46) from timmy/9-product-boundary-decisions into main
Quality gates / quality (push) Successful in 1m26s
daily-2026-08-20
2026-08-20 13:15:22 +00:00
timmy 3c51308a9e docs: fix product boundary and release authority
Quality gates / quality (pull_request) Successful in 1m14s
2026-08-20 08:32:16 +00:00
timmy 8ab1e85bd1 Merge pull request #45: enforce reproducible quality gates
Quality gates / quality (push) Successful in 1m18s
daily-2026-08-19.2
2026-08-19 12:06:38 +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
timmy 535834c060 feat: require verified feature demo video in every release daily-2026-08-19.1 2026-08-19 03:36:04 +00:00
timmy ce84ea577c test: isolate photo acceptance from service workers daily-2026-08-19 2026-08-19 03:02:33 +00:00
timmy 3899eac34f fix: start isolated server for release acceptance gates 2026-08-19 03:01:28 +00:00
timmy 074f52fddc build: add gated reproducible review releases 2026-08-19 03:00:54 +00:00
timmy 0ecf1d1205 docs: add Gitea roadmap and epic map 2026-08-19 02:00:40 +00:00
timmy 58906f11d0 feat: ship photo-first Timmy prototype and sovereign vision spike 2026-08-19 01:54:29 +00:00