Skip to content

perf(admin): slim audit payloads and gzip admin responses - #603

Merged
SantiagoDePolonia merged 2 commits into
mainfrom
feat/audit-payload-diet
Jul 27, 2026
Merged

perf(admin): slim audit payloads and gzip admin responses#603
SantiagoDePolonia merged 2 commits into
mainfrom
feat/audit-payload-diet

Conversation

@SantiagoDePolonia

@SantiagoDePolonia SantiagoDePolonia commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Problem

A Pro user reported the audit list call (/admin/audit/log?days=30&limit=25) taking 14 s / 27 MB, with the Interactions drawer's /admin/audit/conversation still pending behind it (and eventually surfacing "Unable to load interactions."). Each list entry shipped ~1 MB: full request body + response body + per-attempt upstream error bodies + one full rewritten body per request revision (the Pro compression audit trail effectively doubles request bytes), all uncompressed. The drawer then asked for up to 120 such entries.

Changes

1. Slim /admin/audit/log entries (internal/admin/audit_projection.go)
List rows keep scalar metadata, attempt-pip fields, revision savings/detail, headers, and error fields — but drop request_body, response_body, attempts[].response_body/response_headers, and request_revisions[].body. Two new response fields compensate:

  • bodies_omitted — tells the dashboard the full entry lives behind GET /admin/audit/detail (also implies the entry is persisted, not in-flight).
  • conversation_payload — server-computed replacement for the drawer-eligibility sniff the client did on the removed bodies (matters for /v1/messages and passthrough paths).

The dashboard's on-expand detail fetch already existed (AuditEntryRowfetchAuditEntryDetail → merge); the only changes are: the fetch gate honors bodies_omitted, the detail merge clears it, and hasConversationPayload accepts the flag. Live-SSE entries are untouched.

2. Slim /admin/audit/conversation entries
The drawer builds its transcript from id, timestamp, request_body, response_body, error_message only — so thread entries now drop attempts, request_revisions, and header maps.

3. Gzip admin responses (internal/server/http.go)
middleware.Gzip on both admin route groups; the /live/logs SSE stream is exempt (per-event flushing). Audit/usage JSON compresses roughly an order of magnitude.

4. LOGGING_LOG_REVISION_BODIES / logging.log_revision_bodies (default true)
Refines LOGGING_LOG_BODIES: when disabled, request rewriters (e.g. GoModel Pro token compression) still record revision metadata — rewriter, sizes, tokens saved, change detail — but skip storing the full rewritten body, roughly halving audit storage growth per compressed request. Documented in config.example.yaml and docs/advanced/configuration.mdx.

Impact

For the reported workload the list response drops from ~27 MB to tens of KB on the wire (slimming × gzip), and the conversation call sheds the revision/attempt copies plus gzip on what remains. Expanded rows hydrate on demand from /admin/audit/detail.

Tests

  • New: audit_projection_test.go (list slimming incl. survivors, body-less entries unmarked, detail keeps full payload, conversation slimming, hasConversationPayload table).
  • New: revision-body toggle case in request_rewrite_test.go; existing revision tests updated for the new config field.
  • Updated: TestAuditLog_Success now asserts slim entries.
  • Full go test ./... green (72 pkgs), dashboard JS tests 362/362, dist rebuilt and in sync, pre-commit (race, lint, perf guard) all passing.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Audit log list responses now omit heavy request/response and per-attempt/revision payloads, while audit detail views still return full content.
    • Conversation audit entries preserve transcript-rendering content, with explicit flags for whether bodies were omitted.
    • Added a “truncated” indicator for conversation building when time limits cut walks short.
    • Introduced separate control to store rewritten request bodies from request rewriters (now default-enabled).
  • Improvements

    • Admin API responses are gzip-compressed; live log streaming remains unaffected.
  • Documentation

    • Updated OpenAPI and configuration docs to reflect payload omission behavior and the new logging setting/fields.

Follow-up: the 502 root cause (PostgreSQL)

The reporting user is on PostgreSQL, and the /admin/audit/conversation request ultimately died as a 502 from the fronting proxy after ~an hour. That pinned the real root cause: the chain lookups run WHERE data #>> '{response_body,id}' = $1 ORDER BY timestamp ASC LIMIT 1, and with the bare expression index Postgres' planner routinely prefers walking the timestamp index and filtering — detoasting every row's ~1 MB JSONB along the way; effectively a full-table scan when the chained value is rare. With no server-side deadline, the request just ran until the proxy gave up.

