• Timmy review build 2026-11-02 — privacy-safe operator health counters (#19)
    Quality gates / quality (push) Waiting to run
    Pre-Release

    rockachopa released this 2026-11-02 13:29:24 +00:00 | 0 commits to main since this release

    Prerelease for review — tag daily-2026-11-02 on commit 664a9099571fbbf185ab1e94c45d11502458f490 (America/New_York release date 2026-11-02, built 2026-11-02T13:19Z).

    Delta: privacy-safe operator health counters — disclosed on the privacy screen, and readable as an operator report from the command line. This is a real source change, not a rebuild: main moved from 9067ce5 (what daily-2026-11-01 shipped) to 664a909.

    What changed, and what the recording proves

    1. The privacy screen now discloses the counters (user-visible). A fourth row, [data-health-disclosure], sits with the other privacy facts and says what is counted, what is never counted (notes, photos, image fingerprints, identity), and that the counters reset when the server restarts. The recording scrolls that card into frame and reads the app's own sentence first; the scene fails if the copy changes.

    2. GET /api/metrics is an operator surface, not a public one. With TIMMY_METRICS_TOKEN unset the route returns 404 (absent, not guarded); with it set, a missing or wrong bearer gets 403 with no counters in the body; a match returns the snapshot. Token comparison is a SHA-256 digest compare (timingSafeEqual), so a wrong-length guess does not leak a prefix.

    3. scripts/model_metrics_report.mjs reads that snapshot without jq. The recording runs the real CLI against its own server (loopback only, demo token set by the build) and prints what came back — the card on screen is that output, not a fixture:

    SECTION APP     uptime 9m 49s · requests 2 analyzed · 2 refused before the model
    SECTION QUEUE   in flight 0 / 4 · accepted 0 · at capacity no
    SECTION MODEL   readiness disabled · outcomes suggestion 0 · abstained 0 · failure 2
                    abstention no answers yet · latency mean n/a · max 0ms · samples 0
                    failures ingress_refused 2, every other class 0
    wrong token     refused · exit 1 · no counters
    

    Those two ingress_refused failures are the hostile-bytes requests this recording made earlier in the same take (device-guard refusal, then the same bytes posted straight at the running server). The scene asserts the count is ≥ 1 before it draws the card, so a zero would fail the recording rather than be captioned as evidence.

    The privacy property is structural: the formatter imports the three frozen vocabularies and prints only those, so a failure class outside the enum is not printed rather than echoed. No note text, image hash, base64, or caller identity has a path to the terminal — asserted by test, not by convention.

    Completed ticket / PR

    • PR #92 merged — feat(metrics): read the privacy-safe health snapshot without jq (#19), merge commit 48979bf, Closes #19 (auto-closed 2026-11-02T12:07Z). Reviewed before merge: focused 18-file diff, no secrets, no model weights, no medical imagery; npm test 298/298, npm run test:metrics-report 8/8, check:syntax, check:diff, and test:ui in real Chromium all green on the branch in a clean worktree before the merge.
    • Two corrections on top of the merge, both stated because they were caught by running the thing:

    Correction 1 — ef83ad9. Writing the on-camera scene meant running the new CLI. Its first real output printed failure ingress_refused0: the longest failure label exactly filled the 22-character column, so label and count rendered as one broken token. LABEL_WIDTH is now 30 and a format test fails if any row loses the gap between its label and its value. (The disclosure-only demo in the PR would never have exercised this — it never ran the CLI.)

    Correction 2 — 664a909. The first recording was made and inspected at full resolution before publishing, and the card was wrong in a different way: ANALYZE REQUESTS and all eight FAILURE … labels wrapped onto two lines, detaching each label from its count on a 390 px viewport. The card now uses short keys with detail folded into values (one wrapped failures line), and was geometry-probed at the recording's own phone viewport before the rebuild: 706 px of content in a 706 px panel, no clipped key. The rebuild was recorded from scratch; no frame from the discarded take is shipped.

    Gates — 30/30 passed

    npm test 299/299 (298 merged + the new label-gap regression); mobile green path; photo-first acceptance; sleek Hermes chat; manual fallback + draft recovery; provisional suggestion state; hard-stool follow-up; vision corpus refusal; abstention quality gate; worker container receipts; worker post-load readiness; longitudinal pattern summary; grounded chat citations; training contribution consent; corpus manifest provenance; reviewer adjudication blind; dataset card; calibration harness; operator backup restore; production runbook commands; portable backup restore; image ingress refusal; privacy-safe health metrics; dependency audit (0 high); syntax (node/bash/python); secret scan; forbidden artifacts; demo H.264 720×1280 probe; complete MP4 decode; release delta verified painted on camera (103/103 captions, delta caption on screen, top 14 px, 73 px band, padBottom 14 px).

    Post-build, independently of the builder: sha256sum -c SHA256SUMS → both OK; ffprobe → H.264 720×1280 yuv420p, 25 fps, 12,889 frames, 515.56 s, video-only (no audio track, by design); ffmpeg -f null - full decode → exit 0, no errors.

    The build refused to start while anything held 127.0.0.1:4173, and hash-compares two served files against the clone under test before the first gate — the demo cannot be recorded against a different tree.

    Artifacts

    • source archive timmy-talking-turd-2026-11-02-664a9099571f.tar.gz — 388,064 bytes — sha256 038e2340380541e8f6707d438c1cb988c42271645bd3f06322f212462bb15e8a
    • demo video timmy-talking-turd-2026-11-02-664a9099571f-demo.mp4 — 31,718,265 bytes — H.264 720×1280 yuv420p, 25 fps, 515.56 s — sha256 14aa6a89d6d6ef858b6afd33e98df11814c4ab19edef8cff66bba82f8f87e1dc

    Model / profile

    Built and recorded by Hermes (profile default, model deepseek-flash). The demo runs the real app from the built commit with TIMMY_VISION_ENABLED=false; the configured vision profile remains self-hosted SmolVLM2-2.2B-Instruct (pinned GGUF) with the hosted profile as fallback. The health report card is a real CLI run against a real server, but that server is in its disabled-AI state, so the report shows readiness disabled and only the failure classes that state can produce. No live inference appears in the video. No model weights, .env, provider logs, raw corpora, or real medical images are packaged; every log, note, and photo placeholder on screen is synthetic.

    Operational note

    timmy.alexanderwhitestone.com routes to 127.0.0.1:4173. Nothing was listening on that port when this run started, so the public URL had no backend before the build began (this release did not take it down; the gate only requires the port be free while it runs). It is running again from 664a909 and the public URL answers 200 (/api/healthz too). The next release build will refuse to start while it runs — that is the gate working as intended, so stop the listener before the build and restart it after.

    Verified on this run, both auth branches: token unset → 404 {"error":"Not found"} (route absent); token set + wrong bearer → 403; token set + match → 200 snapshot.

    Review focus

    Watch from the privacy screen onward (~7:00–7:30): the disclosure sentence, then the report card. The thing to check is the honesty of the card, specifically two rows — REQUESTS: 2 analyzed · 2 refused before the model should match the two hostile uploads the video showed earlier, and READINESS: disabled should make it obvious that this snapshot is from a server with AI switched off, not a claim about model health. If that reads as a health dashboard for a live model, it over-claims and needs rewording.

    Known accuracy limitation

    Unchanged by this release, and not made better by it. Bristol accuracy is not clinically validated; the calibration receipt still reports BLOCKED because no candidate model clears every gate. queue.inFlight is the app's own admission depth for POST /api/analyze, not the full bounded queue with cancellation and overload fallback — that is #17, still unmerged (PR #64). User confirmation remains mandatory everywhere: photo analysis may suggest visible Bristol form, broad color, and image quality only, and never symptoms or a diagnosis. Visible color is not blood.

    Downloads