Slice 3 of Round 4 — the Toby-the-dog fix. With Slice 1 the probes
report severity and with Slice 2 banners route by severity, but the
critical behavioral change is here: the agent's system prompt itself
must carry the degradation truth so the model can't confidently lie
about features that don't work.
The Toby case in detail: user said "remember my dog Toby is a golden
retriever". The Ollama probe correctly reported missing nomic-embed-text
(degraded). The memory extractor tried to embed Toby, the embed call
failed, no row was inserted in `facts`. But the agent's system prompt
said "you are Jarvis with memory" and the model answered "Got it —
Toby." A lie, dressed up as competence.
Implementation:
- `AgentOrchestrator` gains a private `var degradationSummary: String?`
+ a public `setDegradationSummary(_:)` actor-isolated setter. Mutable
because installAgent runs BEFORE runBootHealth in the boot order;
the orchestrator is constructed with `nil` and AppDelegate pushes
the summary in post-construction. Re-probes from the Status panel
update the value mid-session.
- `runTurn` prepends the summary BEFORE `composedSystem` (which already
includes the UntrustedWrapper nonce + locked self-aware preamble),
so the warning lands at the very top of the system message — outranks
the preamble, outranks presence/memory enrichment.
- `AppDelegate.runBootHealth` now calls
`orchestrator.setDegradationSummary(buildDegradationSummary(snapshot:))`
after every probe sweep. The builder produces text like:
CRITICAL — SUBSYSTEMS DEGRADED:
- memory: failed (vec0 missing) — DO NOT promise to use memory
- ollama: degraded — missing models: nomic-embed-text
Be honest. Do not claim to use tools that are unavailable. Do not
pretend memory works if it doesn't.
When every subsystem is `.ok`, the function returns `nil` and the
orchestrator's behavior is identical to pre-Round-4.
- Cache-hints invariant preserved: the locked preamble is ~700 chars,
the worst-case degradation summary is <500 chars; sum stays well
under the 4096-char Anthropic cache-eligibility boundary so adding
the summary doesn't unintentionally flip `cache_control` emission.
CacheHintsEligibilityTests/preambleDoesNotEnableCacheUnintentionally
remains green.
4 new tests in AgentOrchestratorDegradationPreambleTests (all pass):
* DP1: initial summary threaded into first turn's system message
* DP2: nil summary leaves prompt unchanged (no "CRITICAL" / "DO NOT")
* DP3: setDegradationSummary updates the next turn's prompt
* DP4: setting summary back to nil clears it from the next turn
Boundary gates 18/18 green. `swift test --package-path packages/AgentCore`
runs 242/240 (4 new minus 2 pre-existing unrelated failures from
qwen2.5-coder model-ID literal drift, present before Round 4).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>