---
id: STATE-WP-0044
type: workplan
title: "RecentlyOnScope Domain Digest"
domain: infotech
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/<domain_slug>/`.
- 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.