Second commit (d982710c):

  • Composite (expression, timestamp) indexes replace the bare expression indexes on both dialects (old ones dropped at store init), so the filter and the order come from one index and the timestamp-scan plan is never attractive.
  • 10 s deadline on the whole chain walk. A deadline expiring mid-walk now returns the partial thread collected so far (ConversationResult.Truncated: true) instead of failing — the drawer renders the turns nearest the anchor. Only a timeout before the anchor loads surfaces as a 504. Postgres honors context cancellation, so the runaway query is actually killed server-side.
  • Tests: bidirectional-walk happy path, partial-on-deadline in both directions, anchor-timeout-still-errors.

Note for operators: the first startup after this change builds the two composite indexes; on a large audit_logs table that is a one-time cost at boot.

A 25-row audit list page weighed ~27 MB for agent traffic: every entry
shipped its full request body, response body, per-attempt error bodies,
and one rewritten body per request revision, uncompressed. The
Interactions drawer then requested up to 120 such entries and routinely
timed out behind proxies.

Four changes, one per bottleneck:

- /admin/audit/log entries are slimmed server-side: bodies, attempt
  error payloads, and revision bodies are stripped; scalar metadata,
  attempt pips data, and revision savings survive. New bodies_omitted
  and conversation_payload fields tell the dashboard to lazy-load
  /admin/audit/detail on row expand (that fetch path already existed)
  and preserve the Interactions-drawer eligibility signal it previously
  sniffed from the bodies.

- /admin/audit/conversation entries drop attempts, request revisions,
  and header maps; the drawer builds its transcript solely from
  id/timestamp/request_body/response_body/error_message.

- Admin API responses are gzipped (the live-log SSE stream is exempt,
  it must flush per event).

- New LOGGING_LOG_REVISION_BODIES (logging.log_revision_bodies, default
  true) lets operators keep revision metadata but skip storing the full
  rewritten body per compressed request, roughly halving audit storage
  growth under GoModel Pro token compression.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 27, 2026 22:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Audit logging adds configurable rewritten-body capture, slimmed admin list and conversation payloads, omission metadata, partial conversation results on deadline, dashboard detail fetching, updated API documentation, lookup indexes, and gzip compression for admin routes.

Changes

Audit payload handling

