--- id: STATE-WP-0044 type: workplan title: "RecentlyOnScope Domain Digest" domain: custodian repo: state-hub status: finished owner: codex topic_slug: custodian created: "2026-05-22" updated: "2026-05-22" state_hub_workstream_id: "ffefe4b2-e162-44c7-8658-5d8d9e27ad9c" --- # RecentlyOnScope Domain Digest ## Summary Add a file-backed RecentlyOnScope digest that answers: "What happened in this domain recently?" The digest is generated as Markdown from a deterministic Markdown template, with a time range parameter defaulting to one hour. Generated reports are collected in a State Hub report directory and are browsable from a new Domains navigation subentry. This should reuse MarkiTect template-rendering capabilities instead of adding a new ad hoc templating language. The local tool surface currently provides `markitect template render` and the Python API `markitect_tool.template.render_template`. ## Current Findings - Domains are first-class records with topics and repos. Domain-scoped work can be resolved through `Domain -> Topic -> Workstream -> Task`. - `GET /progress/` already supports `topic_id`, `workstream_id`, `task_id`, `event_type`, and `since` filters, making progress events the first digest source. - Decisions, workstreams, and tasks have timestamp fields, but their existing list endpoints do not expose a domain/time-window digest view. - Agent messages are not currently domain-linked. They should only enter the first digest when they can be tied to a topic, workstream, task, or explicit domain reference. - The dashboard currently exposes `Domains` as a top-level page in `dashboard/observablehq.config.js`. A subentry will require turning it into a collapsible navigation group or adding a nested Domains section. - No State Hub report directory exists yet. The work should create a clear generated-artifact location, proposed as `reports/recently-on-scope/` inside this repo or the configured runtime data directory. ## Out of Scope - LLM summarization of the digest. This work is deterministic collection and Markdown rendering. - Scheduled/background generation. This work provides on-demand generation and browsing hooks only. - Replacing the existing progress, task, decision, or workstream APIs. - Backfilling historic reports before the feature exists. ## T01 - Define Digest Contract and Report Layout ```task id: STATE-WP-0044-T01 status: done priority: high state_hub_task_id: "0b8d0211-1d66-4808-b078-2d7c23af886a" ``` Define the input, output, and file layout for a RecentlyOnScope digest before implementation. Implementation notes: - Required input: `domain_slug`. - Optional input: `range`, defaulting to `1h`. - Optional exact-window inputs: `since` and `until`; when supplied, they should override or constrain `range` predictably. - Accept simple duration values such as `15m`, `1h`, `6h`, and `1d`; reject ambiguous values with a 422 response or CLI error. - Normalize all comparisons and generated filenames to UTC. - Store the tracked template at `templates/recently-on-scope/domain-digest.md`. - Store generated reports under a configurable report root, defaulting to `reports/recently-on-scope//`. - Name reports with enough information to sort and de-duplicate, for example `20260522T120000Z--1h.md` or `20260522T110000Z--20260522T120000Z.md`. - Include frontmatter in each generated Markdown report with `domain_slug`, `range`, `since`, `until`, `generated_at`, `template_version`, and source counts. Done when the report contract is documented and has tests for duration parsing, default range behavior, and output path generation. ## T02 - Build Domain Activity Collector ```task id: STATE-WP-0044-T02 status: done priority: high state_hub_task_id: "4d18fc40-dd28-417f-a2bf-538165eaa1e7" ``` Create a domain-scoped collector that turns recent State Hub records into a stable data object for template rendering. Implementation notes: - Add a focused service module, for example `api/services/recently_on_scope.py`. - Resolve `domain_slug` to the domain id, associated topic ids, active repos, workstreams, and tasks. - Collect `ProgressEvent` rows for the domain topic ids and workstream/task ids in the requested time window. - Collect decisions created, updated, or resolved in the time window for domain topics and workstreams. - Collect workstreams and tasks updated in the time window, including status changes where that can be inferred from current records or progress events. - Include open human-intervention items in a separate "still needs attention" section when they belong to the domain, even if they were created before the requested window. - Keep output deterministic: sort by timestamp descending within sections, and include stable ids/links where available. - Do not infer domain ownership for messages unless a message is explicitly linked to a domain, topic, workstream, task, or digest-generation request. Done when the collector returns a deterministic plain-Python data structure covering progress, decisions, workstreams, tasks, repos, and attention items for one domain and time window. ## T03 - Reuse MarkiTect for Markdown Rendering ```task id: STATE-WP-0044-T03 status: done priority: high state_hub_task_id: "b3c5a238-3559-442b-a5ac-6f9aae802bac" ``` Render the digest with MarkiTect rather than custom string substitution. Implementation notes: - Add a thin adapter, for example `api/services/markitect_templates.py`, that imports `markitect_tool.template.render_template` when available. - Keep a subprocess fallback to `markitect template render` for environments where the CLI is installed but the Python package is not importable. - Fail clearly if neither MarkiTect path is available; do not silently switch to a new template syntax. - Validate the template before generation by checking required variables. - Define a template data contract with keys such as `domain`, `window`, `generated_at`, `progress_events`, `decisions`, `workstreams`, `tasks`, `repos`, and `attention_items`. - Keep the template Markdown readable on its own, with no dashboard-specific markup. - Persist the rendered Markdown atomically so partial reports are not listed by the dashboard. Done when a report can be rendered from the template using MarkiTect in tests and written to the configured report directory. ## T04 - Provide Generation and Listing Mechanisms ```task id: STATE-WP-0044-T04 status: done priority: high state_hub_task_id: "e54ddc1e-75a5-44e5-b452-d8db58cce901" ``` Expose a practical mechanism to generate, list, and read RecentlyOnScope reports. Implementation notes: - Add an API route group under Domains, for example: - `POST /domains/{slug}/recently-on-scope` to generate a report. - `GET /domains/{slug}/recently-on-scope` to list generated reports. - `GET /domains/{slug}/recently-on-scope/{report_id}` to return Markdown. - Return report metadata from generation and list calls: id, domain, range, since, until, generated_at, path, and source counts. - Return Markdown with `text/markdown` where appropriate. - Add a CLI script or make target for operator use, for example `python -m scripts.recently_on_scope --domain custodian --range 1h`. - Make the report root configurable with an environment variable such as `STATE_HUB_REPORT_DIR`, while preserving the repo-local default. - Avoid requiring dashboard access for generation; the CLI/API should be usable by agents and operators. Done when operators can generate a digest from the command line or API, list existing reports, and read the Markdown contents. ## T05 - Add Domains Navigation and Dashboard View ```task id: STATE-WP-0044-T05 status: done priority: medium state_hub_task_id: "dedad1d0-4afd-490a-ab59-a2ad348de5d2" ``` Make the reports accessible from a subentry under Domains in the State Hub dashboard navigation. Implementation notes: - Update `dashboard/observablehq.config.js` so `Domains` can expose a child page without hiding the existing `/domains` overview. - Add a page such as `dashboard/src/domains/recently-on-scope.md`. - Provide domain selection, a time-range control defaulting to `1h`, and a generate action backed by the new API. - Show the generated report list grouped by domain and sorted by `generated_at` descending. - Render or preview Markdown safely in the dashboard, or link to the raw `text/markdown` endpoint when full rendering is out of scope for the first pass. - Keep the view operational and compact: no landing page, no marketing copy, and no generated-output text that overlaps on small screens. - Add reference docs at `dashboard/src/docs/domains.md` or a dedicated docs page explaining where reports are stored and what the range parameter means. Done when the dashboard navigation has a Domains subentry for RecentlyOnScope, reports can be generated/browsed from it, and raw Markdown is accessible for each entry. ## T06 - Verification, Docs, and Operational Notes ```task id: STATE-WP-0044-T06 status: done priority: medium state_hub_task_id: "cecfb226-435b-429e-89fc-0da743a229ce" ``` Cover the feature with focused tests and operator documentation. Implementation notes: - Add unit tests for duration parsing, collector filtering, MarkiTect adapter behavior, report naming, and report listing. - Add router tests for generation, list, missing domain, invalid range, and missing MarkiTect failure modes. - Add dashboard data/API smoke tests where existing dashboard test patterns make this practical. - Document the report directory, retention expectations, and whether generated reports are committed or treated as runtime artifacts. - If generated reports should stay out of Git, add a targeted `.gitignore` entry while keeping the template tracked. - Verify with `python3 -m pytest` and dashboard build/test commands already used by this repo. - After the workplan file is synced, run `make fix-consistency REPO=state-hub` from `~/state-hub`. Done when tests pass, docs explain the operator workflow, and generated reports have a clear retention and Git-tracking policy.