
### 2026-11-06 — v0.10.17 guided neck visible-skin study
- Previous v0.10.16 frozen upper-neck ROI repeatedly fell on beard/chin, so 1 vs 3 peaks are **not anatomically valid**.
- An explicit phone camera calibration now records user-selected visible bare neck ROI and an unobstructed cheek/face reference as normalized source-video coordinates. Both are frozen during a paired study and exported alongside timing in JSON. Placement PNG may be exported.
- Offline v2 computes differentiated local flow between selected neck and face ROIs with texture/QC flags. No real-time physiological verdict; test prospective data before tuning.
- Development video pilot showed that manually chosen face reference accidentally on the hand caused very low QC; correctly selected cheek allowed data, but exploratory v2 on already inspected footage did not establish 3 detectable peaks. This is a necessary quality limitation, not a failure of user's equalization.
- Nose code and historical throat modules remain unchanged byte-for-byte.

# Current Project State — 0.10.15

**Current approach: video-first research.** The previous throat live-detection engine v0.10.14 is frozen; analyze properly labeled videos first. Nose v0.10 and all previous throat modules frozen and retained. New `motion-lab` only records video + timestamps; videos are not included in JSON or browser backups.

## Data lineage
Nose v0.10: original `nose` directory kept byte-identical. Throat v0.10.14 remains `throat`; earlier 0.10.13 `throat-v01013`, 0.10.12 `throat-previous`, 0.10.9 `throat-legacy`. Current 0.10.15 `motion-lab`. Keep JSON and videos together; avoid over-interpreting scheduled prompts as verified physiological events.

**Latest v0.10.14 UX note:** trial Start / Stop / phase timer / progress bar are now directly below the live video frame (`throat/index.html` `.capture-quickbar`). User requested seeing video while tapping start, rather than scrolling past calibration and tests. The section 03 trial instructions and optional local video recording remain further down the page. Confirm button changes from control to Frenzel after the first run. No engine changes.

# CURRENT STATE · 0.10.14 (2026-11-06)

## Critical context for resuming in a future chat
- Starting public bundle: `EQ-Coach-v0.10.14-INTEGRATED-CLOUDFLARE.zip`. Private archive: `EQ-Coach-v0.10.14-PRIVATE-RESEARCH.zip`. Never deploy the private archive.
- Nose engine v0.10 is byte-identical to v0.10.13, frozen. Older throat 0.10.13 preserved under `throat-v01013/`, throat 0.10.12 under `throat-previous/`, throat legacy 0.10.9 under `throat-legacy/`.
- New `throat/` uses JS LK Optical Flow on a user-tapped *neck skin colour* mask, not anatomical segmentation. Three-band gate has been removed; side references are optional QA. A user's calibration click centres a shorter ROI around visible neck skin and gives a chroma overlay for user verification.
- Preflight only indicates mechanical measurability, **not** clinical validity. Thresholds: >=60% valid preview, >=22% approximate colour coverage, >=3 valid target feature points mean. Skin must be manually selected. An explicit research-only override records untrustworthy data but prevents positive interpretation.
- Preserve complete source files and research datasets. In v0.10.13 measured 0/74 valid baseline & 0/119 valid action in control, and 27/75 baseline & 0/115 action in Frenzel; screenshot showed ROI overlapping garment. These are data-quality failures, NOT absence of Frenzel.
- Data keys: `eqcoach_throat_skin_v01014` (new), `eqcoach_throat_flow_face_v01013`, `eqcoach_throat_flow_v01010`, `eqcoach_throat_v0103`, `eqcoach_nose_v010`.
- Cloudflare Pages: user successfully deployed earlier v0.10.13 at a Pages project. Recommend updating existing project with a new deploy, rather than creating separate projects.
- No claim of accurate anatomical laryngeal tracking. Need real-phone calibration screenshot AND control/Frenzel JSON; optional consented videos to validate actual visual movement. Also investigate motion of neck skin using time-series; do not assume all Frenzel produces visible larynx movement.
- User prefers front camera showing eyes, nose, chin, and neck, uncropped; Hebrew short spoken voice prompts with female voice when OS supports it; no unnatural demand to hold head perfectly still.

---

# EQ Coach — current state v0.10.13 | 2026-11-06

**CURRENT, supersedes earlier sections below.** A single integrated website includes: `nose/` frozen at v0.10 byte-identical to 0.10.12; `throat/` new face-anchored three-band tracker v0.10.13; `throat-previous/` exact v0.10.12; `throat-legacy/` v0.10.9. The project must continue from this source, NOT be recreated. Source manifests and all prior experiment JSON archives are in the private research ZIP; public Netlify ZIP contains NO real personal photos or experiment JSON.

## New experimental motor and reasoning

- Image sensor shows full front camera FOV (no CSS `cover` crop). A face model gives eye center, tilt, scale, and initially the chin.
- At first reliable frame, a **single eye-relative anchor is calibrated using chin** and `neckOffset`; from then on face eyes + tilt/scale determine neck crop location. This intentionally prevents chin motion from changing the measurement window. It does NOT mathematically correct head pitch or perspective.
- Three vertical strips within the broad central anterior-neck target are tracked independently via pure-JS two-level pyramidal Lucas–Kanade optical flow. A frame is valid when at least **two of three bands** have sufficient reliable points. Median central vertical displacement, integrated over time, is the **primary face-aligned skin-motion signal**.
- The two side-neck regions are **optional** secondary trackers; both can fail without invalidating central tracking. Their reference-corrected signal (`neckRelativeUp`) is exported and chartable but NOT used in the primary event count.
- Event scoring still requires usable baseline and action. Low-quality trials save for research but cannot be called detected / not detected. Three simulated peak tests do not establish true Frenzel sensitivity. No direct anatomical tracking of larynx, tongue base, glottis, pressure, or Eustachian tube action is claimed.
- Three-stage protocol unchanged: 3 sec prep, 5 sec neutral baseline, 8 sec action. Control → Frenzel (3 intended pulses) → optional swallow. Opt-in local camera-only videos are held in page memory and MUST be downloaded before closing page. Privacy: no videos or personal data bundled in public ZIP.

## Data and migration

Keys: nose `eqcoach_nose_v010` unchanged; legacy template throat `eqcoach_throat_v0103`; previous optical-flow `eqcoach_throat_flow_v01010`; new flow `eqcoach_throat_flow_face_v01013`. Root landing page can export one combined numeric JSON. A new Netlify origin does not inherit localStorage from another origin. Download the combined backup after every session and import into next deployment. Old 0.10.12 JSON belongs to `throat-previous/`, NOT new flow.

## What was tested in this build

- JS syntax checks; deterministic synthetic textured frames showing independent upper/middle/lower movement and zero-to-three pulse detection (no medical inference).
- Inline Chromium smoke test with simulated camera, face landmarks, and fast-forwarded protocol: camera shown, preview captured, ROI confirmation, control saved, Frenzel saved, correct isolated storage key, no JS page errors. Camera and model were **mocked**. Real Samsung camera, MediaPipe CDN networking, and video codec support **not verified**.
- Preserve the earlier observed problems: v0.10.11 control 90.8% action valid vs Frenzel 1.7%; v0.10.12 improved active valid to 48.3% but had only 3.6% both side references. The last two user-submitted static photos show subtle external neck differences but do not prove anatomical tissue displacement or identify which image is active. Do not force the engine to return three movements.

---

# EQ Coach — Project State 0.10.12 (2026-11-05)

## Current decision

Keep the `nose/` module frozen v0.10, including ROI and thresholds. Nose under-finger closure allowed clear separation in one pair, natural finger placement did not; not validated as physiology.

The frontal throat module v0.10.9 produced unreliable studies (0.10.8 run had 0 control peaks, 1 active peak, only 42.9% active action valid and 57.1% search-boundary invalid). Do not tune the threshold to force 3 peaks. User wants frontal face plus neck in full camera view. All camera previews must show the full sensor image (`contain`, aspect from video metadata), not artificially crop a landscape stream to portrait. User wants a visible non-mirrored option, concise Hebrew voice, and clear live markers.

## New throat flow engine

