A programmatic replacement for the MOSERS spreadsheet workflow used to evaluate counterparty risk and produce the monthly Counterparty Exposure reporting package (Excel workbooks + PowerPoint).
- Operators (non-technical): run the monthly process via a button-driven Runner (Excel or a simple Windows app) and deliver the output files. Operators do not need repo access.
- Maintainers: develop and maintain the pipeline in this repository, primarily through agent-driven issues and PRs.
- Updated historical Excel workbooks (time series inputs for charts)
- Updated monthly PowerPoint (screenshots replaced + chart links refreshed)
- A run folder with a manifest (inputs, hashes, warnings, summaries). The manifest carries a top-level
manifest_schema_version(currently"counter-risk-manifest/v1") so the contract can evolve safely, and aprovenanceblock tying the run to the exact code that produced it:tool,tool_version,git_sha(best-effort;nulloutside a git checkout),python_version, andplatform. - Registry-backed counterparty and clearing-house name matching (see docs/name_registry.md)
- A
DATA_QUALITY_SUMMARY.txtand manifestdata_qualityobject for green/yellow/red operator review (see docs/data_quality.md) - A
concentration_metrics.csvwith Top 5/Top 10 share and HHI per(variant, segment)(see docs/concentration_metrics.md) - Optional
risk_rankings.csvandrisk_top_movers.csvrisk proxy outputs when source columns exist (see docs/risk_proxy_outputs.md) - A
limit_breaches.csvwhen configured exposure limits are breached (see docs/limit_monitoring.md) - Optional βdistributionβ deliverables (static PPT/PDF) that do not prompt for link refresh
Outputs are registered per run via output_generators in YAML config files. Each entry has:
name: unique identifier for the generatorregistration: eitherbuiltin:<id>or<python_module>:<symbol>stage: one ofhistorical,ppt_master,ppt_refresh,ppt_post_distributionenabled:true/false
Example:
output_generators:
- name: historical_workbook
registration: builtin:historical_workbook
stage: historical
enabled: true
- name: ppt_screenshot
registration: builtin:ppt_screenshot
stage: ppt_master
enabled: true
- name: ppt_link_refresh
registration: builtin:ppt_link_refresh
stage: ppt_refresh
enabled: false
- name: custom_exhibit
registration: my_package.outputs:CustomExhibitGenerator
stage: ppt_post_distribution
enabled: trueSetting enabled: false cleanly skips that generator for the run.
Repo Cash loading supports layered source selection and audit-friendly overrides:
cash_overrides_<as_of_date>.csv(or explicitcash_overrides_csv)- Structured source (
cash_source_type: csv|xlsxwithcash_source_path) - PDF source (
cash_source_type: pdfordaily_holdings_pdf)
Optional config keys:
cash_source_type:csv,xlsx,pdf, ornonecash_source_path: explicit source file pathcash_overrides_csv: explicit overrides CSV pathrequired_repo_counterparties: counterparties that must be present in the loaded mapcash_total_min/cash_total_max: expected total-range checks
Source choice and overrides are emitted in run warnings, which are persisted in manifest.json.
- Project agent guide: AGENTS.md
- Consumer repo workflow rules: CLAUDE.md
- How to use labels/keepalive/autopilot: WORKFLOW_USER_GUIDE.md
- Issue formatting standard: docs/AGENT_ISSUE_FORMAT.md
- CI/Workflows integration guide: docs/CI_SYSTEM_GUIDE.md
- Keepalive troubleshooting: docs/KEEPALIVE_TROUBLESHOOTING.md
- Consumer setup checklist: docs/SETUP_CHECKLIST.md
- GUI runner usage: docs/gui_runner.md
Use docs/name_registry.md as the maintainer runbook. The short loop is:
- Run the mapping diff report before editing the registry.
- Edit
config/name_registry.ymlusing stablecanonical_keyvalues, workbook/report-safedisplay_namevalues, and aliases for source spelling variants. - Use
series_included.by_segmentonly for intentional segment-level exclusions. - Re-run the focused registry tests and confirm the diff report resolves the
intended names into
NAME_RESOLUTIONS.
This repo is integrated with the central stranske/Workflows library.
Typical maintainer loop:
- Write/format an issue using the repo issue format.
- Label the issue to trigger agent workflows (for example,
agents:formatthenagent:codex). - Keepalive iterates on the PR until tasks and acceptance criteria are complete.
If a change requires editing synced workflow files, do it in stranske/Workflows first and then sync.
Autopilot smoke tests are enabled to validate basic keepalive and automation flow behavior.
Use these maintainer commands from the repository root:
make lintrunsruff check src/ tests/make formatrunsruff format src/ tests/make testrunspytest -m "not slow"
manifest.json includes an evidence object on each top_exposures entry.
The source_id uses the same key namespace as input_hashes (for example,
mosers_all_programs_xlsx), and the sheet and row fields point to the
workbook location used to produce the exposure fact. Evidence remains local to
the manifest and is not exported in LangSmith fleet records.
Some tests are too expensive for PR feedback, so they are tagged with the
slow pytest marker and excluded from PR Gate. They still run in Main CI
after merges to main.
| Where it runs | Marker filter | Typical duration |
|---|---|---|
PR Gate (pr-00-gate.yml) |
not release and not slow |
~4 min |
Main CI (ci.yml) |
(all tests) | ~12-15 min |
Release E2E (release-e2e.yml) |
release |
nightly / on label |
What counts as "slow":
tests/pipeline/test_run_pipeline.pyβ everytest_run_pipeline_*test callsrun_pipeline()with real Excel fixtures (100-170 s each on CI). Auto-marked viatests/pipeline/conftest.py.tests/spec/test_macro_spec_fixtures.pyβ session-scoped fixture parses three large NISA workbooks (~85 s one-time cost). Module-levelpytestmark = pytest.mark.slow.
When adding new tests that parse real workbooks or run full pipeline
orchestration, mark them @pytest.mark.slow (or add them to the conftest
hook) so the Gate stays fast.
The run-context chat assistant now uses LangChain-backed providers (instead of stubs) for
openai and anthropic.
- Ensure runtime dependencies are installed before using chat providers
(for example
pip install -r requirements.txtorpip install -e .). - Copy
.env.exampleto a local.env(or set variables in your runtime environment). - Configure at least one credential path:
GITHUB_TOKEN(used for OpenAI-compatible GitHub Models path)OPENAI_API_KEY(direct OpenAI path)CLAUDE_API_STRANSKE(Anthropic path)
- Missing package failures are surfaced with explicit install guidance
(
langchain-openaiorlangchain-anthropic) before provider calls execute. - The deterministic local stub provider is disabled by default and only available when
COUNTER_RISK_CHAT_OFFLINE_MODE=1(intended for offline tests/dev only). - Optional routing/model overrides are also documented in
.env.example(LANGCHAIN_PROVIDER,LANGCHAIN_MODEL, slot overrides, timeout/retry settings). - Chat logging mode defaults to
transcript; override withCOUNTER_RISK_CHAT_LOG_MODE(transcript,full,off). - See docs/chat_logging.md for mode behavior, payload fields, and LangSmith trace linkage.
- See docs/langsmith_fleet.md for the
dashboard-safe
langsmith-fleet.ndjsonartifact emitted by monthly risk runs.
The production workflow run path is:
counter-risk run --config <workflow.yml> --as-of-date YYYY-MM-DD --output-dir <runs/<timestamp>>
Examples:
python -m counter_risk.cli run --config config/all_programs.yml --as-of-date 2025-12-31 --output-dir runs/2025-12-31_000000python -m counter_risk.cli run --discover --config config/all_programs.yml --as-of-date 2025-12-31 --output-dir runs/2025-12-31_000000
Optional runtime overrides:
--strict-policy warn|strict(reconciliation fail policy override)--export-pdf/--no-export-pdf--formatting-profile <name>(applies supported numeric formatting policies to output writers)--settings <path/to/runner-settings.json>(Runner.xlsm / GUI serialized settings payload)
Supported formatting profile values:
default- preserve template/default number formats.currency- USD-style currency formatting for historical notional outputs.accounting- accounting-style currency formatting for historical notional outputs.plain- non-currency numeric format with two decimals.
Current profile application scope:
- Historical workbook append rows written by the pipeline.
- CPRS-CH/CPRS-FCM static table PNG renderers when invoked with
formatting_profile.
Legacy packaging path is still available for release validation only:
counter-risk run --fixture-replay --config config/fixture_replay.yml --output-dir <path>
For macro-restricted environments, operators can launch the Tkinter runner:
counter-risk guicounter-risk gui --headless --as-of-date 2025-12-31 --mode all(CI/smoke)
- π Python 3.11+ - Modern Python with type hints
- π§ Ruff - Fast Python linting and formatting
- π MyPy - Strict type checking
- π§ͺ Pytest - Testing with 80% coverage requirement
- π€ CLI Codex Automation - Gate-triggered keepalive for automated development
- π Dual Checkout Pattern - Consumer repo + centralized Workflows scripts
This repository uses reusable workflows from stranske/Workflows:
| Workflow | Purpose | Trigger |
|---|---|---|
| Gate | PR validation (CI, lint, tests) | Pull request |
| CI | Push-to-main continuous integration | Push to main |
| Autofix | Automatic lint/format fixes | Label: autofix |
| Workflow | Purpose | Trigger |
|---|---|---|
| Keepalive Loop | Runs Codex CLI after Gate passes | Gate completion, PR label |
| PR Meta | Updates PR status summaries | PR events |
| Issue Intake | Creates PRs from labeled issues | Issue labeled |
| Guard | Security checks for agent execution | Before agent runs |
| Bot Comment Handler | Processes @codex commands | Issue comments |
| Autofix Loop | Autofix integration with keepalive | Autofix + agent label |
Note: agents-orchestrator.yml is legacy and can be removed. The current architecture uses agents-keepalive-loop.yml which integrates with the Gate workflow for event-driven triggering.
This template uses the Gate-triggered keepalive architecture:
- Create Issue with structured Scope/Tasks/Acceptance sections
- Label Issue with
agent:codex - Issue Intake creates PR from issue
- Gate Workflow runs CI validation
- Keepalive Loop triggers after Gate completion
- Evaluates eligibility (unchecked tasks, no pause labels)
- Runs CLI Codex via
reusable-codex-run.yml - Codex implements changes and pushes commits
- Gate Runs Again β loop continues
- Completion when all acceptance criteria checked
- Activation: PR must have
agent:codexlabel, Gate success, unchecked tasks - Task Tracking: Agent updates checkboxes in PR body after completing work
- Progress Detection: Automatic checkbox reconciliation via session analysis
- Failure Handling: After 3 failures, adds
needs-humanlabel and pauses - Concurrency: One keepalive run per PR (configurable via
agents:max-parallel:N)
| Label | Effect |
|---|---|
agent:codex |
Enables Codex automation |
agents:pause |
Halts all agent activity |
needs-human |
Auto-added after failures, blocks keepalive |
agents:max-parallel:N |
Override concurrent run limit (default: 1) |
Add issues to Issues.txt using the structured format, then trigger the intake workflow:
1) Issue title here
Labels: agent:codex, enhancement
## Scope
Explanation of what needs to be done and why.
## Tasks
- [ ] Task 1
- [ ] Task 2
- [ ] Task 3
## Acceptance Criteria
- [ ] All tests pass
- [ ] Code is documented
- [ ] Coverage β₯80%
Implementation notes
- Technical details or constraints
- Verify PR has
agent:codexlabel - Check Gate workflow passed
- Ensure PR body has unchecked tasks
- Look for
agents:pauseorneeds-humanlabels - Review keepalive summary comment for skip reasons
- Verify issue has Scope/Tasks/Acceptance sections
- Run
agents-pr-meta.ymlmanually - Check PR links to source issue
After 3 failures, keepalive pauses and adds needs-human:
- Review failure reason in keepalive summary
- Fix the issue (code, prompt, auth)
- Remove
needs-humanlabel to resume
- Verify
CODEX_AUTH_JSONor GitHub App credentials are set - Check environment
agent-standardexists - Ensure PATs have required scopes:
repo,workflow
- Workflows Repo - Central workflow library
- Consumer README - Complete setup guide
- Keepalive Architecture - Detailed design
- Setup Checklist - Step-by-step configuration
MIT License - see LICENSE for details.