Skip to content

Commit 4939fab

Browse files
committed
intake: put the backlog in the Recent feed
The feed held 50 and could only find 10, because it read every bucket EXCEPT the largest: `draft/` is 150 prompts against a handful of registry rows, so skipping it meant Recent saw almost none of what had been happening. The paging added in #251 had nothing to page. Drafts now carry their own date (PyAutoMind grows a `Filed:` prompt header) and the census reads it back, so a filed prompt is an event like any other. That fills the feed: 45 filed, 3 parked, 1 issued, 1 found on today's Mind, and the `…` reveal finally does something. 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`. `_header_date` replaces the inline `Issued:` lookup: `Issued:` wins over `Filed:` when a prompt carries both, since an issued prompt keeps the `Filed:` it had as a draft and the later event is the one that dates the task. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L4HPWjv5rdzBAkKpfW1SbR
1 parent ad927eb commit 4939fab

3 files changed

Lines changed: 81 additions & 6 deletions

File tree

agents/conductors/intake/AGENTS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,11 @@ schema — light structure over free-form prose.
9090

9191
**Recent** is the one section laid out by *date* rather than by state: the 50
9292
newest events on the **work in hand** — issued, parked, filed — merged across
93-
the live buckets and sitting between the Backlog and the Epics. It *holds* 50
93+
every live bucket (the `draft/` backlog included, which is most of them:
94+
150 prompts against a handful of registry rows) and sitting between the Backlog
95+
and the Epics. Epic members stay out, as they do in every pick list on the
96+
page — they are worked in order through their epic, and a Recent row hands out
97+
a standalone `/start_dev`. It *holds* 50
9498
and *shows* 10 (`RECENT_MAX` / `RECENT_PAGE`): the table is a glance, not a
9599
log, so the rest is one tap away — a `` button on the Pages twin, and nested
96100
`<details>` on the markdown page, which GitHub renders where it strips the