New `throat/` v0.10.10 uses *native JS pyramidal Lucas–Kanade optical flow*, NOT the compiled OpenCV.js library. A self-contained model keeps the user experience independent of another CDN. Runtime measurement: MediaPipe face landmarks provide geometric alignment; detect many high-texture corners over broad laryngeal-surface target and two neck-side reference zones; temporal tracking estimates per-group 2D median displacement; subtract side reference and integrate vertical motion. A single side fallback carries a warning. All three selection masks and live points are exposed to user. Motion is just skin movement; tongue base/glottis/actual anatomical larynx not directly observed.

The prior v0.10.9 template-matching code is kept unchanged under `throat-legacy/`, accessible from app. Its data and the new flow data are NEVER compared numerically as if produced by the same measurement units. Frozen nose data and legacy throat data retain their localStorage keys. New data uses `eqcoach_throat_flow_v01010` and exports with the `module: throat-optical-flow` marker. The root project state export/import includes all three independently.

## Protocol and success criteria

Paired no-intent control then 3 natural gentle Frenzel attempts, with optional 1 swallow as non-Frenzel positive motion control. Each: 3 seconds prep + 5s reference + 8s action. A trial stops if baseline <70% valid samples OR fewer than 26 valid baseline frames. Action data under 70% valid is caution; single-sided reference is caution. Do not infer failed equalization from an inconclusive result. Before a new quantitative test, user should send a ROI placement PNG to verify actual skin coverage and region selection.

## Previous research files and reproducibility

The private ZIP contains old experiments, the source snapshot v0.10.9, and old private master archive. Public deploy contains source but NO personal research JSON or photographs. For transfer to a new URL, export a combined JSON then import it from the app homepage. See VERSION.json and CHANGELOG.md for exact hashes.

# EQ Coach — Project state | 2026-11-05 | Integrated build 0.10.2

## Purpose
Commercially relevant *research prototype* for remotely teaching/evaluating dry-land ear equalization mechanics in freediving. **Not** a pressure measurement, medical diagnosis, or proof of Eustachian tube opening. The user is an expert freediving instructor; preserve their teaching assumptions as hypotheses to test, not as proven computer-vision labels.

## Architecture: one web app, modular
- `/index.html`: unified landing page, navigation and local JSON project-state export/import.
- `/nose/`: **v0.10 signal algorithm frozen unchanged.** Original v0.10 nose source is also archived in the separate PRIVATE research bundle. The deployed nose app has integration-only navigation and numeric data persistence/import. **Do not recalibrate or alter nose thresholds without a new explicit research decision.**
- `/throat/`: frontal neck-surface motion research module, first introduced in 0.10.1, visually recalibrated in 0.10.2. Independent source and results. Neck target region plus two lateral neck references; robust local texture matching estimates vertical movement after subtracting reference displacement. Face landmarks used for camera alignment, **not** throat-anatomy detection.
- `/docs/`: design assumptions, changes and reproducibility notes. **No private experimental JSON data deployed**.
- Planned later: frontal upper-chest/abdomen movement to investigate respiratory strain/possible Valsalva, and careful multimodal fusion.

## Frozen nose assumptions
- Frontal, fixed-phone camera; live grayscale patch aligned using facial landmarks.
- Separate left and right alar/nasal-wing ROIs; asymmetry is expected, not a failure.
- Paired control (no inflation) and three intended gentle Frenzel pumps; a visible skin signal isn't a measurement of nasal pressure.
- Measurement-quality warning must be separate from event detection. Nose signals may be masked by fingers.
- Natural finger pinch was **not reliably distinguished** in the latest pilot. Positioning fingers underneath exposes alar tissue but is not typical. A nose clip and instructional photos are deferred *design options*, not accepted product requirements.
- Existing v0.10 nose peak detection sometimes counted four events when the experienced tester deliberately performed three. Preserve this finding; do not tune thresholds blindly.

## Research evidence, not public test data
The private archive stores actual historical v0.7, v0.8, v0.9, v0.10 JSON files. The v0.10 paired test with fingers underneath yielded 0 control events vs 4 active peaks (one weak extra); the natural finger pinch yielded 1 control event vs 1 active, indeterminate. These are two single-person trials, not validated sensitivity or specificity.

