Files
hapi/android/core/protocol
weishu 03651984e0 feat(android): chat pipeline port — 48 chat fixtures green (B-M2a)
Port web/src/chat/ (normalize → reduce → group) to :core:protocol
app.hapi.protocol.chat, file-for-file:

- ChatTypes (blocks/tool-call/permission/usage; AgentEvent sealed over a
  verbatim raw JsonObject so wire events project byte-exact)
- Normalize/NormalizeUser/NormalizeAgent (codex/output/event families,
  agy mapping, skip rules, stringify-never-drop fallback)
- Tracer (parentToolUseId grouping, prompt fallback, orphans)
- ReducerEvents/ReducerTools/ReducerCliOutput/ReducerTimeline/Reducer
  (usage-limit pipe parsing, dedupe + title echo, api-error folding,
  tool pairing, stream coalescing, agent-run cards, turn-duration,
  title-changed synthesis, sentinel suppression, pending-permission
  synthesis with oldest-visible gate, latestUsage, goal filtering)
- ToolGroups (families, id stability, buildVisibleChatBlocks)
- ToolPresentation (event labels; java.time in place of toLocaleString)
- FixtureProjection + CanonicalJson + ChatFixtureTest: every
  shared/fixtures/chat/*.json replayed and compared under canonical
  JSON equality, with a loud fixtureVersion gate

TS undefined maps to Kotlin null, TS null to JsonNull; permission
objects carry a presence set so JS spread-merge semantics survive.

:core:protocol:test 223/223 green (48 fixtures), :app:assembleDebug ok.
2026-08-17 16:20:27 +08:00
..