Skip to content

[WIP] Add preventive spend-governance layer with PACER-native MCP server#8

Closed
Copilot wants to merge 1 commit into
claude/pacer-spend-governance-50JNsfrom
copilot/preventive-spend-governance-layer
Closed

[WIP] Add preventive spend-governance layer with PACER-native MCP server#8
Copilot wants to merge 1 commit into
claude/pacer-spend-governance-50JNsfrom
copilot/preventive-spend-governance-layer

Conversation

Copilot AI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Thanks for the feedback on #6. I've created this new PR, which merges into #6, to address your comment. I will work on the changes and keep this PR's description up to date as I make progress.

Original PR: #6
Triggering comment (#6 (comment)):

Plan: slim this PR + map follow-ups

This PR is kept to the governance core (preventive spend cap + agent mode + --matter + court scoping + tests). Everything else moves to focused follow-up PRs so each lands as one reviewable thing.

Current PR state: 237 passed / 3 skipped, pyflakes + audit clean; CI green except the now-advisory ruff backlog (#7).


Follow-up PR A — MCP server (extract from this PR)

Move the optional MCP layer out so this PR is purely the CLI governance core (~1840 → ~1480 LOC).

  • Moves out: src/pacer_cli/mcp_server.py, tests/test_mcp_server.py, the MCP rows of tests/test_failclosed_invariant.py, the mcp extra + pacer-mcp entry point in pyproject.toml, and the MCP section of README.md.
  • Stays: security.check_spend() / spend_today() are already ctx-free and shared, so the extraction is clean — the MCP PR just re-adds the adapter on top.
  • Net: this PR shrinks; the MCP server gets its own review.

Follow-up PR B — Security review

Full security-review pass over the governance surface. Concrete findings already identified to fix there:

  • S1 (med) — audit-log injection via client code. --matter/config.client_code is written verbatim as client={code} into the audit line, and that line is the ledger spend_today() parses (|-delimited). A matter code containing a newline or | could forge/corrupt ledger rows. Fix: validate the matter code (PACER allows ~32 chars) and reject control chars / | / newline before it reaches the X-CLIENT-CODE header or the log. (This also closes the existing TODO(unverified) on per-request billing.)
  • S2 (low) — spend ledger is plaintext, append-only, user-writable. The cap trusts a file the local user can edit to under-report spend. Acceptable for a local trust model; note it, and it's the natural home for the previously-deferred signed/tamper-evident receipts.
  • S3 (low) — MCP stdio has no transport auth. Inherent to local stdio; document that it inherits the OS user's trust and obeys the same caps.
  • S4 (info) — confirmed no secrets in the audit log (url/cost/client only; no password/token).

Follow-up PR C — Optimizations

Concrete targets (the gate runs on every billable op, so per-op file work adds up):

  • O1 — spend_today() rescans + parses the whole monthly audit log on every gate call (O(file)). Cache a per-day running total keyed by date, invalidated on append (or tail-read).
  • O2 — apply_policy_csv() re-reads/parses policy.csv every enforce_spend. Cache by mtime.
  • O3 — resolve_court_scope() re-reads courts.csv every search. Cache by mtime (all_search_court_ids() is already lru_cached).
  • O4 — done by @copilot in fbe8090 (any(()) tuple + partition-based cost parse).

Already tracked


If this mapping looks right, I'll start with PR A (MCP extract) so this PR slims down, then open B and C. Say the word and I'll execute.


Generated by Claude Code

Copy link
Copy Markdown
Owner

Closing this — it's an empty draft (0 files changed, no commits beyond the initial scaffold) and has been idle since it opened. I've executed the plan directly instead:

Optimizations (O1–O3 from the plan) will follow as a separate small PR.


Generated by Claude Code

@johnzfitch johnzfitch closed this Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants