diff --git a/CHANGELOG.md b/CHANGELOG.md index a55a12d0d..073aa51a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ breaking changes may land in a minor release. ### Fixed +- Explain that unpinned result-artifact scans search only the configured artifact\n directories themselves, so a nested story spec no longer produces an opaque\n `no-artifact` breadcrumb (#780). + - Read untracked paths verbatim so rollback snapshots and cleanup handle non-ASCII and space-edged filenames; a resumed run's pre-fix baseline still protects the files it listed; failed-unit diff capture includes them too (#783). diff --git a/src/bmad_loop/adapters/generic.py b/src/bmad_loop/adapters/generic.py index b6735b11e..80a869b0a 100644 --- a/src/bmad_loop/adapters/generic.py +++ b/src/bmad_loop/adapters/generic.py @@ -2270,7 +2270,13 @@ def _frontmatter_fallback( self._note_resultless_stop( task_id, "no-artifact", - "no result artifact newer than session launch under: " + where, + ( + f"no result artifact newer than session launch at: {where}" + if only is not None + else "no result artifact newer than session launch directly under: " + + where + + " (subdirectories are not searched)" + ), ) return None if len(candidates) > 1: diff --git a/tests/test_generic_tmux.py b/tests/test_generic_tmux.py index cbddc53b9..0bbba671b 100644 --- a/tests/test_generic_tmux.py +++ b/tests/test_generic_tmux.py @@ -1096,6 +1096,25 @@ def test_resultless_stop_breadcrumb_scan_no_artifact(tmp_path, monkeypatch): assert str(impl) in crumb["detail"] # names the searched dirs +def test_resultless_stop_breadcrumb_explains_non_recursive_artifact_scan(tmp_path, monkeypatch): + """A nested result is outside the legacy scan, so the breadcrumb must say so.""" + adapter, impl = make_dev_adapter(tmp_path) + monkeypatch.setattr(generic, "RESULT_GRACE_S", 0.0) + nested = impl / "stories" + nested.mkdir() + (nested / "spec-3-1-foo.md").write_text( + "---\nstatus: done\n---\n\n## Auto Run Result\n\nStatus: done\n", + encoding="utf-8", + ) + + assert adapter._result_json(_dev_handle(), _dev_spec(tmp_path), wait=True) is None + + (crumb,) = _breadcrumbs(adapter) + assert crumb["verdict"] == "no-artifact" + assert str(impl) in crumb["detail"] + assert "subdirectories are not searched" in crumb["detail"] + + def test_resultless_stop_breadcrumb_stories_pending(tmp_path, monkeypatch): adapter, _ = make_dev_adapter(tmp_path) monkeypatch.setattr(generic, "RESULT_GRACE_S", 0.0) @@ -5935,6 +5954,9 @@ def test_expected_spec_breadcrumb_names_the_pinned_path(tmp_path, monkeypatch): (crumb,) = _breadcrumbs(adapter) assert crumb["verdict"] == "no-artifact" assert str(ours) in crumb["detail"] + assert "at:" in crumb["detail"] + assert "directly under" not in crumb["detail"] + assert "subdirectories are not searched" not in crumb["detail"] assert "someone-elses" not in crumb["detail"]