Skip to content

Commit f810335

Browse files
docs(cache-policy): verified provider healing profiles in CK inventory
Source-grounded ground-truth pass on the OpenCode<->Pi quirk divergences ahead of the MC-under-SUBC migration. Verified every divergent quirk is still valid (none obsolete) and added a 'Provider healing profiles' section establishing the organizing principle: quirk_pass_work = provider_requirement - serializer_healing, a per-path property. Verified (current source + harness-owner confirmation, not stale comments): - @ai-sdk/anthropic 4.0.1 (latest) groupIntoBlocks still merges consecutive assistants and pushes thinking in source order (no reposition); OpenCode 1.17.10 ships 3.0.82. stripReasoningFromMergedAssistants stays required. - OpenCode AI-SDK ProviderTransform.message empty-filter covers anthropic+bedrock only (exact model.api.npm, excludes google-vertex/anthropic); a separate V2 core runner path heals universally. - Pi 0.80.2 serializers heal empties universally (drop empty text/thinking, auto-fill reasoning_content='') and never merge consecutive assistants. Migration consequence: on the owned/llm-runner path the residual can be ZERO if llm-runner heals like Pi - Pi is named the reference implementation and the llm-runner column is the spec to fill. Co-authored-by: Alfonso [Magic Context] <288211368+alfonso-magic-context@users.noreply.github.com>
1 parent 03ca7db commit f810335

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

docs/cache-policy/ck-message-field-inventory.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,59 @@ is fixed across defer passes, and a provider/model switch is a HARD bust, so the
103103
emitter cannot vary mid-epoch. That fixed-determinism is what makes CK-level
104104
byte-stability imply wire byte-stability uniformly (no per-path vector binding).
105105

106+
## Provider healing profiles (verified ground truth)
107+
108+
The organizing principle for every bucket-(b) row:
109+
110+
```
111+
quirk_pass_work(provider, path) = provider_requirement - serializer_healing(provider, path)
112+
```
113+
114+
A "quirk" is never `f(provider)` alone. The same provider needs different
115+
treatment on different paths, because each path's serializer heals a different
116+
slice of the provider's requirements. So the quirk pass on a path applies only
117+
the RESIDUAL the path's serializer leaves unhealed. This was verified against
118+
current source + the two harness owners (not from stale comments):
119+
120+
**Genuine provider requirements** (these are real, not harness bugs):
121+
- Anthropic / Bedrock: no empty text/thinking content blocks on the wire;
122+
thinking blocks in the latest assistant turn must be unmodified and not
123+
repositioned after text; redacted thinking + signatures preserved verbatim.
124+
- OpenAI-compatible subset (Kimi / Moonshot / DeepSeek-V4-thinking): a tool-call
125+
assistant message must carry a non-empty `reasoning_content` field.
126+
127+
**Serializer healing coverage, by path (verified):**
128+
129+
| Requirement | Pi serializer (0.80.2, tarball-verified) | OpenCode AI-SDK path (`ProviderTransform.message`, 1.17.10) | OpenCode V2 core runner (`to-llm-message.ts`) | llm-runner (owned path) |
130+
|---|---|---|---|---|
131+
| drop empty text | universal | **anthropic + bedrock only** (exact `model.api.npm`; excludes google-vertex/anthropic) | universal | **TBD - must specify** |
132+
| drop empty thinking | universal | anthropic + bedrock only | universal | **TBD** |
133+
| auto-fill `reasoning_content=""` | yes (`requiresReasoningContentOnAssistantMessages`) | not in this path | n/a (native lowering) | **TBD** |
134+
| no consecutive-assistant merge (avoids interleaved-thinking 400) | **never merges** - one provider message per assistant | **merges** (`@ai-sdk/anthropic` `groupIntoBlocks`, still unfixed in 4.0.1 latest; OC ships 3.0.82) | n/a | **should follow Pi: do not merge** |
135+
| preserve redacted thinking + signature | yes | yes | yes | **TBD** |
136+
137+
**What this proves for the migration (the load-bearing point):**
138+
139+
- MC's per-harness divergence today is exactly the residual: Pi heals
140+
universally so MC clears reasoning to empty + drops signature for ALL
141+
providers and omits the merge + structural-noise workarounds; OpenCode's
142+
AI-SDK path heals anthropic/bedrock only so MC keeps the `[dropped]` fallback
143+
for copilot/openai-compat (#135) and the `stripReasoningFromMergedAssistants`
144+
workaround (because @ai-sdk still merges + interleaves thinking).
145+
- **On the owned/llm-runner path the residual can be ZERO.** If llm-runner's
146+
serializer heals like Pi (drop empties universally, auto-fill
147+
`reasoning_content`, do NOT merge consecutive assistants, preserve redacted +
148+
signatures), then EmptyContent/Reasoning are pure llm-runner-serializer
149+
concerns and MC's downstream quirk pass does NOTHING on the owned path. The
150+
entire merged-assistant interleaved-thinking quirk class simply does not exist
151+
if llm-runner never merges (Pi proves this is the clean design).
152+
- Therefore the llm-runner column above is the spec to fill: each "TBD" is a
153+
serializer behavior llm-runner must implement to keep the owned-path quirk
154+
pass empty. **Pi (`~/Work/OSS/pi-mono/packages/ai/src/providers/`) is the
155+
reference implementation** - `anthropic.ts` empty-drop + one-param-per-assistant,
156+
`openai-completions.ts` `reasoning_content` fill, `transform-messages.ts`
157+
cross-model thinking handling.
158+
106159
## Where assembly happens: plugin gap-fills, owned/MITM assembles
107160

108161
Family *assembly* (Anthropic pulls System-role messages to a top-level `system`

0 commit comments

Comments
 (0)