Layer / File(s) Summary
Revision body logging control
config/..., internal/auditlog/..., internal/server/request_rewrite*, docs/advanced/configuration.mdx
Adds LogRevisionBodies, defaults and configuration documentation, propagates it to audit logging, and conditionally stores rewritten request bodies while preserving revision metadata.
Audit projection and response contract
internal/admin/audit_projection*, internal/admin/handler*, cmd/gomodel/docs/docs.go, docs/openapi.json
Slims list and conversation responses, adds omission and conversation markers, preserves full detail payloads, and updates API descriptions and schemas.
Conversation traversal and timeout handling
internal/auditlog/conversation_helpers*, internal/auditlog/reader.go, internal/admin/handler_audit.go
Returns partial conversation results for deadline-limited later hops, exposes truncated, and bounds admin conversation construction with a timeout.
Dashboard payload resolution
web/dashboard/src/pages/audit-logs/*
Uses conversation_payload for conversation detection and fetches detail payloads when bodies were omitted, clearing the marker after merging detail data.
Audit lookup indexes
internal/auditlog/store_sql.go
Replaces single-expression response lookup indexes with expression-and-timestamp indexes for SQLite and PostgreSQL.

Admin response compression

Layer / File(s) Summary
Gzip middleware for admin routes
internal/server/http.go
Applies gzip compression to current and legacy admin routes while excluding live-log streaming paths.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Dashboard
  participant AuditLogAPI
  participant AuditProjection
  participant AuditDetailAPI
  Dashboard->>AuditLogAPI: request audit list
  AuditLogAPI->>AuditProjection: slim entries
  AuditProjection-->>Dashboard: entries with bodies_omitted
  Dashboard->>AuditDetailAPI: fetch omitted payload
  AuditDetailAPI-->>Dashboard: full entry and clear omission state
Loading

Possibly related PRs

Suggested reviewers: copilot

Poem

A rabbit trims the audit trail,
Keeps revision notes without the bulk.
Slim threads hop through the dashboard,
Full details wait for one quick pull.
Gzip wraps the admin way—
Live logs still stream and play.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title concisely captures the main changes: slimming admin audit payloads and enabling gzip on admin responses.
Description check ✅ Passed The PR description explains the problem, changes, impact, tests, and follow-up, so it covers the template's required brief explanation.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/audit-payload-diet

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mintlify

mintlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
gomodel 🟢 Ready View Preview Jul 27, 2026, 10:25 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@codecov-commenter

codecov-commenter commented Jul 27, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 92.17391% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/admin/audit_projection.go 94.52% 2 Missing and 2 partials ⚠️
internal/admin/handler_audit.go 70.00% 2 Missing and 1 partial ⚠️
internal/auditlog/conversation_helpers.go 93.33% 1 Missing ⚠️
internal/auditlog/factory.go 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/server/request_rewrite_test.go (1)

376-458: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Convert the revision body logging matrix to a table-driven test.

TestRequestRewriteMiddlewareRecordsRevisions checks the LogBodies/LogRevisionBodies combinations via a shared run() helper and duplicate assertions. Represent these cases as table entries with per-case setup/expectations to reduce duplication and make the matrix explicit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/server/request_rewrite_test.go` around lines 376 - 458, Refactor the
subtests in TestRequestRewriteMiddlewareRecordsRevisions into a table-driven
matrix covering each LogBodies/LogRevisionBodies combination. Keep the shared
server/request setup from run, but move case-specific expectations into table
fields and execute common revision count, body, size, and detail assertions
through one loop, preserving each case’s expected body and metadata behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@internal/server/request_rewrite_test.go`:
- Around line 376-458: Refactor the subtests in
TestRequestRewriteMiddlewareRecordsRevisions into a table-driven matrix covering
each LogBodies/LogRevisionBodies combination. Keep the shared server/request
setup from run, but move case-specific expectations into table fields and
execute common revision count, body, size, and detail assertions through one
loop, preserving each case’s expected body and metadata behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: cbd1bce9-6c94-45b8-afb1-29b7ee3a8eec

📥 Commits

Reviewing files that changed from the base of the PR and between 7e974d6 and 170f7f4.

⛔ Files ignored due to path filters (2)
  • internal/admin/dashboard/static/dist/assets/index-Dy9UJDJP.js is excluded by !**/dist/**
  • internal/admin/dashboard/static/dist/index.html is excluded by !**/dist/**
📒 Files selected for processing (19)
  • cmd/gomodel/docs/docs.go
  • config/config.example.yaml
  • config/config.go
  • config/config_test.go
  • config/logging.go
  • docs/advanced/configuration.mdx
  • docs/openapi.json
  • internal/admin/audit_projection.go
  • internal/admin/audit_projection_test.go
  • internal/admin/handler.go
  • internal/admin/handler_audit.go
  • internal/admin/handler_test.go
  • internal/auditlog/auditlog.go
  • internal/auditlog/factory.go
  • internal/server/http.go
  • internal/server/request_rewrite.go
  • internal/server/request_rewrite_test.go
  • web/dashboard/src/pages/audit-logs/conversation-helpers.js
  • web/dashboard/src/pages/audit-logs/live-logs-logic.js

The /admin/audit/conversation chain lookups run
`WHERE <json expr> = ? ORDER BY timestamp ASC LIMIT 1`. With the bare
expression indexes, PostgreSQL's planner routinely prefers walking the
timestamp index and filtering — detoasting every row's JSON blob and
scanning the whole table when the value is rare. On a user deployment
one request hung until the fronting proxy returned 502 Bad Gateway.

Replace both expression indexes with composite (expression, timestamp)
indexes so the filter and the order are satisfied by one index and the
timestamp-scan plan is never attractive; the old indexes are dropped at
store init.

As a safety net for degraded stores, the handler now bounds the whole
walk with a 10s deadline. A deadline expiring mid-walk returns the
partial thread collected so far (ConversationResult.Truncated) instead
of failing; only a timeout before the anchor loads surfaces as a 504.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 27, 2026 22:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/auditlog/store_sql.go`:
- Around line 181-191: Update jsonPathIndexes() for both SQLite and PostgreSQL
so each replacement composite index is created before dropping the corresponding
legacy indexes. Preserve the existing index definitions and statement order
otherwise, ensuring NewSQLStore() cannot remove the old lookup indexes before
the replacements are available.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 716a4cee-d576-4741-99a6-e807dc4aa66a

📥 Commits

Reviewing files that changed from the base of the PR and between 170f7f4 and d982710.

📒 Files selected for processing (7)
  • cmd/gomodel/docs/docs.go
  • docs/openapi.json
  • internal/admin/handler_audit.go
  • internal/auditlog/conversation_helpers.go
  • internal/auditlog/conversation_helpers_test.go
  • internal/auditlog/reader.go
  • internal/auditlog/store_sql.go

Comment on lines +181 to +191
`DROP INDEX IF EXISTS idx_audit_response_id`,
`DROP INDEX IF EXISTS idx_audit_previous_response_id`,
`CREATE INDEX IF NOT EXISTS idx_audit_response_id_ts ON audit_logs(json_extract(data, '$.response_body.id'), timestamp)`,
`CREATE INDEX IF NOT EXISTS idx_audit_previous_response_id_ts ON audit_logs(json_extract(data, '$.request_body.previous_response_id'), timestamp)`,
}
case sqlx.PostgreSQL:
return []string{
`CREATE INDEX IF NOT EXISTS idx_audit_response_id ON audit_logs((data #>> '{response_body,id}'))`,
`CREATE INDEX IF NOT EXISTS idx_audit_previous_response_id ON audit_logs((data #>> '{request_body,previous_response_id}'))`,
`DROP INDEX IF EXISTS idx_audit_response_id`,
`DROP INDEX IF EXISTS idx_audit_previous_response_id`,
`CREATE INDEX IF NOT EXISTS idx_audit_response_id_ts ON audit_logs((data #>> '{response_body,id}'), timestamp)`,
`CREATE INDEX IF NOT EXISTS idx_audit_previous_response_id_ts ON audit_logs((data #>> '{request_body,previous_response_id}'), timestamp)`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

rg -n -C 20 '\bjsonPathIndexes\s*\(' --glob '*.go'
rg -n -C 20 '\b(Begin|Commit|Rollback|Exec|MustExec)\b' internal/auditlog --glob '*.go'

Repository: ENTERPILOT/GoModel

Length of output: 156


🏁 Script executed:

#!/bin/bash
set -u

echo "== files =="
git ls-files | rg '(^|/)store_sql\.go$|internal/auditlog/.+\.go$' || true

echo "== jsonPathIndexes occurrences =="
rg -n -C 30 'jsonPathIndexes|idx_audit_response_id_ts|idx_audit_previous_response_id_ts|jsonPath' --glob '*.go' . || true

echo "== auditlog outlines =="
for f in $(git ls-files 'internal/auditlog/*.go'); do
  echo "--- $f"
  wc -l "$f"
  ast-grep outline "$f" || true
done

echo "== relevant store_sql slice =="
file=$(git ls-files 'internal/auditlog/store_sql.go' | head -n 1)
if [ -n "${file:-}" ]; then
  nl -ba "$file" | sed -n '1,260p'
fi

Repository: ENTERPILOT/GoModel

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -u

echo "== sqlx package imports =="
rg -n "'github\.com/jmoiron/sqlx'\"|\"github\.com/jmoiron/sqlx\"" --glob '*.go' . | head -n 100

echo "== sqlx.Exec/Schema/AddColumns definitions if vendored/module cache exists =="
for path in $(go env GOPATH 2>/dev/null | tr ':' '\n'); do
  for f in $(find "$path/pkg/mod/github.com/jmoiron/sqlx*" "$path/mod/cache/download/github.com/jmoiron/sqlx*" 2>/dev/null | rg 'sqlx.go$|db.go$|schema.go$' | head -n 20); do
    echo "--- $f"
    rg -n -C 8 'type DB struct|func .*Schema|func .*AddColumns|func (\.Exec|DB\.Exec)\(' "$f" | head -n 80
  done
done

echo "== relevant schema migration execution slice =="
file=$(git ls-files 'internal/auditlog/store_sql.go' | head -n 1)
nl -ba "$file" | sed -n '135,196p'

echo "== reader SQL lookup slice =="
file=$(git ls-files 'internal/auditlog/reader_sql.go' | head -n 1)
nl -ba "$file" | sed -n '219,235p'

echo "== lock/index tests =="
rg -n -C 12 'idx_audit_response_id_ts|idx_audit_previous_response_id_ts|response_id_ts|previous_response_id_ts|idx_audit_response_id|idx_audit_previous_response_id' internal/auditlog --glob '*.go'

Repository: ENTERPILOT/GoModel

Length of output: 3390


Create replacement indexes before dropping the legacy indexes.

jsonPathIndexes() drops the existing lookup indexes before creating their composite replacements, and NewSQLStore() executes each statement sequentially with only a warning on failure. If creation fails or the process exits between statements, the conversation lookup can fall back to an unindexed scan instead of using the intended composite indexes. Create both replacement indexes first, then drop the old ones.

Proposed ordering
 return []string{
-    `DROP INDEX IF EXISTS idx_audit_response_id`,
-    `DROP INDEX IF EXISTS idx_audit_previous_response_id`,
     `CREATE INDEX IF NOT EXISTS idx_audit_response_id_ts ...`,
     `CREATE INDEX IF NOT EXISTS idx_audit_previous_response_id_ts ...`,
+    `DROP INDEX IF EXISTS idx_audit_response_id`,
+    `DROP INDEX IF EXISTS idx_audit_previous_response_id`,
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
`DROP INDEX IF EXISTS idx_audit_response_id`,
`DROP INDEX IF EXISTS idx_audit_previous_response_id`,
`CREATE INDEX IF NOT EXISTS idx_audit_response_id_ts ON audit_logs(json_extract(data, '$.response_body.id'), timestamp)`,
`CREATE INDEX IF NOT EXISTS idx_audit_previous_response_id_ts ON audit_logs(json_extract(data, '$.request_body.previous_response_id'), timestamp)`,
}
case sqlx.PostgreSQL:
return []string{
`CREATE INDEX IF NOT EXISTS idx_audit_response_id ON audit_logs((data #>> '{response_body,id}'))`,
`CREATE INDEX IF NOT EXISTS idx_audit_previous_response_id ON audit_logs((data #>> '{request_body,previous_response_id}'))`,
`DROP INDEX IF EXISTS idx_audit_response_id`,
`DROP INDEX IF EXISTS idx_audit_previous_response_id`,
`CREATE INDEX IF NOT EXISTS idx_audit_response_id_ts ON audit_logs((data #>> '{response_body,id}'), timestamp)`,
`CREATE INDEX IF NOT EXISTS idx_audit_previous_response_id_ts ON audit_logs((data #>> '{request_body,previous_response_id}'), timestamp)`,
case sqlx.SQLite:
return []string{
`CREATE INDEX IF NOT EXISTS idx_audit_response_id_ts ON audit_logs(json_extract(data, '$.response_body.id'), timestamp)`,
`CREATE INDEX IF NOT EXISTS idx_audit_previous_response_id_ts ON audit_logs(json_extract(data, '$.request_body.previous_response_id'), timestamp)`,
`DROP INDEX IF EXISTS idx_audit_response_id`,
`DROP INDEX IF EXISTS idx_audit_previous_response_id`,
}
case sqlx.PostgreSQL:
return []string{
`CREATE INDEX IF NOT EXISTS idx_audit_response_id_ts ON audit_logs((data #>> '{response_body,id}'), timestamp)`,
`CREATE INDEX IF NOT EXISTS idx_audit_previous_response_id_ts ON audit_logs((data #>> '{request_body,previous_response_id}'), timestamp)`,
`DROP INDEX IF EXISTS idx_audit_response_id`,
`DROP INDEX IF EXISTS idx_audit_previous_response_id`,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/auditlog/store_sql.go` around lines 181 - 191, Update
jsonPathIndexes() for both SQLite and PostgreSQL so each replacement composite
index is created before dropping the corresponding legacy indexes. Preserve the
existing index definitions and statement order otherwise, ensuring NewSQLStore()
cannot remove the old lookup indexes before the replacements are available.

@SantiagoDePolonia
SantiagoDePolonia merged commit 5a0ed51 into main Jul 27, 2026
21 checks passed
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.

3 participants