feat(sdk): emitter affordance to record host-side projection failures - #71
Merged
Merged
Conversation
MohammadHaroonAbuomar
requested a review
from Caitie McCaffrey (CaitieM20)
as a code owner
August 7, 2026 08:13
MohammadHaroonAbuomar
force-pushed
the
mhabuomar/host-error-synthesis
branch
2 times, most recently
from
August 7, 2026 19:27
4b76735 to
d754349
Compare
When the host's own to-wire projection fails before a valid AgentContext exists (e.g. a tool-call argument property getter throws during conversion at the chat seam), the host could only fail the run closed recordless: §11's reserved reasons cover failures the emitter can see, but a host-side projection fault happens before anything exists to emit. Add an emitter affordance — record_host_failure(point, ...) in Rust and Python, recordHostFailure in TypeScript, RecordHostFailure in .NET and Go — that synthesizes and delivers the fail-closed record: a deny host_error:context_invalid in the §10.3 rejection shape (null identities under the declared provider, decided_by null, no verdict summaries) carrying a payload-free type-name/path detail as the projected message and the envelope facts the host still knows (session_id, sequence, timestamp; ""/-1/absent when unknown). The record enters the same stream (sink, then buffer) as every emission. In evaluate_only the record still gets produced and documents the host fault without implying enforcement (§8). All five bindings assemble the record through the core's finalize over a deliberately partial envelope basis, so the shape is pinned to one implementation. No new reserved reason (context_invalid's cause already names "could not construct a schema-valid AgentContext") and no record-shape or schema change; golden vectors unaffected. Spec: §10.3 gains the "Host projection failure" host obligation (MUST fail closed, SHOULD record; sequence-integrity and data-minimization rules); §11 lists §10.3 as a synthesis site. Closes #70 Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>
MohammadHaroonAbuomar
force-pushed
the
mhabuomar/host-error-synthesis
branch
from
August 7, 2026 19:32
d754349 to
25316d5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #70.
What
When the HOST's own wire projection fails before a valid
AgentContextexists for a point (e.g. a tool-call argument property getter throws during to-wire conversion at the chat seam), the host could only fail the run closed recordless — §11's reserved reasons cover interceptor/context failures the emitter can see, but a host-side projection fault happens before anything exists to emit.This adds an emitter affordance that synthesizes and delivers the fail-closed record, in all five SDKs:
InterceptionEmitter::record_host_failure(point, HostFailure { detail, session_id, sequence, timestamp })emitter.record_host_failure(point, detail, *, session_id=, sequence=, timestamp=)emitter.recordHostFailure(point, { detail, session_id, sequence, timestamp })emitter.RecordHostFailure(point, detail, sessionId, sequence, timestamp)emitter.RecordHostFailure(point, HostFailure{Detail, SessionID, Sequence, Timestamp})Record semantics
deny host_error:context_invalid, null identities under the declared provider,decided_by: null, no per-interceptor summaries,interceptors_registeredas registered.host_error:context_invalid's cause already names "the host could not construct a schema-valid AgentContext";spec/reserved-reasons.jsonis untouched (nothing for ACS's vendored copy to sync).detailis a type name/path only, recorded as the verdictmessageand truncated by the same §10.3 projection as every combined verdict.""/-1/absent when unknown). The record enters the same stream (sink, then buffer) as every emission.evaluate_onlythemodemember keeps the record from implying a block happened (§8) — the action failed on its own, not on a verdict.finalizeover a deliberately partial envelope basis (never §4-valid, so the rejection shape is forced), keeping cross-SDK behaviour pinned to one implementation. No record-shape or schema change; golden vectors unaffected.Spec
enforce, SHOULD record; detail is type/path only (§14); sequence-integrity guidance; evaluate_only does not imply enforcement.Downstream
Unblocks microsoft/agent-framework#7564's recordless chat-seam projection-failure path and the same gap in the merged Python feature (adoption there is follow-up work; no agent-framework code is touched here).
Testing
Full local matrix mirroring CI:
cargo fmt --check+clippy -D warnings+cargo test --locked --workspace --all-features(Rust);ruff format --check/ruff check+pytest185 passed (Python); native build + zero binding drift +tsc+node --test135 passed (TypeScript);dotnet format --verify-no-changes+-warnaserrorbuild + 126 tests passed (.NET);gofmt/go vet/go testall packages ok (Go);scripts/check-version-consistency.pyagrees at 0.1.0-alpha.5. Four new tests per SDK (rejection shape, unknown-envelope defaults, evaluate_only + sink delivery, projection truncation).