## New frontal throat feasibility experiment
1. User keeps eyes facing the screen, chin/neck/upper chest in the camera; avoid needing a side pose.
2. Three draggable ROIs on neck: *central anterior neck* over visible thyroid-cartilage region, and two lateral skin references. All must be unobscured. **Placement is user-confirmed, not anatomically identified by AI.**
3. Paired test: 3s prep + 5s baseline + 8s no intentional neck movement; then same sequence with 3 gentle Frenzel attempts. Optional third test is a single swallow as a **positive-motion camera check**, never Frenzel validation.
4. Algorithm: stabilized grayscale frontal neck crop; template correlation of selected skin texture; displacement of central template relative to mean displacement of two side references; positive upward motion; local peak detection with MAD/no-inflation control calibration, refractory interval, quality scores and boundary rejection.
5. Interpretation: *movement signal present / no measurable movement / inconclusive*. **No detection of glottis, tongue base, vocal folds, epiglottis or ear pressure**, which are not directly visible in a frontal RGB camera. A real Frenzel can have negligible visible larynx motion; swallowing/voice/jaw movement can cause motion unrelated to successful equalization.
6. Acceptance for next step: repeated per-person 0 vs >=2 events with acceptable quality, but not infer population accuracy. Improve under natural small movements and different throat anatomies; validate placement with annotated video subject to consent before making product claims.

## Persistence / continuity
- Browser `localStorage` keys: `eqcoach_nose_v010`, `eqcoach_throat_v0101` (numeric arrays only).
- Root homepage: **Export project state** JSON includes both modules; **Import** accepts same project state or compatible single-module JSON exports.
- Different Netlify deployments often have different site origins, so localStorage DOES NOT follow automatically; export and save the project-state JSON after testing and import it into the new deployment.
- User may preserve the **private research archive** ZIP together with current deployment ZIP; attach either archive and latest project-state JSON in later ChatGPT sessions for exact continuity. The private archive contains raw numerical research files and must **not be deployed publicly**.
- Still needed for proper production-grade history: versioned repository, consent policies, non-public storage with opt-in encryption, multi-user schema migrations and cross-device synchronization.

## Versioning rule
- `nose/`: frozen signal code is v0.10 unless explicitly changed; integration modifications are navigation and storage only.
- `throat/`: 0.10.1 initial POC, separate thresholds and measurement methods.
- Unified site integrated build 0.10.1. Never silently replace prior data or old thresholds. Preserve original files and a changelog.

## Sources / physiological caveats
AIDA2 learning material describes tongue/palate mechanics and avoidance of abdominal/chest pressure during Frenzel, but **visible anterior-neck motion is not a validated stand-alone indicator of successful Frenzel**. MediaPipe Face Landmarker predicts face landmarks (not an anatomical larynx or tongue-base landmark). In the final product, thorax, abdominal and neck signals should be combined as contextual evidence, not binary physiological diagnoses.

## 0.10.2 diagnostic finding and controlled fix
The v0.10.1 throat sample was **INDETERMINATE**: control 0 and Frenzel 0 peaks, with Frenzel action-valid 53.2% (46.8% hitting the template-search boundary); swallow action-valid 27.6%. There is no evidence from these data that throat movement was physiologically absent. The previous target ROI was 60x103 of 288x240 patch and could mix multiple tissues; lateral references were 46x76 and might include background or clothing. A fixed eye-offset aligned patch did not anatomically track the throat.
In 0.10.2 ONLY throat module calibration UX changes: the patch center is anchored to FaceLandmarker chin point 152 plus a user-adjustable offset below the chin, color live crop display (measurement remains gray), smaller same-level regions by default (target 56x48; refs 38x45), explicit user skin-only placement check, visual placement screenshot export, strongest-valid-signal review frame even without detected peaks. The previous signal thresholds and template matcher are not recalibrated; this is a placement/observability study, not a validated solution.
The nose v0.10 signal source and localStorage key are UNCHANGED. Throat localStorage key `eqcoach_throat_v0101` is kept for compatibility with existing project backups; run-level `neckOffset` is recorded on new runs and null on legacy runs. New calibration offset stored separately at `eqcoach_throat_crop_calibration_v0102`. Backup and import through root homepage are essential when Netlify origin changes.


