Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion agents/conductors/intake/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ schema — light structure over free-form prose.

**Recent** is the one section laid out by *date* rather than by state: the 50
newest events on the **work in hand** — issued, parked, filed — merged across
the live buckets and sitting between the Backlog and the Epics. It *holds* 50
every live bucket (the `draft/` backlog included, which is most of them:
150 prompts against a handful of registry rows) and sitting between the Backlog
and the Epics. Epic members stay out, as they do in every pick list on the
page — they are worked in order through their epic, and a Recent row hands out
a standalone `/start_dev`. It *holds* 50
and *shows* 10 (`RECENT_MAX` / `RECENT_PAGE`): the table is a glance, not a
log, so the rest is one tap away — a `…` button on the Pages twin, and nested
`<details>` on the markdown page, which GitHub renders where it strips the
Expand Down
35 changes: 30 additions & 5 deletions agents/conductors/intake/_intake.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,14 +337,15 @@ def parse_header(text: str) -> dict:

Only scans the top of the file so a stray "Status:" deep in prose does not
fire; first occurrence of each field wins. No YAML — the blessed convention.
`Epic:`/`Phase:` are optional epic-membership fields (dashboard grouping)
and `Issued:` is the prompt's own copy of its registry date; none are in
`Epic:`/`Phase:` are optional epic-membership fields (dashboard grouping);
`Filed:`/`Issued:` are the prompt's own date, keyed by the state it was in
when that happened (PyAutoMind REFERENCE.md "Task dates"). None are in
HEADER_FIELDS, so their absence is never header hygiene.
"""
fields = {}
for line in text.splitlines()[:30]:
m = re.match(r"(Type|Target|Difficulty|Autonomy|Priority|Status|"
r"Issued|Epic|Phase):\s*(\S.*)",
r"Issued|Filed|Epic|Phase):\s*(\S.*)",
line.strip())
if m:
fields.setdefault(m.group(1).lower(), m.group(2).strip())
Expand Down Expand Up @@ -377,6 +378,18 @@ def _prefix_match(path: str, prefix: str) -> bool:
"found", "completed", "shipped")


def _header_date(header: dict) -> str:
"""A prompt's own date from its `Issued:` / `Filed:` header, else ''.

`Issued:` wins when a prompt carries both — it is the later, more specific
event, and an issued prompt keeps the `Filed:` it had as a draft."""
for key in ("issued", "filed"):
m = _ISO_DATE.search(header.get(key) or "")
if m:
return m.group(1)
return ""


def _entry_date(fields: dict) -> tuple:
"""(date, event) for a registry entry, or ('', '') when it carries none."""
for key in DATE_KEYS:
Expand Down Expand Up @@ -537,6 +550,16 @@ def recent_events(c: dict, limit: int = RECENT_MAX) -> list:
events.append({"date": r["date"], "event": r.get("event") or "issued",
"title": r["title"], "path": r["path"],
"payload": f"/start_dev {r['path']}"})
# The backlog is the LARGEST pool of work the Mind holds — 150 prompts
# against a handful of live rows — so a feed that skipped it could see
# almost none of what has been happening. Epic members stay out, as they do
# in every pick list on the page: they are worked in order through their
# epic, and a Recent row hands out a standalone `/start_dev`.
for r in c.get("records") or []:
if r.get("date") and not r.get("epic"):
events.append({"date": r["date"], "event": "filed",
"title": r["title"], "path": r["path"],
"payload": f"/start_dev {r['path']}"})
for key, verb in (("parked", "resume"), ("planned", "start")):
for e in c.get(key) or []:
if e.get("date"):
Expand Down Expand Up @@ -593,6 +616,9 @@ def census(mind: Path) -> dict:
"status": header.get("status", "-"),
"epic": header.get("epic", ""),
"phase": phase,
# `Filed:` normally; `Issued:` only on a prompt that has been
# issued and moved back, which is still the later event.
"date": _header_date(header),
"header": header,
"missing": missing,
})
Expand Down Expand Up @@ -639,8 +665,7 @@ def _count(key):
# claims it) dated rather than dropping it out of the recent feed.
date, event = row.get("date", ""), row.get("event", "")
if not date:
m = _ISO_DATE.search(header.get("issued", ""))
date, event = (m.group(1), "issued") if m else ("", "")
date, event = _header_date(header), "issued"
in_flight.append({
"path": rel,
"title": _title(text),
Expand Down
46 changes: 46 additions & 0 deletions tests/test_intake_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -675,3 +675,49 @@ def test_the_html_blurb_renders_its_code_spans(tmp_path):
html = _intake.render_dashboard_html(_intake.census(_many(tmp_path, 80)))
assert "<code>complete/index.md</code>" in html
assert "`complete/index.md`" not in html


# --------------------------------------------------------------------------- #
# recent: the backlog is most of the work
# --------------------------------------------------------------------------- #
def test_a_dated_draft_is_in_the_feed(tmp_path):
"""The backlog is the largest pool of work the Mind holds, so a feed that
skipped it saw almost none of what has been happening."""
mind = _mind(tmp_path, drafts={
"feature/widgets/sprocket.md":
_prompt("Sprocket work").replace("Status: formalised",
"Status: formalised\nFiled: 2026-08-20")})
rows = _intake.census(mind)["recent"]
assert [(r["date"], r["event"], r["title"]) for r in rows] == [
("2026-08-20", "filed", "Sprocket work")]
assert rows[0]["payload"] == "/start_dev draft/feature/widgets/sprocket.md"


def test_an_undated_draft_stays_out(tmp_path):
mind = _mind(tmp_path, drafts={"feature/widgets/sprocket.md": _prompt("S")})
assert _intake.census(mind)["recent"] == []


def test_an_epic_member_is_not_offered_standalone_in_the_feed(tmp_path):
"""Members are worked in order through their epic — every other pick list
on the page excludes them, and a Recent row hands out a `/start_dev`."""
member = _epic_prompt_body("Phase one", "jax-profiling", phase=1).replace(
"Status: formalised", "Status: formalised\nFiled: 2026-08-20")
mind = _mind(tmp_path, registries={"epics.md": _EPICS},
drafts={"feature/widgets/phase_one.md": member,
"feature/widgets/loose.md":
_prompt("Loose end").replace(
"Status: formalised",
"Status: formalised\nFiled: 2026-08-21")})
assert [r["title"] for r in _intake.census(mind)["recent"]] == ["Loose end"]


def test_issued_beats_filed_on_a_prompt_carrying_both(tmp_path):
"""An issued prompt keeps the `Filed:` it had as a draft; the later, more
specific event is the one the feed reports."""
body = _prompt("Sprocket").replace(
"Status: formalised",
"Status: formalised\nFiled: 2026-07-01\nIssued: 2026-08-19")
rows = _intake.census(
_mind(tmp_path, active={"sprocket.md": body}))["recent"]
assert [(r["date"], r["event"]) for r in rows] == [("2026-08-19", "issued")]
Loading