chore(chat-routes): mark single-consumer turn seams @experimental + document upload's sole consumer (audit)#202
Conversation
…cument upload's sole consumer Audit simplification pass. No behavior change, no export added or removed — honest labeling of the single-consumer surface the over-engineering audit flagged. - turnLock/contextGate/beforeTurn/onRawEvent: @experimental + single-consumer (gtm, #200) JSDoc. They stay FLAT top-level options (not grouped under a `hooks` object): that regroup would break gtm's shipped createChatTurnRoutes call for no mechanism gain, and this package's exports are additive-only. lifecycle/heartbeat stay stable (generically useful). - createUploadRoute: kept, NOT deleted. Its sole consumer is the `--chat` scaffold (the shipped reference multimodal path, PR #199). Documented that the four fleet apps (gtm/tax/legal/insurance) keep their own durable-vault upload routes (KV / encrypted R2) — a different persistence model — and shouldn't route through it. - Docs (AGENTS.md/CLAUDE.md module map, ARCHITECTURE.md) reflect both.
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 0781808c
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
tangletools · auto-approval · reason: drewstone_author · 2026-07-17T18:03:37Z
tangletools
left a comment
There was a problem hiding this comment.
🟢 Value Audit — sound
| Verdict | sound |
| Concerns | 0 (none) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 67.2s (2 bridge agents) |
| Total | 67.2s |
💰 Value — sound
Doc-only honest labeling — marks 4 single-consumer turn seams @experimental and documents createUploadRoute's sole consumer; zero behavior change, resists the two wrong fixes (delete a shipped feature / regroup into a hooks object).
- What it does: Adds @experimental JSDoc tags + 'single-consumer (gtm, #200); shape may change' notes to four optional seams on CreateChatTurnRoutesOptions (turnLock, contextGate, beforeTurn, onRawEvent); adds a @remarks block to createUploadRoute naming its sole consumer (the --chat scaffold) and explaining why the four fleet apps keep their own durable-vault routes; syncs the module-map prose in AGENTS.md and A
- Goals it achieves: Honest stability labeling. An over-engineering audit flagged these as single-consumer surfaces that currently look like stable public API. The PR signals to future consumers that the shape may change until a second consumer exercises it — without breaking the one shipped caller (gtm's chat vertical, #200) or the multimodal scaffold (PR #199). lifecycle/heartbeat stay untagged because they are gene
- Assessment: Good change, in the grain of the codebase. (1) It is honest: it does not pretend single-consumer seams are stable, and it does not delete a shipped, tested, advertised feature to look tidy. (2) It picks the correct tool — the @experimental JSDoc convention — over heavier machinery (runtime warnings, type namespaces) that would be over-engineering for a labeling task. (3) It explicitly resists two
- Better / existing approach: none — this is the right approach. Searched for: (a) an existing hooks-grouping or options-namespace pattern in the package that this should follow — none; the additive-only invariant and the shipped gtm caller make flat top-level options correct. (b) an existing upload primitive elsewhere in src/ that createUploadRoute duplicates — none; /web owns body parsing, /stream owns turn buffering, /chat-
- Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 2
- Bridge warning: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content
🎯 Usefulness — sound
Honest stability labeling of single-consumer chat-route seams (@experimental) and the upload route's sole consumer (the --chat scaffold) — pure doc/JSDoc, no behavior change, claims verified against the repo.
- Integration: No new surface; the labeled seams remain reachable via createChatTurnRoutes (turn-routes.ts:249-269) and the upload route via template-chat/src/chat.ts:151. Nothing was added or removed, so reachability is unchanged.
- Fit with existing patterns: Matches the codebase's documentation-as-contract pattern: JSDoc stability tags + the module map kept in sync across AGENTS.md:32 and ARCHITECTURE.md:91. The @experimental convention is the right grain for a single-consumer, additive-only package whose exports must not break.
- Real-world viability: Doc-only change, so robustness is trivial — the only live assertion is 'single-consumer (gtm, #200),' which is conservative either way: if true, labeling is accurate; if the consumer count drifts, @experimental gives license to reshape without a breaking-change violation.
- Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 1
No concerns — sound change, no better or existing approach found. ✅
What this audit checks
It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.
| Pass | What it asks |
|---|---|
| Heuristic | Vague title? Whitespace-only or cruft-bearing diff? (content signals only) |
| Duplication | Do added function/class names already exist elsewhere in the repo? |
| Value Audit | What does it do? What goal does it achieve? Is it good? Better architecture or already-exists? |
| Usefulness Audit | Does it integrate and fit? Will it hold up in real use and actually get used? |
Findings are concerns, not blocks — the human reviewer decides what to do with them.
✅ No Blockers —
|
tangletools
left a comment
There was a problem hiding this comment.
✅ Approved — 1 non-blocking finding — 0781808c
Full multi-shot audit completed 3/3 planned shots over 4 changed files. Global verifier still owns final merge decision.
Full immutable report for this review: trace
Summary comment for this run: full summary
tangletools · 2026-07-17T18:08:07Z · immutable trace
Audit simplification pass. No behavior change, no export added or removed — this is honest labeling of the single-consumer surface the over-engineering audit flagged. Full suite green (typecheck, 2506 tests, build).
createUploadRoute: KEPT, not deleted — and here's why
The audit premise was "zero consumers." That's true for the four fleet apps but not true overall:
grep createUploadRoute= 0 in all four). They write to a durable vault (gtm/legal/insurance → KV; tax → AES-GCM-encrypted R2 + DB integrity trail). That is a different persistence model from this route's inline-data:-or-ephemeral-sandbox-workspace split, so routing any of them throughcreateUploadRoutewould be a downgrade, not a cleanup. Option (b) (wire gtm onto it) is therefore not a clean win and was not done.--chatscaffold.create-agent-app --chat→template-chat/src/chat.tsimports and wirescreateUploadRouteas its multimodal path (PR feat(create-agent-app): --chat variant — the one-day multimodal chat app, CI-enforced (#188 wave 3) #199, "the assembled multimodal chat app"). It's also documented inexamples/chat-app.mdand covered bytests/chat-routes/upload.test.ts. Deleting it would break the scaffold's typecheck and rip a shipped, advertised feature out of the flagship template — that's feature removal, not dead-surface removal, and the task explicitly kept the multimodal input path.So
createUploadRouteis single-consumer (the scaffold), same category as the lifecycle seams below — not zero-consumer. This PR labels it honestly instead of deleting it. If you'd rather strip multimodal from the scaffold entirely (a bigger, deliberate call), say so and I'll do that as a separate change.Seams: marked @experimental, NOT regrouped
turnLock/contextGate/beforeTurn/onRawEvent→@experimental+single-consumer (gtm, #200)JSDoc. They enabled the gtm collapse and are the extension pattern, so they stay.lifecycle/heartbeat→ left stable (generically useful).hooks?: {}object. gtm's shippedcreateChatTurnRoutes<GtmTurnContext>({ ... })call (from feat(chat-routes): product turn-lifecycle seams (heartbeat, beforeTurn, lifecycle, context-gate, turn-lock) #200) passes all six as flat top-level options. Grouping them is a breaking change to the one consumer for zero mechanism gain, and this package is additive-only. Documented the grouping intent in the docblock instead.Files
src/chat-routes/turn-routes.ts— docblock + 4@experimentalfield tags; fixed a stale "Five seams" → "Six".src/chat-routes/upload.ts—@remarksdocumenting the sole (scaffold) consumer and the deliberate fleet-vault difference.AGENTS.md(+CLAUDE.mdvia symlink) /ARCHITECTURE.md— module map reflects both.Net: +28 / −7 across 4 files. No deletions.