Skip to content

feat(agent): enforce unresolved-conflict escalation to the coordinator - #86

Merged
atomicdragonranch merged 1 commit into
masterfrom
feat/82-conflict-escalation
Jul 9, 2026
Merged

atomicdragonranch merged 1 commit into
masterfrom
feat/82-conflict-escalation

Conversation

@atomicdragonranch

Copy link
Copy Markdown
Owner

Closes #82.

Problem

ConflictRecord defaults resolution="unresolved" and its docstring states sub-agents must never silently resolve a conflict; they mark it unresolved and hand it to the coordinator. But escalate() routed purely by report.severity and never looked at diagnosis.conflicts. A diagnosis carrying contradictory evidence could pass at LOW/MEDIUM and be logged-and-forgotten. Acting autonomously on contradictory evidence is the exact failure mode the contract exists to stop.

Fix

escalate() now, whenever the diagnosis has unresolved conflicts:

  • surfaces them first (ERROR log + prominent printout), before any severity prompt, so the audit trail never shows a silent pass;
  • forces a human acknowledgment gate for non-CRITICAL incidents (CRITICAL already gates, and conflicts are surfaced before that prompt, so no double-prompt);
  • records unresolved_conflict_count and conflicts_acknowledged in the audit entry.

Degrades gracefully with no stdin (automated run): the conflict is still surfaced and audited, acknowledgment recorded as None, never dropped.

Tests (6)

Surfaced + gated + audited on accept / reject / no-stdin; resolved conflicts not gated; no-conflict path unchanged; CRITICAL+conflict prompts once, not twice.

Full suite 222 passed; ruff + mypy clean.

https://claude.ai/code/session_01R5VygSzbGTggW7mHd3PVwE

Closes #82.

ConflictRecord defaults resolution="unresolved" and the schema states
sub-agents must never silently resolve a conflict; they hand it to the
coordinator. But escalate() routed purely by report.severity and never looked
at diagnosis.conflicts, so a diagnosis carrying contradictory evidence could
pass at LOW/MEDIUM and be logged-and-forgotten. Acting autonomously on
contradictory evidence is the exact failure mode the contract exists to stop.

escalate() now, whenever the diagnosis has unresolved conflicts:
- surfaces them first (ERROR log + prominent printout), before any severity
  prompt, so the audit trail never shows a silent pass;
- forces a human acknowledgment gate for non-CRITICAL incidents (CRITICAL
  already gates, and the conflicts are surfaced before that prompt, so no
  double-prompt);
- records unresolved_conflict_count and conflicts_acknowledged in the audit
  entry.

Degrades gracefully with no stdin (automated run): the conflict is still
surfaced and audited, acknowledgment recorded as None, never dropped.

Tests (6): surfaced + gated + audited on accept/reject/no-stdin, resolved
conflicts not gated, no-conflict path unchanged, and CRITICAL+conflict prompts
once not twice. Full suite 222 passed; ruff + mypy clean.
@atomicdragonranch
atomicdragonranch merged commit cc4f12c into master Jul 9, 2026
3 checks passed
@atomicdragonranch
atomicdragonranch deleted the feat/82-conflict-escalation branch July 9, 2026 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(agent): enforce unresolved-conflict escalation to the coordinator

1 participant