Skip to content

feat: fix the coach's input (spec 004) - #13

Merged
AnaLauraFFerraz merged 16 commits into
mainfrom
004-coach-input
Oct 25, 2026
Merged

AnaLauraFFerraz merged 16 commits into
mainfrom
004-coach-input

Conversation

@AnaLauraFFerraz

@AnaLauraFFerraz AnaLauraFFerraz commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Summary

Spec 004 fixes the input the AI coach receives. Four of the six texts of the first demo seed were rejected because of what the coach was told, not because of the analysis: it never knew which laps it compared, it was given the personal best (which in the demo is one of the compared laps), and it ranked, numbered and read the signs itself.

  • The coach's message names the two compared laps (number, official time, validity), states the official difference in words, and says that every delta is the primary lap against the comparison lap. When the comparison lap is invalid, the code says that the time it gains is not a target.
  • The code, not the model, ranks and labels up to three opportunities with the frontend's rule (deltaLossS > 0, stable descending sort, first three; label <rank>. <apex>m · +<loss>s) and writes the direction of each braking, pressure and throttle difference in words.
  • No benchmark (personal or theoretical best) enters the message. GET /sessions/:id/benchmark is unchanged.
  • The system prompt is rewritten (no own corner numbers, no sectors, no statement against a field, coasting defined, the sign of every difference, no unmeasured driver states).
  • PROMPT_VERSION (SHA-256 of the line-break-normalized prompt and of the messages built from fixed reference inputs, 16 hex) is exported and stored per row in the new column lap_analyses.prompt_version.
  • A cached analysis is served only if its prompt version and model are the current ones; otherwise it is regenerated once per pair (single-flight) and the row replaced, or, without the API key, answered with 503.
  • npm run analyze also prints the exact message the coach would receive and the prompt version, with no paid call (the output is no longer a single JSON document).

Spec, plan, research, tasks: specs/004-coach-input/.

Contract

Response shape and status codes of POST /sessions/:id/analysis are unchanged. One behaviour change: a cached pair whose prompt version or model is not the current one (every row written before this PR has prompt_version NULL) is no longer served. With the API key it is regenerated (a paid call, once per pair even under concurrent requests) and the row is replaced; without the key the endpoint answers the existing 503 (coaching indisponível: configure ANTHROPIC_API_KEY). Current rows are still served with cached: true.

The first start of this version migrates data/telemetry.db in place (adds lap_analyses.prompt_version); the README documents the VACUUM INTO backup to take first, to a folder outside the repository.

No frontend change.

Bug fixed

Two simultaneous requests for a new pair made two paid calls, and the second ended in a 500 on SQLITE_CONSTRAINT_UNIQUE, discarding its paid text. Concurrent requests for the same pair now share one call.

Validation

  • npm run typecheck clean, npm test 190/190, run without an API key (no paid call by the agent at any step).
  • Each new pure function was seen failing on its own assertion against a stub before the implementation.
  • Contract check: no diff against main in messageFormat.ts, sessionsRouter.ts and the sample/session repositories; every status code and error string of analysisRouter.ts kept.
  • Replay of the published demo recording into a temporary database, then npm run analyze for the six ordered pairs of laps 6, 7 and 8: each coach message equals, character for character, the one approved in the research; the lap times are 74.306, 74.144 and 73.372 s. Implemented PROMPT_VERSION: 8c4d40e60f323e80.
  • Stale-row policy on the same temporary database, no key: a row with prompt_version NULL answers 503; with the current version and model it is served with cached: true.

Manual steps

  • Backup before the first start on the real database: the maintainer will not start this branch on data/telemetry.db before the merge, so the backup is taken before the first start after the merge.
  • Token count of the new prompt, measured by the maintainer with the token-counting endpoint (an estimate, free): 2,172 tokens for claude-opus-4-8, above the documented 1,024-token minimum for prompt caching. Caching of the system block with this model had already been seen working with the previous prompt (cache_write=1380, then cache_read=1380), which also corrected a wrong sentence in the README, CLAUDE.md and coachService.ts that said the prompt was below the minimum. The new prompt itself has not been sent to the API yet.
  • The six messages were read and approved by the maintainer.

Out of scope

  • The analysis engine's artefacts visible in the messages (shared ±80 m windows, braking start at the apex, totalDeltaS), next spec.
  • Spec 003: the seed's promptVersion, the start check against PROMPT_VERSION, the export's --dry-run.
  • The frontend (the duplicated opportunity rule is a known debt) and .gitattributes eol rules.
  • The reading of texts generated with the new prompt (human reading, before they are published).
  • serverFailFast.test.ts is not hermetic (recorded in the research as debt).

CI

Last push: head da41324, run 40146450927: typecheck success, test success (jobs API).

@AnaLauraFFerraz
AnaLauraFFerraz marked this pull request as ready for review October 25, 2026 00:27
@AnaLauraFFerraz
AnaLauraFFerraz merged commit 7dc6685 into main Oct 25, 2026
2 checks passed
@AnaLauraFFerraz
AnaLauraFFerraz deleted the 004-coach-input branch October 25, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant