CRUMB a card from devarno-cloud

Dual Emitter Contract

kahn intermediate 5 min read

ELI5

Two parallel postal forms — one for parcels of CI status, one for parcels of agent thoughts. Same paper size, same stamps, same drop-box ritual; only the contents differ. Keeping them as separate forms means a sender only carries the form they need.

Technical Deep Dive

contracts/kahn_emit.py (CI-prototype) and contracts/kahn_agent_emit.py (agent product surface) are sibling files in lockstep on shared concerns and deliberately diverged on schema-shape concerns.

Mirrored Concerns (verbatim)

ConcernBoth files
Timestamp shapeUTC, millisecond precision, Z suffix; now_ts() byte-identical
Append mode"ab", one write per call, newline terminator, UTF-8; flush()+fsync() on __exit__
Unknown-field passthroughBuilders never strip unknown keys
Validation gatingvalidate=False default; jsonschema imported lazily inside _build_validator()

Deliberate Divergences

classDiagram
class kahn_emit {
+Status: pending..blocked
+Outcome: clean..catastrophic
+run_start()
+node_transition()
+node_attempt()
+run_end()
+Emitter
~no agent_id
}
class kahn_agent_emit {
+AgentStatus: thinking..failed
+AgentOutcome: converged..aborted
+AuditResult: pass|fail|warn
+agent_run_start()
+agent_transition()
+tool_invocation()
+audit_checkpoint()
+agent_run_end()
+AgentEmitter
+agent_id on every event
}
class transitions_schema_json
class agent_transitions_schema_json
kahn_emit ..> transitions_schema_json: validates against
kahn_agent_emit ..> agent_transitions_schema_json: validates against

Why Sibling, Not Merged

Per agent-fleet.md: merging would conflate Status + AgentStatus into one enum and re-introduce the drift the realignment fixed. Producers vendor exactly one file; mixing CI + agent symbols would force every consumer to filter.

Vendoring Contract

  • Stdlib-only runtime. Zero non-stdlib deps unless validate=True.
  • A producer in a sister repo copies one file into its tree and emits.
  • The audit:contract-shape checkpoint (audit/contract-shape.json) verifies both emitters expose every event their respective schemas declare — drift here means events pass the constructor but fail downstream validation.

Key Terms

  • lockstep → Shared concerns are mirrored without intentional divergence; touching one without the other is a bug.
  • Frozenkahn_emit.py is at v0.4.0-ci-prototype; do not extend with agent semantics.
  • dep-light producer → A sister repo that vendors the emitter with no extra Python deps.

Q&A

Q: Why is jsonschema imported lazily? A: So vendoring stays cheap. A dep-light producer that never opts into validation never pays for jsonschema.

Q: Can I add a new event to kahn_emit.py? A: No — the CI surface is frozen. New agent semantics go to kahn_agent_emit.py.

Q: What enforces lockstep across the two emitters? A: Convention + the audit:contract-shape checkpoint. There is no shared base class — duplication is intentional so each emitter can be vendored alone.

Examples

A producer in choco-hq that wants to emit agent transitions copies only kahn_agent_emit.py plus agent_transitions.schema.json. Its pyproject.toml gains zero runtime deps; if it later opts into validation it adds jsonschema to its own extras.

neighbors on the map