Merge pull request 'Document product boundary and release authority' (#46) from timmy/9-product-boundary-decisions into main
All checks were successful
Quality gates / quality (push) Successful in 1m26s

This commit is contained in:
rockachopa 2026-08-20 13:15:22 +00:00
commit 930f156590
6 changed files with 74 additions and 2 deletions

View File

@ -4,6 +4,7 @@ A working mobile-first bowel diary with an optional **photo-first AI assist**:
- [Product roadmap and live Gitea epic map](ROADMAP.md)
- [Product and safety boundary](PRODUCT.md)
- [Product boundary and release authority decision](docs/PRODUCT-DECISIONS.md)
- [Self-hosted stool-vision decision](research/SELF-HOSTED-STOOL-VISION.md)
## Build a gated review release

51
docs/PRODUCT-DECISIONS.md Normal file
View File

@ -0,0 +1,51 @@
# Product Boundary and Release Authority Decision
- **Status:** Accepted
- **Date:** 2026-08-20
- **Scope:** Photo-assisted bowel logging and release governance
## Context
Timmy can make a conservative visual suggestion from a user-selected image, but the available general-purpose model is not clinically validated. The product must preserve manual logging, deterministic red-flag escalation, and user control regardless of model availability or output.
## Decision
### Observable AI fields
AI may suggest only:
- visible Bristol form (Types 17);
- broad color;
- image quality.
Every suggestion is provisional, may abstain, and requires user review or correction before it can enter the journal. Symptoms remain user-entered, and journal saving is separate from training contribution consent.
### Prohibited inferences
AI must not infer or claim disease, bleeding, pain, urgency, fever, vomiting, treatment, causation, or whether a food is safe. It must not replace professional care, suppress deterministic red-flag escalation, or present a suggestion as a diagnosis.
### Release authority
Hermes/Timmy is the release authority for routine engineering, test, build, deployment, and release-candidate preparation. Automated evidence must remain reproducible and must not overstate model accuracy or safety.
### Human gates
Human gates are limited to:
1. clinical and privacy review when language or policy crosses those boundaries;
2. beta consent before participation;
3. RC approval before shipping a release candidate.
Routine provisioning, deployment, label sweeps, and release-candidate assembly are not human-operated gates.
## Consequences
- Model output is assistive and fail-closed, never authoritative.
- A generic open-weight VLM can support bootstrap experiments but cannot become the production Bristol classifier without the documented calibration and evaluation evidence.
- Release evidence and demonstrations must use fictional or synthetic data and state the non-diagnostic boundary honestly.
## Evidence and governing references
- [Product brief and safety boundary](../PRODUCT.md)
- [AI execution evidence](../AI-EVIDENCE.md)
- [Sovereign vision decision and measured limitations](../research/SELF-HOSTED-STOOL-VISION.md)

View File

@ -4,7 +4,7 @@
"private": true,
"type": "module",
"scripts": {
"test": "node --test tests/domain.test.js tests/analysis.test.js tests/vision-service.test.js tests/vision-config.test.js tests/training-ingest.test.js tests/ci-workflow.test.js tests/release-demo.test.js",
"test": "node --test tests/domain.test.js tests/analysis.test.js tests/vision-service.test.js tests/vision-config.test.js tests/training-ingest.test.js tests/ci-workflow.test.js tests/product-decisions.test.js tests/release-demo.test.js",
"test:ui": "node tests/ui.acceptance.mjs",
"test:photo": "node tests/photo-first.acceptance.mjs",
"check:syntax": "node --check app.js && node --check server.mjs && node --check service-worker.js && node --check src/analysis.js && node --check src/domain.js && node --check src/vision-config.js && node --check src/vision-service.js && node --check scripts/record_release_demo.mjs && bash -n scripts/run_selfhost_smolvlm.sh && python3 -m py_compile scripts/ingest_training_photo.py scripts/build_release.py",

View File

@ -97,10 +97,11 @@ await caption('The photo stays unsaved until explicit consent', 1300);
await page.locator('#ai-consent').check();
await tap('#analyze-photo', 500);
await page.getByText(/83% confidence/i).waitFor();
await caption('Timmy suggests only visible form and broad color', 1500);
await caption('AI may suggest visible form, broad color, and image quality — never symptoms or diagnosis', 1900);
await tap('#use-suggestion', 600);
await caption('Nothing persists until the user reviews or corrects it', 1500);
await page.locator('[data-type="4"]').scrollIntoViewIfNeeded();
await caption('Release gates: clinical/privacy review, beta consent, and RC approval', 1800);
await sleep(700);
await page.evaluate(() => {
document.querySelector('#demo-caption')?.remove();

View File

@ -0,0 +1,17 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
const decisionPath = new URL('../docs/PRODUCT-DECISIONS.md', import.meta.url);
test('product decision record fixes the AI boundary and release authority', async () => {
const decision = await readFile(decisionPath, 'utf8');
assert.match(decision, /Observable AI fields[\s\S]*Bristol form[\s\S]*broad color[\s\S]*image quality/i);
assert.match(decision, /Prohibited inferences[\s\S]*disease[\s\S]*bleeding[\s\S]*pain[\s\S]*urgency[\s\S]*fever[\s\S]*vomiting[\s\S]*food/i);
assert.match(decision, /Hermes\/Timmy[\s\S]*release authority/i);
assert.match(decision, /Human gates[\s\S]*clinical and privacy review[\s\S]*beta consent[\s\S]*RC approval/i);
assert.match(decision, /\.\.\/PRODUCT\.md/);
assert.match(decision, /\.\.\/AI-EVIDENCE\.md/);
assert.match(decision, /\.\.\/research\/SELF-HOSTED-STOOL-VISION\.md/);
});

View File

@ -9,5 +9,7 @@ test('release demo visibly explains the CI-protected browser path without overst
assert.match(demo, /Automated checks replay this synthetic path before review/);
assert.match(demo, /tests\/fixtures\/synthetic-type4\.jpg/);
assert.match(demo, /AI may suggest visible form, broad color, and image quality — never symptoms or diagnosis/);
assert.match(demo, /Release gates: clinical\/privacy review, beta consent, and RC approval/);
assert.match(demo, /Visual assistance — never a diagnosis\./);
});