feat(broker): wire session attribution into commit attestation

Merged
KH
3mo ago
+548-5

Summary

  • Adds session_ref: Option<String> to CommitAttestation (wire key: sessionRef) so git commits stamped by spawned agents carry a Session-Id: trailer linking the commit to the session that produced it
  • Updates with_commit_attestation_env() to inject RELAY_ATTEST_SESSION_ID when session_ref is present and valid; strips any stale inherited value before re-injecting so child agents cannot inherit an ancestor's session
  • Updates the embedded prepare-commit-msg hook to stamp Session-Id: $RELAY_ATTEST_SESSION_ID inside the existing attestation block
  • Fixes broker_payload_from_action (bridge.rs): uses find_map across four key aliases in priority order — session_ref → sessionRef → session_id → sessionId — matching the canonical fleet on-wire format used by relaycast_spawn_session_ref; blank/whitespace values are skipped so they cannot suppress a valid later alias

Why

relayauth#79 covers the ledger half of the attribution chain. This closes the spawner half:

commit → attestation ledger → OIDC-bound human → session → reasoning
                                                  ↑
                                          Session-Id trailer (this PR)

Without this, sessionRef stays null in the ledger even after relayauth#79 merges, because relay's spawner never injects the session into the commit environment.

What's out of scope

  • relayauth: ledger side already handled by relayauth#79
  • factory: POST /v1/attestations/grants needs to forward sessionRef from the spawn spec to relayauth — separate, smaller change, noted for Chief routing

Test plan

  • broker_hook_appends_session_id_trailer_when_session_ref_present — end-to-end: real git commit through a spawned agent carries Session-Id: trailer
  • session_ref_in_attestation_is_injected_as_relay_attest_session_id
  • absent_session_ref_does_not_inject_session_id_env_var — backward-compatible: existing attestations without session_ref are unaffected
  • invalid_session_ref_is_silently_skipped — control chars / empty strings skipped
  • stale_session_id_is_stripped_when_attestation_has_no_session_ref — child cannot inherit ancestor session
  • valid_session_ref_overwrites_stale_session_id — re-injection replaces stale value
  • bridges_top_level_session_ref_canonical_key — fleet canonical session_ref key bridges correctly
  • bridges_top_level_session_ref_camel_case_alias — fleet sessionRef camelCase alias bridges correctly
  • blank_session_ref_falls_through_to_valid_session_ref_alias — blank value does not suppress valid alias
  • blank_session_id_falls_through_to_valid_session_id_alias — whitespace-only value does not suppress valid alias
  • bridges_top_level_session_id_into_attestation_session_ref — legacy session_id key still works
  • bridges_top_level_session_id_camel_case_alias — legacy sessionId camelCase alias still works
  • session_id_without_attestation_is_silently_ignored — un-attested spawns unaffected
  • explicit_attestation_session_ref_wins_over_top_level_session_id — no overwrite if already set
  • Full broker suite: 897 passed, 0 failed (CI green on e4fe62483)

Known pre-existing issue (not caused by this PR)

runtime::tests::delivery_retry_transient_blip_emits_failed_event_for_present_worker occasionally fails under heavy local parallel test load. It does not fail in CI (passes on both main and this branch), passes cleanly when run in isolation, and runtime/tests.rs was last touched three commits before this branch diverged. Not a blocker.

🤖 Generated with Claude Code