Skip to content

Commit 5a9f725

Browse files
fix(ding): report a located-but-unproven composer as a wait, not a coverage gap
A harness that locates its composer and still returns Ambiguous — an active turn, a modal, an unrecognised footer — was folded into NoMaintainedComposer, which says no harness could locate the pane and that it will not clear until one can. Both halves were false for a covered pane that may settle on its own. Per review on #375. agent-identity: dev3.direct.claude.paqjmjfq agent-persona: generalist agent-supervisor: unavailable agent-tool: Claude Code agent-tool-version: 2.1.250 agent-runtime: Claude Code 2.1.250 tooling-profile: dotfiles@a1a5f89
1 parent ffd8aa8 commit 5a9f725

1 file changed

Lines changed: 21 additions & 4 deletions

File tree

src/ding/mod.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@ pub enum DeferralReason {
257257
/// The lowest maintained composer holds text that is not the exact notice — typically a human
258258
/// draft. Named by harness only: the text on that pane belongs to whoever is typing it.
259259
ComposerChanged { harness: &'static str },
260+
/// A maintained harness located its composer but proved nothing about this screen — an active
261+
/// turn, a modal, or a footer it does not recognise. Distinct from an unlocatable pane: this
262+
/// one is covered and can clear on its own, so it is a wait rather than a coverage gap.
263+
ComposerUnproven { harness: &'static str },
260264
/// No maintained harness could locate a composer on this pane, so nothing is proven either
261265
/// way. An unrecognised, resized, or not-yet-drawn TUI lands here.
262266
NoMaintainedComposer,
@@ -271,6 +275,10 @@ impl std::fmt::Display for DeferralReason {
271275
formatter,
272276
"the {harness} composer holds other text (a draft or an unfinished turn); waiting rather than typing over it"
273277
),
278+
Self::ComposerUnproven { harness } => write!(
279+
formatter,
280+
"the {harness} composer was located but proved nothing about this screen (an active turn, a modal, or an unrecognised footer); waiting for it to settle"
281+
),
274282
Self::NoMaintainedComposer => formatter.write_str(
275283
"no maintained harness could locate a composer on this pane; nothing will be delivered here until one can",
276284
),
@@ -643,14 +651,17 @@ fn observed_poke_with_window(
643651
ComposerState::ExactBlocked => return Ok(PokeOutcome::Staged),
644652
ComposerState::EmptySafe => {}
645653
ComposerState::Changed | ComposerState::Ambiguous => {
646-
// `Ambiguous` without a located harness is the unrecognised pane; with one it is a
647-
// maintained harness that proved nothing about this screen, which reads the same to an
648-
// operator as an unlocatable composer.
654+
// Whether a harness was located is the difference between a wait and a coverage gap,
655+
// so it decides the reason rather than being folded into one catch-all.
649656
return Ok(PokeOutcome::Deferred(match (state, harness) {
650657
(ComposerState::Changed, Some(harness)) => {
651658
DeferralReason::ComposerChanged { harness }
652659
}
653-
_ => DeferralReason::NoMaintainedComposer,
660+
// `Changed` cannot arise without a located harness — only a located composer can
661+
// be read as holding other text — but the classifier owns that invariant, not
662+
// this call site, so an unlocated pane is reported as exactly what was observed.
663+
(_, Some(harness)) => DeferralReason::ComposerUnproven { harness },
664+
(_, None) => DeferralReason::NoMaintainedComposer,
654665
}));
655666
}
656667
}
@@ -3941,6 +3952,12 @@ Enter to select · ↑/↓ to navigate · Esc to cancel";
39413952
human_codex_screen(),
39423953
DeferralReason::ComposerChanged { harness: "codex" },
39433954
),
3955+
// Located, but an unrecognised footer proves nothing about the screen. This is a wait,
3956+
// not a coverage gap, and must not be reported as an unlocatable pane.
3957+
(
3958+
idle_codex_screen_with_footer("Esc to interrupt"),
3959+
DeferralReason::ComposerUnproven { harness: "codex" },
3960+
),
39443961
(
39453962
"unrecognized renderer".to_string(),
39463963
DeferralReason::NoMaintainedComposer,

0 commit comments

Comments
 (0)