Repository navigation
[Bug]: govern() config.audit_file is documented but never wired to AuditLog - audit is always in-memory only #3915
Description
Activity
- addedbugSomething isn't workingSomething isn't workingtriageNeeds triageNeeds triage
on Sep 9, 2026 - added a commit that references this issue
on Sep 11, 2026 - added a commit that references this issue
on Sep 12, 2026 - added 3 commits that reference this issue
on Sep 15, 2026 Hi — I'd like to take this if it's still available.
Context: I build pre-execution authorization for irreversible actions in an agent harness (declaration before the action, monotonic deny, one append-only audit ledger), so "the audit trail must survive a restart" is exactly the failure mode I care about.
Plan (small, backward-compatible):
- Expose
audit_fileon the top-levelgovern()factory (today it raisesTypeError). - Wire
GovernedCallableto constructAuditLog(sink=FileAuditSink(path))whenaudit_fileis set; when unset, keepAuditLog()exactly as today so existing behavior and tests are unchanged. - Add a test that writes to a temp file and asserts the record is readable after re-opening (i.e. it actually persisted), plus a test that the unset path stays in-memory.
- Update the docstring / README line so it matches shipped behavior.
Will open a PR shortly. Happy to adjust the shape — e.g. if you'd rather have
audit_fileonly onGovernedCallableand not on the factory, or a different sink-construction location.- Expose
Correction, and apologies for the noise: I posted the claim above without first checking for an already-open PR — that was my mistake.
#3916 (by fer-marino) has been open since 2026-09-09, is actively iterated, and is already under maintainer review. I'm withdrawing my claim so it doesn't fragment that review.
Two things I can genuinely offer instead, if useful:
- External-consumer testing of the persistence path — my use case is exactly "the audit trail must survive a hard kill of the process", and I built the same thing (declaration → monotonic deny → append-only ledger) for an agent harness. If it helps, I can exercise fix: govern - wire audit_file to FileAuditSink so file-based audit persistence actually works #3916's branch from a caller's perspective and report anything that breaks (e.g. behaviour on restart, partial last line, rotation while appending).
- Nothing else — I won't open a parallel PR.
(Also happy to just drop this if the review already covers it.)
- added a commit that references this issue
on Sep 17, 2026 - added a commit that references this issue
on Oct 1, 2026
Package
agent-governance-toolkit-core
Description
GovernanceConfig.audit_fileis documented as "Path for file-based audit log. None = in-memory only." butGovernedCallable.__init__never reads it:AuditLog()is always constructed with no sink, regardless ofaudit_file. Confirmed by grepping the whole package -audit_fileappears only in the field declaration and its own docstring ingovern.py, nowhere else. Worse, the top-levelgovern()factory function (the module's own documented 2-line-integration entrypoint) doesn't even exposeaudit_fileas a parameter, so a caller usinggovern(fn, policy=..., audit_file="...")gets aTypeErrorbefore ever reaching the dead config.This isn't a missing feature - the library already has everything needed to make
audit_filework:FileAuditSink(hash-chained, HMAC-signed JSON-lines, inaudit_backends.py) andAuditLog(sink=...)both exist and are fully functional in isolation.govern()just never connects them.Impact: every audit trail produced through
govern()is lost on process exit, with no way to opt into persistence short of bypassinggovern()entirely and constructingGovernedCallable/AuditLog/FileAuditSinkby hand. For any compliance/audit use case (this is exactly what surfaced it - a policy-enforcement PoC that needs the audit trail to survive a restart), the documentedaudit_fileknob looks like the supported way to do this and silently doesn't work.Repro:
How does this impact your work?
Found while evaluating AGT for a compliance/audit-trail use case (MAESTRO-7 - evidence sources, reasoning steps must be retained). The audit_file field is exactly what that needs, and it looked supported (documented dataclass field) but does nothing - not degraded, not slow, just silently discards persistence. Not currently blocked: workaround is bypassing govern() and wiring GovernedCallable/AuditLog/FileAuditSink by hand, but that defeats the point of the 2-line govern() integration this library advertises. Opening a PR with the fix (wires audit_file to FileAuditSink, adds audit_secret_key for HMAC signing, exposes both on the govern() factory) alongside this issue.
Timeline
No response
Steps to Reproduce
safe = govern(read_doc, policy="allow-all.yaml", audit_file="audit.jsonl")-> TypeError: govern() got an unexpected keyword argument 'audit_file' (not exposed on the factory at all).GovernanceConfig(policy=..., audit_file="audit.jsonl")directly and passing it toGovernedCallable: call the governed function a few times, then check foraudit.jsonlon disk.GovernedCallable.__init__buildsAuditLog()with no sink regardless ofconfig.audit_file.Environment
agent-governance-toolkit-core (agent-mesh package), Python 3.14, Windows 11. Verified against a fresh checkout of main.
Logs / Error Output
Code of Conduct