agents/conductors/intake/_intake.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -337,14 +337,15 @@ def parse_header(text: str) -> dict:
337337
338338
Only scans the top of the file so a stray "Status:" deep in prose does not
339339
fire; first occurrence of each field wins. No YAML — the blessed convention.
340-
`Epic:`/`Phase:` are optional epic-membership fields (dashboard grouping)
341-
and `Issued:` is the prompt's own copy of its registry date; none are in
340+
`Epic:`/`Phase:` are optional epic-membership fields (dashboard grouping);
341+
`Filed:`/`Issued:` are the prompt's own date, keyed by the state it was in
342+
when that happened (PyAutoMind REFERENCE.md "Task dates"). None are in
342343
HEADER_FIELDS, so their absence is never header hygiene.
343344
"""
344345
fields = {}
345346
for line in text.splitlines()[:30]:
346347
m = re.match(r"(Type|Target|Difficulty|Autonomy|Priority|Status|"
347-
r"Issued|Epic|Phase):\s*(\S.*)",
348+
r"Issued|Filed|Epic|Phase):\s*(\S.*)",
348349
line.strip())
349350
if m:
350351
fields.setdefault(m.group(1).lower(), m.group(2).strip())
@@ -377,6 +378,18 @@ def _prefix_match(path: str, prefix: str) -> bool:
377378
"found", "completed", "shipped")
378379

379380

381+
def _header_date(header: dict) -> str:
382+
"""A prompt's own date from its `Issued:` / `Filed:` header, else ''.
383+
384+
`Issued:` wins when a prompt carries both — it is the later, more specific
385+
event, and an issued prompt keeps the `Filed:` it had as a draft."""
386+
for key in ("issued", "filed"):
387+
m = _ISO_DATE.search(header.get(key) or "")
388+
if m:
389+
return m.group(1)
390+
return ""
391+
392+
380393
def _entry_date(fields: dict) -> tuple:
381394
"""(date, event) for a registry entry, or ('', '') when it carries none."""
382395
for key in DATE_KEYS:
@@ -537,6 +550,16 @@ def recent_events(c: dict, limit: int = RECENT_MAX) -> list:
537550
events.append({"date": r["date"], "event": r.get("event") or "issued",
538551
"title": r["title"], "path": r["path"],
539552
"payload": f"/start_dev {r['path']}"})
553+
# The backlog is the LARGEST pool of work the Mind holds — 150 prompts
554+
# against a handful of live rows — so a feed that skipped it could see
555+
# almost none of what has been happening. Epic members stay out, as they do
556+
# in every pick list on the page: they are worked in order through their
557+
# epic, and a Recent row hands out a standalone `/start_dev`.
558+
for r in c.get("records") or []:
559+
if r.get("date") and not r.get("epic"):
560+
events.append({"date": r["date"], "event": "filed",
561+
"title": r["title"], "path": r["path"],
562+
"payload": f"/start_dev {r['path']}"})
540563
for key, verb in (("parked", "resume"), ("planned", "start")):
541564
for e in c.get(key) or []:
542565
if e.get("date"):
@@ -593,6 +616,9 @@ def census(mind: Path) -> dict:
593616
"status": header.get("status", "-"),
594617
"epic": header.get("epic", ""),
595618
"phase": phase,
619+
# `Filed:` normally; `Issued:` only on a prompt that has been
620+
# issued and moved back, which is still the later event.
621+
"date": _header_date(header),
596622
"header": header,
597623
"missing": missing,
598624
})
@@ -639,8 +665,7 @@ def _count(key):
639665
# claims it) dated rather than dropping it out of the recent feed.
640666
date, event = row.get("date", ""), row.get("event", "")
641667
if not date:
642-
m = _ISO_DATE.search(header.get("issued", ""))
643-
date, event = (m.group(1), "issued") if m else ("", "")
668+
date, event = _header_date(header), "issued"
644669
in_flight.append({
645670
"path": rel,
646671
"title": _title(text),

tests/test_intake_dashboard.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,3 +675,49 @@ def test_the_html_blurb_renders_its_code_spans(tmp_path):
675675
html = _intake.render_dashboard_html(_intake.census(_many(tmp_path, 80)))
676676
assert "<code>complete/index.md</code>" in html
677677
assert "`complete/index.md`" not in html
678+
679+
680+
# --------------------------------------------------------------------------- #
681+
# recent: the backlog is most of the work
682+
# --------------------------------------------------------------------------- #
683+
def test_a_dated_draft_is_in_the_feed(tmp_path):
684+
"""The backlog is the largest pool of work the Mind holds, so a feed that
685+
skipped it saw almost none of what has been happening."""
686+
mind = _mind(tmp_path, drafts={
687+
"feature/widgets/sprocket.md":
688+
_prompt("Sprocket work").replace("Status: formalised",
689+
"Status: formalised\nFiled: 2026-08-20")})
690+
rows = _intake.census(mind)["recent"]
691+
assert [(r["date"], r["event"], r["title"]) for r in rows] == [
692+
("2026-08-20", "filed", "Sprocket work")]
693+
assert rows[0]["payload"] == "/start_dev draft/feature/widgets/sprocket.md"
694+
695+
696+
def test_an_undated_draft_stays_out(tmp_path):
697+
mind = _mind(tmp_path, drafts={"feature/widgets/sprocket.md": _prompt("S")})
698+
assert _intake.census(mind)["recent"] == []
699+
700+
701+
def test_an_epic_member_is_not_offered_standalone_in_the_feed(tmp_path):
702+
"""Members are worked in order through their epic — every other pick list
703+
on the page excludes them, and a Recent row hands out a `/start_dev`."""
704+
member = _epic_prompt_body("Phase one", "jax-profiling", phase=1).replace(
705+
"Status: formalised", "Status: formalised\nFiled: 2026-08-20")
706+
mind = _mind(tmp_path, registries={"epics.md": _EPICS},
707+
drafts={"feature/widgets/phase_one.md": member,
708+
"feature/widgets/loose.md":
709+
_prompt("Loose end").replace(
710+
"Status: formalised",
711+
"Status: formalised\nFiled: 2026-08-21")})
712+
assert [r["title"] for r in _intake.census(mind)["recent"]] == ["Loose end"]
713+
714+
715+
def test_issued_beats_filed_on_a_prompt_carrying_both(tmp_path):
716+
"""An issued prompt keeps the `Filed:` it had as a draft; the later, more
717+
specific event is the one the feed reports."""
718+
body = _prompt("Sprocket").replace(
719+
"Status: formalised",
720+
"Status: formalised\nFiled: 2026-07-01\nIssued: 2026-08-19")
721+
rows = _intake.census(
722+
_mind(tmp_path, active={"sprocket.md": body}))["recent"]
723+
assert [(r["date"], r["event"]) for r in rows] == [("2026-08-19", "issued")]

0 commit comments

Comments
 (0)