## v0.10.4 display and horizontal positioning (2026-11-05)
- User screenshot of 0.10.3: native camera stream was 16:9; throat rectangle not horizontally aligned; selfie horizontal direction felt reversed.
- 0.10.4 renders a portrait 3:4 view by a face-centered crop from native video, with exact mapping of throat ROI rectangles from sensor image to portrait screen. Video inference and signal extraction operate on the native camera image, not the flipped presentation.
- Preview defaults to a horizontal reflection to correct reported selfie mirroring, with user override. This reflects both full-view and cropped ROI preview but NOT measurement data. Device-dependent front-camera hardware orientation must be confirmed visually.
- Throat center x is estimated from face axis eye midpoint and chin, without roll-based lateral displacement; optional horizontal offset slider +/- 0.4 eye widths, frozen across trials.
- Throat detection thresholds and nose module are unchanged.
- Synthetic 1280x720 video-to-portrait-browser mock passes basic camera, overlay, flip, slider, paired control/action flow. Live Android camera not yet tested.


### 0.10.5 (2026-11-05) camera regression recovery
The 0.10.4 user reported camera not opening on Android. Suspected cause: changed MediaPipe CDN version to 0.10.42 and video `display:none`. 0.10.5 reverts MediaPipe to validated 0.10.32, keeps <video> decoding, displays camera before model ready, offers retry and explicit errors. No nose or throat signal algorithm threshold changes.


## Current release 0.10.6 (2026-11-05)
After 0.10.4 and 0.10.5 did not open camera on the user's device, this version restores the previously working media initialization order and shows a native video element directly in a portrait 3:4 box. A dedicated camera-check.html can distinguish camera permission/browser issues from MediaPipe/model errors. Exact failure on Samsung device not yet identified because device log is unavailable. Nose v0.10 source and both signal engines remain frozen. Next step: open camera-check.html then throat/index.html; report visible status text or screenshot, **before** recording another trial.


## 2026-11-05 — v0.10.8 FOV / framing regression correction
- User reports v0.10.7 frontal throat module preview appears zoomed even at arm's length, unable to see entire face and neck; original nose module provided wide view. Treat framing as blocker before interpreting throat signals.
- Root-cause code: `object-fit:cover` displayed a landscape (1280x720) camera source inside a forced portrait (3:4) viewport, cropping the displayed image horizontally (visible width = about 42.2% of the source when source is 16:9 and destination 3:4). This is a DISPLAY crop, not proof of a change in physical camera optical zoom.
- v0.10.8: request nose-equivalent 1280x720 camera and frame resolution; `object-fit:contain` for live video + overlay; viewport follows exact returned video aspect ratio. Alternate 960x720 (4:3) mode can be chosen BEFORE starting a measurement (may be ignored by hardware). Report actual video dimensions. Mode locks once any run is saved.
- Overlay canvas sized to exact source video dimensions; landmarks and throat ROI transformed to source coordinates, with only display mirroring (no signal reflection).
- `throat/signal.js`, `nose/signal.js` and all v0.10 nose files byte-identical to v0.10.7. No research threshold changes.
- Latest real user trial (uploaded EQ-Throat-Lab-v0.10.4.json, despite being taken using recent browser release): pair status undetermined; control=0, Frenzel=1 detected peak, control valid 94.8%, Frenzel valid 68.5%, Frenzel boundary rate 30.1%, distance change 0.93%. Camera stream reported 1280x720, confirming portrait crop risk. Do not treat result as Frenzel failure.
- Synthetic Chromium tests verified native source 1280x720 (16:9), 960x720 (4:3), exact overlay dimensions, `object-fit:contain`, face inference, mode switching, display flip, paired run sequence, unchanged nose unit tests. Real Samsung camera remains to be checked.
- Next: user should verify complete face+neck on actual phone, and capture ROI placement PNG; if cannot fit, try 4:3 source mode before measurement. No more threshold changes before framing validation.


