opdev / opdev/agentic-status-report
M5: Synthesizer — skill invocation, audit chain, Slack delivery
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 2
- Avg merge
- 7d 51m
- Merged PRs (30d)
- 8
Description
Summary
Implement M5: end-to-end management report synthesis from confirmed ledger entries — skill invocation, audit chain persistence, and Slack channel delivery.
Design reference: docs/DESIGN.md §5.4 (Synthesizer), §7.3–7.4 (contracts), §8 (Skills integration)
Current state (partial implementation)
| Component | Status |
|---|---|
skills/weekly-status-synthesizer/SKILL.md |
Exists — rules ported from weekly_status-main/.claude/commands/format-status.md |
src/status/skills/synthesizer.py |
Stub — build_synthesis_input() + run_synthesizer() with dry-run fallback |
src/status/cli.py status report |
Exists — --dry-run defaults True; writes markdown to stdout or -o file |
report_run / report_entry tables |
Schema exists in models.py + Alembic — not written to yet |
| Slack report delivery | Not implemented |
| Skill publish | status skills publish --skill synthesizer works if SYNTHESIZER_SKILL_ID unset (creates new) |
Known bugs to fix in M5
In src/status/skills/synthesizer.py:
display_name=entry.person_id— should usePerson.display_namefrom DB joinflags=[]hardcoded — should include unacknowledgedflagrows for the week- No persistence to
report_run/report_entryafter skill returns
Tasks
1. Publish synthesizer skill
status skills publish --skill synthesizer
# Set SYNTHESIZER_SKILL_ID and pin SYNTHESIZER_SKILL_VERSION in .env / OpenShift Secret
Validate against fixtures built from confirmed ledger rows (create fixtures/synthesis-input-*.json from real confirmed data — scrub PII, gitignore if needed).
2. Complete build_synthesis_input()
- Join
Personfordisplay_name - Load unacknowledged flags:
Flagwhereweek_endingmatches andacknowledged = false - Include all
participationrows for the week (confirmed, expired, sent, send_failed, on_leave) - Only include
status_entrywhereis_current AND confirmed_at IS NOT NULL
Repo helpers exist in src/status/db/repo.py:
get_confirmed_entries_for_weekget_participation_for_week
3. Persist audit chain
After successful skill invocation, write:
report_run:
week_ending,prompt_version,model,generated_atoutput_uri— optional path or object store URI if saving markdown filedelivered_at— set when posted to Slack
report_entry:
- One row per cited entry:
(run_id, entry_id, section)wheresectioncomes from synthesizer metadata if available
New module suggested: src/status/db/report.py
def persist_report_run(session, week_ending, output: SynthesisOutput, *, model, prompt_version) -> ReportRun:
...
4. Wire status report CLI
- Change default
--dry-runto False whenSYNTHESIZER_SKILL_IDis set (keep--dry-runflag for testing) - Add
--deliverflag to post markdown toREPORT_CHANNEL_IDvia Slack Web API - Add
--persist(default true) to writereport_runrows
5. Slack delivery
Post synthesized markdown to private channel (REPORT_CHANNEL_ID):
- Use
slack_sdk.WebClient.chat_postMessagewithmrkdwntext - Long reports may need splitting (Slack 40k char limit) — split on section headers if needed
- Set
report_run.delivered_aton success
Optional: attach as snippet or upload file if formatting breaks in chat.
6. Synthesis validation
SynthesisOutput schema in src/status/skills/schemas.py — ensure Pydantic validates:
markdownnon-emptyweek_endingmatches input- Metadata fields:
sections_used,entries_cited,non_responders,asks
On validation failure: do not persist partial report; surface error to CLI.
7. Tests
tests/test_synthesizer.py— build input from fixture DB session (SQLite or mocked)- Test dry-run path unchanged
- Test
report_run+report_entryrows created on persist - Golden test: synthesis input JSON shape, not markdown prose
Synthesis rules (skill must enforce)
From design doc / SKILL.md:
- Sections: Partner Enablement, Certification / CI, Mindshare
- Format:
* **Name** - descriptionwith links on noun phrases - No raw Jira IDs in visible text
- Alphabetical within sections
- Non-responders explicit
- Every
askfrom ledger appears in report - Organize by epic/project, not by person
Acceptance criteria
-
status report --week 2026-08-14invokes skill when configured (not dry-run) -
report_runandreport_entrypopulated with audit chain -
--deliverposts toREPORT_CHANNEL_ID - Confirmed entries only; expired participation reflected in output metadata
- Tests pass:
pytest tests/test_synthesizer.py
Branch / PR
- Branch:
feat/m5-synthesizer - Base:
main - PR title:
feat(synthesizer): management report generation and delivery (M5)
Depends on
- M0–M3 on
main(ledger + confirm flow) - At least one week of confirmed entries in Postgres for integration testing
- M4 not strictly required but improves data quality before first real report
Out of scope (M6 / Phase 2)
- Monday 09:00 auto-expire unconfirmed (
participation.status = 'expired') — M6 - CronJob
lock-and-report - DOCX export / email (
weekly_status-maincommands)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with docs/DESIGN.md §5.4 and §7.3–7.4, then inspect src/status/skills/synthesizer.py, src/status/db/repo.py, models.py, and src/status/cli.py. Use tests/test_synthesizer.py and its fixture DB as the entry point; verify input filtering, validation, persistence, and Slack delivery paths. Done means pytest passes and the listed status report acceptance checks are met.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- postgresql, python
- Domain
- backend, cli, databases
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100