Expose strict brief rendering without implicit Git operations

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a15374-f59f-7a31-86d2-d23b5d2ed181
This commit is contained in:
tegwick 2026-10-19 13:30:59 +02:00
parent 200cbd0a61
commit 09803dcc31
9 changed files with 199 additions and 26 deletions

View file

@ -2847,8 +2847,9 @@ def _summarise_inbox_message(msg: dict[str, Any], *, now: datetime) -> dict[str,
}
def collect_inbox_hygiene(api_base: str, repo_slug: str) -> dict[str, Any]:
messages = _api_get(
def collect_inbox_hygiene(api_base: str, repo_slug: str, *, reader=None) -> dict[str, Any]:
reader = reader or _api_get
messages = reader(
api_base,
"/messages",
{"to_agent": repo_slug, "unread_only": True, "limit": 100},
@ -3392,7 +3393,19 @@ def _commit_working_memory_notes(repo_slug: str, repo_path: str) -> bool:
return False
def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str) -> bool:
def _strict_brief_get(api_base: str, path: str, params=None):
"""Never turn an incomplete read-model snapshot into an empty brief."""
value = _api_get(api_base, path, params, return_error=True)
singular = path.startswith(("/repos/", "/topics/"))
valid = (isinstance(value, dict) and bool(value) and "_error" not in value
if singular else isinstance(value, list) and all(isinstance(row, dict) for row in value))
if not valid:
raise ValueError("brief read model unavailable or malformed at " + path)
return value
def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str, *,
commit: bool = True, strict: bool = False, check: bool = False) -> bool:
"""Generate .custodian-brief.md at the repo root and git-commit if changed.
The brief gives any agent — including subagents without MCP access and
@ -3402,7 +3415,8 @@ def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str) -> boo
import datetime as _dt
from datetime import timezone as _tz
repo = _api_get(api_base, f"/repos/{repo_slug}")
reader = _strict_brief_get if strict else _api_get
repo = reader(api_base, f"/repos/{repo_slug}")
if not repo:
return False
@ -3413,21 +3427,21 @@ def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str) -> boo
# lookup only for compatibility with older API responses that omitted it.
workstreams: list[dict] = []
for status in OPEN_WORKSTREAM_STATUSES:
rows = _api_get(api_base, "/workplans", {"repo_id": repo_id, "status": status}) or []
rows = reader(api_base, "/workplans", {"repo_id": repo_id, "status": status}) or []
if isinstance(rows, list):
workstreams.extend(rows)
_ws_for_domain = workstreams if workstreams else []
if not _ws_for_domain:
all_ws = _api_get(api_base, "/workplans", {"repo_id": repo_id}) or []
all_ws = reader(api_base, "/workplans", {"repo_id": repo_id}) or []
_ws_for_domain = all_ws if isinstance(all_ws, list) else []
if not domain_slug and _ws_for_domain:
topic = _api_get(api_base, f"/topics/{_ws_for_domain[0].get('topic_id', '')}")
topic = reader(api_base, f"/topics/{_ws_for_domain[0].get('topic_id', '')}")
if topic:
domain_slug = topic.get("domain_slug", "")
# Active repo goal (first active one if multiple)
goal_text = ""
goals = _api_get(api_base, "/repo-goals", {"repo_slug": repo_slug}) or []
goals = reader(api_base, "/repo-goals", {"repo_slug": repo_slug}) or []
if isinstance(goals, list):
active_goals = [g for g in goals if g.get("status") == "active"]
if active_goals:
@ -3455,7 +3469,7 @@ def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str) -> boo
for ws in workstreams:
ws_title = ws.get("title", ws.get("slug", "?"))
ws_id = ws["id"]
tasks = _api_get(api_base, "/tasks", {"workplan_id": ws_id}) or []
tasks = reader(api_base, "/tasks", {"workplan_id": ws_id}) or []
if not isinstance(tasks, list):
tasks = []
@ -3502,7 +3516,8 @@ def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str) -> boo
else:
lines += ["## Active Workstreams", "", "*(none — repo may need first-session setup)*"]
hygiene = collect_inbox_hygiene(api_base, repo_slug)
hygiene = (collect_inbox_hygiene(api_base, repo_slug, reader=reader) if strict
else collect_inbox_hygiene(api_base, repo_slug))
if hygiene["stale_unread_count"] or hygiene["missing_thread"] or hygiene["work_requests_unpromoted"]:
lines += ["", "## Inbox Hygiene", ""]
if hygiene["stale_unread_count"]:
@ -3539,7 +3554,7 @@ def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str) -> boo
counterpart = parse_blocked_on(blocked_on)
if not counterpart:
continue
messages = _api_get(
messages = reader(
api_base,
"/messages",
{
@ -3621,14 +3636,19 @@ def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str) -> boo
if _strip_ts(content) == _strip_ts(existing):
return False # no meaningful change
if brief_path.is_symlink():
raise ValueError("refuse redirected brief")
if check:
raise ValueError("brief differs from current read model")
brief_path.write_text(content, encoding="utf-8")
# Commit the brief so remote workers can pull it
_git_commit_writeback(
repo_path,
brief_path,
[f"update .custodian-brief.md for {repo_slug}"],
)
if commit:
_git_commit_writeback(
repo_path,
brief_path,
[f"update .custodian-brief.md for {repo_slug}"],
)
return True

View file

@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""Render a current State Hub orientation brief without Git operations or hub writes."""
import argparse
import json
from pathlib import Path
import re
from consistency_check import _write_custodian_brief
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--repo-path', type=Path, required=True)
parser.add_argument('--repo-slug', required=True)
parser.add_argument('--api-base', default='http://127.0.0.1:8000')
parser.add_argument('--check', action='store_true')
args = parser.parse_args()
try:
if not re.fullmatch(r'[a-z0-9]+(?:-[a-z0-9]+)*', args.repo_slug):
raise ValueError('canonical repository slug required')
if not args.repo_path.is_dir():
raise ValueError('repository path must exist')
if (args.repo_path / '.custodian-brief.md').is_symlink():
raise ValueError('refuse redirected brief')
changed = _write_custodian_brief(args.api_base, args.repo_slug, str(args.repo_path),
commit=False, strict=True, check=args.check)
except (OSError, ValueError, KeyError, TypeError) as exc:
parser.exit(1, f'Brief generation refused: {exc}\n')
print(json.dumps({'repo': args.repo_slug, 'status': 'updated' if changed else 'current',
'source': 'state-hub-read-model', 'git_operations': False}))
if __name__ == '__main__':
main()