Skip to content

test: pin the insights no-cold-bootstrap contract at the wire, and the persist guard at its callers - #5845

Merged
atomantic merged 1 commit into
mainfrom
fix/insights-readpath-transport-assertion
Sep 2, 2026
Merged

test: pin the insights no-cold-bootstrap contract at the wire, and the persist guard at its callers#5845
atomantic merged 1 commit into
mainfrom
fix/insights-readpath-transport-assertion

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

Follow-up to #5626 — the two review threads we didn't hold that PR open for. Test-only; no production code changes.

  • Read-path assertion back at the wire. fix: dedupe insightsService's transport onto the shared aiProvider one #5626 moved the no-cold-bootstrap assertions from a fetchWithTimeout-level spy down to a callProviderAISimple-level one, because the transport moved to aiProvider. That's one export, but the AGENTS.md contract is broader — "PortOS must never queue up AI provider calls a user hasn't knowingly triggered", by any route. A future read path reaching a provider through a direct fetch, a streaming helper, or a second transport would slip past the export-level spy while it stayed green. Restores a global fetch spy alongside it.
  • The actual [module-hygiene-insights-api-transport] Reuse aiProvider for Insights LLM calls #5617 bug is now pinned at the Insights boundary. Both generators persist unconditionally once result.error is unset, so a transport that misclassifies a failed call as a successful empty completion overwrites a real cached theme/narrative with nothing. Until now that was only proven transitively — the shared transport returns an error, and you read the if (result.error) return guard at each call site. Now asserted directly: an errored transport result surfaces as { available: false, reason } and leaves atomicWrite untouched, for both generateThemeAnalysis and refreshCrossDomainNarrative — plus the positive case, so the guard can't pass by never writing at all.

Test plan

  • cd server && npx vitest run services/insightsService.test.js services/aiProvider.test.js — 39 pass
  • Bypass probe (the guard tests are not vacuous): neutering both if (result.error) guards in insightsService.js fails exactly the two persist-guard tests and nothing else; restoring them goes green again
  • fileUtils is partial-mocked via importOriginalPATHS is read at insightsService module scope, so a mock omitting it breaks the import outright

…e persist guard at its callers

Follow-up to #5626 (review threads we chose not to hold that PR open for).

Two gaps the transport dedupe left in insightsService.test.js:

The read-path assertions moved from a fetchWithTimeout-level spy down to a
callProviderAISimple-level one when the transport moved to aiProvider. That is
one export, but the AGENTS.md contract is broader — "PortOS must never queue up
AI provider calls a user hasn't knowingly triggered", by any route. A future
read path reaching a provider through a direct fetch, a streaming helper, or a
second transport would slip past the export-level spy while it stayed green.
Restore a global fetch spy alongside it so the assertion sits back at the wire.

Nothing anywhere pinned the actual bug #5617 describes: both generators persist
unconditionally once result.error is unset, so a transport that misclassifies a
failed call as a successful empty completion overwrites a real cached
theme/narrative with nothing. That was only proven transitively — the shared
transport returns an error, and you read the `if (result.error) return` guard at
each call site. Assert it at the Insights boundary instead: an errored transport
result surfaces as { available: false, reason } and leaves atomicWrite
untouched, for both generateThemeAnalysis and refreshCrossDomainNarrative, plus
the positive case so the guard can't pass by never writing at all.

Verified the two guard tests are not vacuous: neutering both `if (result.error)`
guards in insightsService.js fails exactly those two and nothing else.
@atomantic
atomantic merged commit 3a01633 into main Sep 2, 2026
7 checks passed
@atomantic
atomantic deleted the fix/insights-readpath-transport-assertion branch September 2, 2026 15:58
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