feat(briefing): add deterministic Morning Brief v1 - #15
Conversation
🔎 Lint report:
|
| Rule | Count |
|---|---|
invalid-assignment |
1 |
unresolved-import |
1 |
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `_credits_session_start_micros` of type `int`
tests/test_morning_brief_v1.py:8: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
✅ Fixed issues (2):
| Rule | Count |
|---|---|
unresolved-attribute |
2 |
First entries
run_agent.py:2920: [unresolved-attribute] unresolved-attribute: Object of type `Self@get_credits_spent_micros` has no attribute `_credits_session_start_micros`
tests/run_agent/test_credits_notices_toggle.py:76: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_credits_session_start_micros` on type `AIAgent`
Unchanged: 5559 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 89340d02fd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| def _time_key(value: Any) -> str: | ||
| text = _text(value, "") | ||
| try: | ||
| return datetime.fromisoformat(text.replace("Z", "+00:00")).isoformat() |
There was a problem hiding this comment.
Normalize completion times before sorting wins
When two completion_time values use different offsets, _time_key returns strings that preserve their local offsets, so the reverse sort compares wall-clock text rather than instants. For example, 2026-07-11T09:00:00+00:00 sorts ahead of 2026-07-11T05:30:00-04:00 even though the latter is 30 minutes newer, violating the documented “wins newest first” contract for snapshots aggregated from sources in different time zones.
Useful? React with 👍 / 👎.
| "- **Ready to merge:** " | ||
| + (", ".join(report["github"]["ready_to_merge"]) or "None"), |
There was a problem hiding this comment.
Normalize GitHub lists before joining
If a JSON snapshot has a missing/non-string entry such as null in github.ready_to_merge, validation only checks that the field is a list, and this join raises TypeError. That escapes the invalid-input handler as a traceback/exit 1 instead of rendering UNKNOWN or returning the stable status 2, so a single bad scalar in one GitHub list breaks the default brief.
Useful? React with 👍 / 👎.
Status
SCOPED PASS / REPOSITORY WARN
Draft only. Do not merge yet.
Summary
Adds the canonical deterministic, fixture-backed, local, read-only Hermes Morning Brief v1.
Focused diff
This PR contains one focused commit and 14 Morning Brief files only:
scripts/morning_brief_v1.pytests/test_morning_brief_v1.pytests/fixtures/morning_brief/docs/morning-brief-v1*No main-branch mutation, runtime change, scheduling, notifications, networking, or production configuration changes.
Scoped validation — PASS
Deterministic artifact hashes exactly match the committed examples:
Secret scan before commit:
Repository-wide validation — WARN
The following blockers are pre-existing, unrelated, and explicitly out of scope for this PR:
ruff format --check .reports legacy formatting drift, including.plans/streaming-support.md.pytest -qfails during collection because optionalacpdependencies are unavailable (ModuleNotFoundError: No module named 'acp').ty checkpanics in existingtools/checkpoint_manager.pywithexecute: too many cycle iterations;tyidentifies this as a checker bug (version0.0.21).# noqadirective warning atrun_agent.py:94.No attempt was made to repair optional dependencies, legacy formatting drift, the
typanic, or the existing lint warning.Safety boundaries
Review gate
Review the scoped implementation and separate v1.1 design packet before considering merge. v1.1 is design-only and is not implemented in this PR.