## 0.10.9 state and experimental input (Nov 5, 2026)
The v0.10.8 uploaded experiment contains camera 720x1280 source, `requestedMode: nose`, and identical neck boxes throughout. Baseline valid/total including skipped: control 50/50, Frenzel 11/49, swallow 19/49. Action validity: 65/78, 33/77, 70/79 respectively. As the Frenzel baseline failed 38/49 frames, its raw one-peak count is not interpretable; `bscale` to `ascale` changed 8.66% within the run. Swallow three raw peaks after a single intended swallow likewise require caution. This does not distinguish Frenzel/Val salva and cannot establish laryngeal anatomy. Need ROI placement photo prior to next data collection.

**Update:** throat has baseline quality validation before action, counting both sample matching and missing/geometry-invalid frames, and marks historical imports with failed baseline as uninterpretable. No threshold changes. The nose is still frozen at v0.10.


## v0.10.11 — low-quality flow tests must not block collecting Frenzel data
Screenshot (2026-11-05) shows a frontal full-frame camera 1280x720 displayed portrait due to device rotation, face rectangle covering much of the beard, narrow yellow throat target over exposed skin directly under beard, and purple references on either side. **No photo or optical data proves these regions correspond to the moving larynx**, nor that the references are stationary. User reported repeated failure of control baseline quality and inability to enter Frenzel. The v0.10.10 code had an unconditional `abort` for baseline-valid rate <70% or <26 samples, and none of the three regions were freely movable (only yellow within restricted x bounds).
Fix in v0.10.11: low-quality control and action trial data are retained (JSON marks `researchOnly`, `baselineQuality`, `qualityAtCapture`) and can be followed by Frenzel. `compare` remains undetermined unless both runs meet quality requirements. The baseline threshold remains a diagnostic criterion, but is **not a blockade**. Yellow, left and right ROI may be dragged individually in live crop, and yellow height can be adjusted. Avoid beard, clothing, and background. Future tests need a placement photo plus JSON; don't infer physiology from peaks alone.

## v0.10.12 — real-world optical flow failure analysis and evidence capture

User's paired file `EQ-Throat-OpticalFlow-0.10.11.json` (2026-11-05): control baseline 67/75 valid, action 109/120; Frenzel baseline 12/75 and action 2/116 valid. Only ~39% of Frenzel action frames had >=5 central tracked features; only ~12% had >=3 tracked features in at least one lateral reference. Control face center x ~0.50 of image width, Frenzel active x ~0.32, corresponding to a substantial lateral change not captured by face-scale-only quality metrics (pair distance change just 0.24%). The three-ROI reference design cannot make reliable calls under these conditions. A target-only signal may still be explored, but cannot be used to validate larynx motion or Frenzel physiology. Older run stored in PRIVATE research only.

The development team attempted a dynamic moving-ROI upgrade to follow tissue automatically, but it **failed synthetic regression** with combined global/local motion. It was rejected and not shipped. The proven 0.10.11 group-tracking logic and signal thresholds remain the interpretable path; 0.10.12 adds (a) pre-run live tracking-quality feedback, (b) separate non-diagnostic center-only signal even without skin references, (c) opt-in local-only video recording for visual assessment, (d) explicit face-lateral-drift report. Nose remains byte-identical. 

Next: inspect video plus placement image before any further algorithmic architecture changes. If frontal skin/texture does not visually reveal the moving structure (potential beard occlusion, chin anchor drifting independently from throat), do NOT claim that threshold changes can fix it. Consider body/shoulder pose anchoring, alternate viewpoint, simple fiducial sticker, or a minimally standardized capture posture as prospective *options*, not assumed requirements.


## 0.10.16 — Frozen upper-neck signal prototype (2026-11-06)
Video lab was retained and extended with non-Frenzel negative-control conditions (swallow, jaw). A reproducible *offline Python* analysis method with locked ROI and parameters is included in `research/frozen_detector.py` and explained in `research/PROTOCOL.md`. It **replays** the development pair with 3 exploratory neck motion peaks versus 0 in control, but does not constitute independent validation. Fixed ROI selected after inspecting the same pair; future recordings must not be used to retune it. The browser does NOT run the offline analyzer automatically. Nose files and historical throat engine files unchanged. No videos shipped in public ZIP.
