feat: separate saved-photo lifecycle from the confirmed log (#36) #80
Closed
rockachopa
wants to merge 0 commits from
timmy/36-photo-lifecycle-controls into main
pull from: timmy/36-photo-lifecycle-controls
merge into: stackchain:main
stackchain:main
stackchain:timmy/19-metrics-operator-report
stackchain:timmy/16-image-ingress-hardening
stackchain:timmy/40-security-rc-evidence
stackchain:timmy/27-dataset-card
stackchain:timmy/26-review-adjudication
stackchain:timmy/32-abstention-policy
stackchain:timmy/29-evaluation-harness
stackchain:timmy/35-portable-backup-versions
stackchain:timmy/24-training-contribution-consent
stackchain:fix/demo-caption-pixels
stackchain:timmy/release-notes-grounded-chat
stackchain:timmy/37-grounded-chat-citations
stackchain:timmy/21-escalation-regression
stackchain:timmy/34-explainable-pattern-summaries
stackchain:timmy/15-container-worker-receipts
stackchain:timmy/73-blank-first-ordering
stackchain:timmy/18-vision-corpus
stackchain:timmy/20-photo-dataflow-threat-model
stackchain:timmy/67-hard-stool-followup
stackchain:timmy/13-provisional-suggestion-state
stackchain:timmy/12-manual-fallback-draft-recovery
stackchain:timmy/11-mobile-capture-recovery
stackchain:free/hy3-timmy-16
stackchain:timmy/35-version-ledger-migrations
stackchain:timmy/41-release-observability-dashboard
stackchain:free/step-timmy-14
stackchain:timmy/21-escalation-regression-suite
stackchain:timmy/17-bounded-inference-queue
stackchain:timmy/58-strict-csp-runtime-config
stackchain:timmy/55-staging-deployment-tooling
stackchain:timmy/53-private-subpage-staging
stackchain:timmy/10-reproducible-smolvlm-bootstrap
stackchain:timmy/48-vomiting-phrase-hotfix
stackchain:timmy/48-server-safety-override
stackchain:timmy/47-sleek-hermes-agent
stackchain:timmy/9-product-boundary-decisions
stackchain:timmy/8-ci-gates
No Reviewers
Labels
Clear labels
area/backend
area/data
area/frontend
area/model
area/privacy
area/release
area/safety
blocked
human-gate
priority/P0
priority/P1
priority/P2
state:review
type/docs
type/epic
type/feature
type/ops
type/research
type/security
type/test
Application API and storage
Dataset and provenance
PWA and interaction design
Vision model and inference
Privacy and consent
Release engineering and distribution
Clinical safety boundary
Blocked on an explicit dependency or decision
Requires explicit human approval
Release-critical
High priority
Planned
Documentation and evidence
Roadmap epic
Product feature
Infrastructure and operations
Research or evaluation
Security hardening
Verification and quality gate
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: stackchain/timmy-talking-turd#80
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #36
What changed
A confirmed log and the image attached to it are now separate things the person owns:
Photo savedlabel; no thumbnail is rendered in the list or when the log is opened.Show photorenders the stored bytes from this browser only after the person asks for it.Delete this log and its photo→Tap again…) removes the log and its image together; the first tap only arms it.data:imagebytes remain in storage.New
src/photo-lifecycle.jsdecides presence from the stored image bytes (not a filename or flag) and returns new lists fromwithoutPhoto/withoutEntry; the ledger passed in is never mutated.Acceptance criteria → evidence
.entries-card img, and zero#entry-photobefore an explicit request.photoDataUrlis cleared, and the other confirmed fields still match; the separate two-step log delete is asserted to require two taps.JSON.stringify(localStorage)contains nodata:image.Tests
npm test— 192 pass, 0 fail (6 new intests/photo-lifecycle.test.js).npm run test:photo-lifecycle— pass. Includes visual acceptance (label fits 390px, no horizontal scroll, ≥44px touch targets) and Escape-dismisses-dialog.ui,photo,mobile-capture,sleek,manual-fallback,provisional,followup,vision-refusal,worker-readiness,pattern-summary,grounded-chat,photo-lifecycle).npm run check:syntaxandnpm run check:diffpass.TDD note: each unit behaviour and the browser behaviour were written first and observed failing for the missing feature (module not found; zero photo indicators), then implemented to green.
Demonstration path
scripts/record_release_demo.mjsnow records the lifecycle on camera with a synthetic 1x1 PNG constant (no real photo): label without thumbnail → open log without revealing → explicitShow photo→Remove photowith the log and fields intact → delete-all performed (dialog accepted) with an assertion that no image bytes survive.scripts/build_release.pygates four new captions, and a recording of this branch completed successfully (61 captions, receipt includes the release delta).Boundary
No diagnosis, no new inference, no inference exposure, no model weights, no real medical images, no production service change. Photos remain in this browser only; the chat path still excludes them.
Release review (2026-10-19 nightly gate; recorded as a comment because Gitea blocks self-approval on a PR authored by the same account).
Verified at head
ebee52fin a clean checkout:Approved for merge and tonight's release.
Pull request closed