Skip to content

feat(audit-log): mirror decision-changing guardrail evaluations into AuditEntry (P2) - #681

Merged
arantespp merged 1 commit into
mainfrom
claude/soat-roadmap-next-4hbifv
Jul 25, 2026
Merged

feat(audit-log): mirror decision-changing guardrail evaluations into AuditEntry (P2)#681
arantespp merged 1 commit into
mainfrom
claude/soat-roadmap-next-4hbifv

Conversation

@arantespp

Copy link
Copy Markdown
Member

What & why

Implements Audit-log PRD Phase 2 — the next item on the delivery roadmap's substrate tier. Decision-changing guardrail evaluations now surface on the shared AuditEntry audit substrate, the same substrate the activity feed (approvals P4) and SIEM export build on.

The selective-write decision

The PRD's original framing ("land it in AuditEntry rather than a parallel table") predated the guardrail_evaluations table actually shipping. That table is now the full operational log — one row per guardrail per call, including plain execute. Migrating or dual-writing that high-volume firehose into the mutation-focused audit log would flood it and break existing consumers (approval cross-links, dry-run reuse, generation stamping).

So instead of migrate/dual-write, this selectively mirrors only the evaluations that changed the call's outcome:

Decision Operational table Audit log
execute (identity)
route_to_approval
blocked
tripwire

This gives up nothing on any axis: acceptance criteria met, existing consumers untouched, AuditEntry's mutation-only/low-volume design respected, no data duplication.

How

  • Mirror is a fire-and-forget write on the audit queue from the single choke point persistGuardrailEvaluations, so all three dispatch paths (agent tool gate, orchestration tool guardrail, orchestration engine) are covered; the dry-run preview (never persists) produces no entries.
  • Entries are platform-originated: null principal columns, action: guardrails:Evaluate, guardrail as the resource, full evaluation record as detail (detail.kind = "guardrail_evaluation"). A route_to_approval entry also carries the filed approval_id.
  • The product-feed-ownership question (AuditEntry.detail vs a dedicated ActivityEntry model) is intentionally out of scope — it's an approvals-P4 concern and P2 doesn't need it settled.

Tests (red/green TDD)

  • Write side, through the real resolver dispatch entry point (agentToolGuardrailGate.test.ts): class D/C/B (blocked / route_to_approval / tripwire) each write a guardrail_evaluation audit entry; class A (execute) writes none.
  • Read side, through the audit-log REST list endpoint (auditLog.test.ts): a decision-changing evaluation surfaces snake-cased through the API; execute writes nothing.
  • A shared schema fixture (guardrailEvaluationDetail.ts) is asserted on both sides — camelCase (write) and snake_case (read) — so the guardrails kind and the audit PRD cannot drift (acceptance criterion Feat files #2).

Docs & housekeeping

  • docs/prd-audit-log.md — P2 marked shipped, selective-write decision recorded, stale "blocked on guardrails P3" removed (P3 is shipped).
  • docs/roadmap.md — P2 marked done across backlog, dependency graph, build order, and the activity-feed reconciliation note.
  • packages/website/docs/modules/audit-log.md + guardrails.md — document the new guardrail_evaluation system-originated entry.
  • OpenAPI detail description mentions the new kind (no SDK/CLI diff — cosmetic).

Checks

  • pnpm typecheck ✅ · pnpm eslint ✅ · no as any / as unknown
  • affected server suites (guardrail gate, orchestration guardrails, audit-log, guardrail evaluation) ✅ green against a real Postgres
  • pnpm docs-lint

🤖 Generated with Claude Code

https://claude.ai/code/session_01Vf1q3tun1okV7hpnXpvB1o


Generated by Claude Code

…AuditEntry (P2)

Land audit-log PRD Phase 2 as a selective-write: guardrail evaluations that
change a call's outcome (route_to_approval / blocked / tripwire) are mirrored
into the shared AuditEntry substrate as detail.kind = "guardrail_evaluation",
while plain `execute` evaluations stay solely in the dedicated
guardrail_evaluations operational table.

The mirror is a fire-and-forget write on the audit queue from the single choke
point (persistGuardrailEvaluations), so all three dispatch paths — agent tool
gate, orchestration tool guardrail, orchestration engine — are covered, and the
dry-run preview (which never persists) produces no entries. Entries are
platform-originated: null principal columns, action `guardrails:Evaluate`, with
the full evaluation record as detail; a route_to_approval entry also carries the
filed approval_id.

A shared schema fixture (guardrailEvaluationDetail.ts) is asserted on both the
write side (camelCase, via the resolver gate test) and the read side (snake_case,
via the audit-log REST test) so the guardrails kind and the audit PRD cannot
drift.

Docs, PRD, and roadmap updated to reflect P2 shipped and the selective-write
decision; the product-feed-ownership question is left to approvals Phase 4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vf1q3tun1okV7hpnXpvB1o
@github-actions

Copy link
Copy Markdown

Deploy Outputs

Package Stack Output Key Output Value
@soat/website SoatWebsite-claude-soat-roadmap-next-4hbifv BucketWebsiteURL http://soatwebsite-claude-soat-roadmap-next--staticbucket-ayq4e70mua9m.s3-website-us-east-1.amazonaws.com

@arantespp
arantespp merged commit 736bdf3 into main Jul 25, 2026
6 checks passed
@arantespp
arantespp deleted the claude/soat-roadmap-next-4hbifv branch July 25, 2026 11:22
@arantespp arantespp mentioned this pull request Jul 25, 2026
3 tasks
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