Skip to content

feat(ui): add /api/audit/summary aggregator for production audit dashboard - #749

Merged
POWERFULMOVES merged 1 commit into
mainfrom
codex/audit-summary-api-20260302
Mar 2, 2026
Merged

POWERFULMOVES merged 1 commit into
mainfrom
codex/audit-summary-api-20260302

Conversation

@POWERFULMOVES

@POWERFULMOVES POWERFULMOVES commented Mar 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • add pmoves/ui/app/api/audit/summary/route.ts
  • aggregate production audit sources into one payload:
    • pmoves/docs/PRODUCTION_AUDIT_DASHBOARD.md
    • latest pmoves/docs/audit/RELEASE_GATE_CHECK_*.md
    • planning timestamps from ROADMAP/NEXT_STEPS
    • PR monitor artifacts (docs/logs primary, docs/evidence/pr_monitor fallback)
    • Graphiti signed artifact (docs/logs/graphiti_signed_latest.json)
    • optional runtime health summary via checkAllServices
  • route is node runtime, fail-soft on missing files, and returns warnings[] for absent artifacts

Notes

  • supports dashboard designs that either fetch once or snapshot the payload into a static JS object for offline/PR artifact use
  • this change is additive and does not modify existing dashboard pages

Validation

  • npx eslint app/api/audit/summary/route.ts (from pmoves/ui)
  • full UI typecheck currently fails on pre-existing unrelated issues in tokenism and lib/serviceDiscovery.ts

Summary by CodeRabbit

Release Notes

  • New Features
    • Added a new audit summary API endpoint that aggregates production metrics, release gates, planning data, and system health information with comprehensive error reporting.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Mar 2, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Introduces a new Next.js API route that aggregates production audit data from multiple markdown and JSON sources, including audit dashboards, release gates, roadmaps, and optional runtime health checks, returning a unified JSON response with structured sections and warnings.

Changes

Cohort / File(s) Summary
Audit Summary API Route
pmoves/ui/app/api/audit/summary/route.ts
New API endpoint that reads and parses multiple markdown/JSON sources (audit dashboard, release gates, roadmap, next steps), aggregates data into structured sections (productionAudit, releaseGates, planning, prMonitor, graphiti, runtimeHealth), includes optional health checks with timeout protection, and provides robust error handling with warnings instead of failures.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant APIRoute as Audit Summary Route
    participant FileSystem as File System
    participant Parser as Data Parser
    participant Response as Response Handler

    Client->>APIRoute: GET /api/audit/summary
    APIRoute->>FileSystem: Find docs root
    alt docs root found
        FileSystem-->>APIRoute: docs path
        APIRoute->>FileSystem: Read PRODUCTION_AUDIT_DASHBOARD.md
        APIRoute->>FileSystem: Read release gate markdown
        APIRoute->>FileSystem: Read ROADMAP.md
        APIRoute->>FileSystem: Read NEXT_STEPS.md
        APIRoute->>FileSystem: Read PR monitor artifacts
        APIRoute->>FileSystem: Read Graphiti artifacts
        FileSystem-->>APIRoute: file contents + errors/warnings
        
        APIRoute->>Parser: Parse markdown tables (metrics, blockers, gates)
        APIRoute->>Parser: Parse last-updated timestamps
        APIRoute->>Parser: Aggregate JSON artifacts
        Parser-->>APIRoute: structured data
        
        alt includeHealth query param set
            APIRoute->>FileSystem: Fetch runtime health data
            FileSystem-->>APIRoute: health metrics
            APIRoute->>Parser: Compute health summary
            Parser-->>APIRoute: health aggregation
        end
        
        APIRoute->>Response: Construct JSON payload with all sections
        Response-->>Client: 200 OK (structured audit summary + warnings)
    else docs root not found
        FileSystem-->>APIRoute: not found
        APIRoute->>Response: Construct error response
        Response-->>Client: 500 Internal Server Error
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 whiskers twitching with delight
A summary route hops into view,
Gathering docs left and right,
Parsing tables, metrics true,
Health checks and gates reviewed,
One endpoint to rule them all—
Production audits, now renewed! 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description provides a clear summary of changes and validation steps, but is missing required sections like Testing and Review Coordination checkboxes from the template. Add Testing section with commands run, and complete Review Coordination and Required Checks sections with appropriate checkboxes marked or explained.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a new API route for aggregating production audit sources into a dashboard payload.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/audit-summary-api-20260302

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 and usage tips.

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pmoves/ui/app/api/audit/summary/route.ts`:
- Around line 319-323: The code currently reads ROADMAP.md and NEXT_STEPS.md
silently failing; wrap the reads for roadmapPath and nextStepsPath in existence
checks or try/catch and when a read fails push a descriptive warning into the
existing warnings array (include the path variable like
roadmapPath/nextStepsPath and context such as "ROADMAP.md missing" or the caught
error message). Update the logic around roadmapMarkdown and nextStepsMarkdown to
only use their values if the read succeeded. Ensure you reference the variables
roadmapPath, nextStepsPath, roadmapMarkdown, nextStepsMarkdown and the warnings
array so missing files are reported rather than ignored.
- Around line 120-134: The parseMetricTable function currently processes every
markdown table row and can pick up rows from unrelated tables; change it to
first locate the metrics table header (a row where the first column lowercased
is "metric" and there is a second column like "value"/"metric value"), then only
parse subsequent table rows until the table ends (stop when a non-table line or
a blank line occurs). Update parseMetricTable to: scan lines to find the header
row, begin parsing only after that header, skip the header/separator (e.g.,
lines starting with "---"), and use the existing cols[0]/cols[1] assignment to
populate ExecutiveMetrics so unrelated table rows cannot leak in.
- Around line 353-379: Remove absolute filesystem exposure by not returning
docsRoot and by converting every source path to a docs-relative identifier:
compute a relative path using path.relative(docsRoot,
dashboardPath|releaseGatePath|roadmapPath|nextStepsPath) (or null if the
markdown var is falsy or the path is outside docsRoot), and set
productionAudit.source, releaseGates.source, planning.roadmap.source and
planning.nextSteps.source to that relative identifier instead of the raw
absolute path; ensure docsRoot itself is omitted from the returned payload.
- Around line 188-196: latestReleaseGatePath (and the other spot using
fs.readdir) calls fs.readdir without try/catch which can throw despite the prior
exists() check; wrap each fs.readdir invocation in a try/catch that logs a
warning (following the readText/exists pattern) and returns null (or an empty
result) to preserve fail-soft behavior. Locate latestReleaseGatePath and the
other function using fs.readdir, add a try/catch around the await
fs.readdir(...) call, on catch call the module's logger/warning mechanism with
contextual details and return null so the route degrades gracefully.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72add4d and 83edd47.

📒 Files selected for processing (1)
  • pmoves/ui/app/api/audit/summary/route.ts

Comment on lines +120 to +134
function parseMetricTable(markdown: string): ExecutiveMetrics {
const metrics: ExecutiveMetrics = {};
for (const line of markdown.split(/\r?\n/)) {
if (!line.startsWith("|")) continue;
const cols = line
.split("|")
.map((c) => c.trim())
.filter(Boolean);
if (cols.length < 2) continue;
if (cols[0].toLowerCase() === "metric") continue;
if (cols[0].startsWith("---")) continue;
if (!cols[0] || !cols[1]) continue;
metrics[cols[0]] = cols[1];
}
return metrics;

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.

⚠️ Potential issue | 🟠 Major

Scope parseMetricTable to the metrics table only.

Line 122 currently parses all markdown table rows, so rows from other tables can leak into executiveMetrics and corrupt the summary.

Proposed fix
 function parseMetricTable(markdown: string): ExecutiveMetrics {
   const metrics: ExecutiveMetrics = {};
+  let inMetricsTable = false;
+
   for (const line of markdown.split(/\r?\n/)) {
-    if (!line.startsWith("|")) continue;
+    if (!inMetricsTable) {
+      if (/^\|\s*Metric\s*\|\s*Value\s*\|/i.test(line)) inMetricsTable = true;
+      continue;
+    }
+    if (!line.startsWith("|")) break;
+
     const cols = line
       .split("|")
       .map((c) => c.trim())
       .filter(Boolean);
     if (cols.length < 2) continue;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/ui/app/api/audit/summary/route.ts` around lines 120 - 134, The
parseMetricTable function currently processes every markdown table row and can
pick up rows from unrelated tables; change it to first locate the metrics table
header (a row where the first column lowercased is "metric" and there is a
second column like "value"/"metric value"), then only parse subsequent table
rows until the table ends (stop when a non-table line or a blank line occurs).
Update parseMetricTable to: scan lines to find the header row, begin parsing
only after that header, skip the header/separator (e.g., lines starting with
"---"), and use the existing cols[0]/cols[1] assignment to populate
ExecutiveMetrics so unrelated table rows cannot leak in.

Comment on lines +188 to +196
async function latestReleaseGatePath(docsRoot: string): Promise<string | null> {
const auditDir = path.join(docsRoot, "audit");
if (!(await exists(auditDir))) return null;
const files = await fs.readdir(auditDir);
const matches = files.filter((name) => /^RELEASE_GATE_CHECK_\d{4}-\d{2}-\d{2}\.md$/i.test(name));
if (!matches.length) return null;
matches.sort((a, b) => b.localeCompare(a));
return path.join(auditDir, matches[0]);
}

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -n -C3 'fs\.readdir\(' pmoves/ui/app/api/audit/summary/route.ts

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 870


🏁 Script executed:

cat -n pmoves/ui/app/api/audit/summary/route.ts | sed -n '180,220p'

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 1699


🏁 Script executed:

cat -n pmoves/ui/app/api/audit/summary/route.ts | sed -n '1,100p'

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2977


🏁 Script executed:

rg -n 'export.*GET|async.*GET' pmoves/ui/app/api/audit/summary/route.ts -A 50

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2199


🏁 Script executed:

cat -n pmoves/ui/app/api/audit/summary/route.ts | sed -n '290,360p'

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 3324


Guard fs.readdir calls to preserve fail-soft behavior.

Lines 191 and 209 use fs.readdir without error handling. The existence checks do not prevent all failures—permission errors, concurrent deletions, and other I/O issues can still occur and crash the route. The codebase pattern (see readText at lines 95-100 and exists at lines 70-77) consistently wraps file operations in try/catch to degrade gracefully by adding warnings. These two calls should follow the same pattern.

Proposed fix
 async function latestReleaseGatePath(docsRoot: string): Promise<string | null> {
   const auditDir = path.join(docsRoot, "audit");
   if (!(await exists(auditDir))) return null;
-  const files = await fs.readdir(auditDir);
+  let files: string[] = [];
+  try {
+    files = await fs.readdir(auditDir);
+  } catch {
+    return null;
+  }
   const matches = files.filter((name) => /^RELEASE_GATE_CHECK_\d{4}-\d{2}-\d{2}\.md$/i.test(name));
   if (!matches.length) return null;
   matches.sort((a, b) => b.localeCompare(a));
   return path.join(auditDir, matches[0]);
 }
@@
     const fallbackDir = path.join(docsRoot, "evidence", "pr_monitor");
     if (await exists(fallbackDir)) {
-      const files = (await fs.readdir(fallbackDir)).filter((f) => f.endsWith("-latest.json"));
-      files.sort((a, b) => b.localeCompare(a));
-      if (files.length > 0) {
-        source = path.join(fallbackDir, files[0]);
+      let files: string[] = [];
+      try {
+        files = await fs.readdir(fallbackDir);
+      } catch {
+        files = [];
+      }
+      const latest = files.filter((f) => f.endsWith("-latest.json"));
+      latest.sort((a, b) => b.localeCompare(a));
+      if (latest.length > 0) {
+        source = path.join(fallbackDir, latest[0]);
         payload = await readJson<unknown>(source);
       }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/ui/app/api/audit/summary/route.ts` around lines 188 - 196,
latestReleaseGatePath (and the other spot using fs.readdir) calls fs.readdir
without try/catch which can throw despite the prior exists() check; wrap each
fs.readdir invocation in a try/catch that logs a warning (following the
readText/exists pattern) and returns null (or an empty result) to preserve
fail-soft behavior. Locate latestReleaseGatePath and the other function using
fs.readdir, add a try/catch around the await fs.readdir(...) call, on catch call
the module's logger/warning mechanism with contextual details and return null so
the route degrades gracefully.

Comment on lines +319 to +323
const roadmapPath = path.join(docsRoot, "PMOVES.AI PLANS", "ROADMAP.md");
const roadmapMarkdown = await readText(roadmapPath);
const nextStepsPath = path.join(docsRoot, "NEXT_STEPS.md");
const nextStepsMarkdown = await readText(nextStepsPath);

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.

⚠️ Potential issue | 🟡 Minor

Emit warnings when planning files are missing.

ROADMAP/NEXT_STEPS reads currently fail silently, so warnings[] under-reports missing artifacts.

Proposed fix
   const roadmapPath = path.join(docsRoot, "PMOVES.AI PLANS", "ROADMAP.md");
   const roadmapMarkdown = await readText(roadmapPath);
   const nextStepsPath = path.join(docsRoot, "NEXT_STEPS.md");
   const nextStepsMarkdown = await readText(nextStepsPath);
+  if (!roadmapMarkdown) warnings.push("missing ROADMAP.md");
+  if (!nextStepsMarkdown) warnings.push("missing NEXT_STEPS.md");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/ui/app/api/audit/summary/route.ts` around lines 319 - 323, The code
currently reads ROADMAP.md and NEXT_STEPS.md silently failing; wrap the reads
for roadmapPath and nextStepsPath in existence checks or try/catch and when a
read fails push a descriptive warning into the existing warnings array (include
the path variable like roadmapPath/nextStepsPath and context such as "ROADMAP.md
missing" or the caught error message). Update the logic around roadmapMarkdown
and nextStepsMarkdown to only use their values if the read succeeded. Ensure you
reference the variables roadmapPath, nextStepsPath, roadmapMarkdown,
nextStepsMarkdown and the warnings array so missing files are reported rather
than ignored.

Comment on lines +353 to +379
docsRoot,
warnings,
productionAudit: {
source: dashboardMarkdown ? dashboardPath : null,
lastUpdated: dashboardMarkdown ? parseLabelValue(dashboardMarkdown, "Last Updated") : null,
branch: dashboardMarkdown ? parseLabelValue(dashboardMarkdown, "Branch") : null,
commit: dashboardMarkdown ? parseLabelValue(dashboardMarkdown, "Commit") : null,
executiveMetrics: dashboardMarkdown ? parseMetricTable(dashboardMarkdown) : {},
activeBlockers: dashboardMarkdown ? parseActiveBlockers(dashboardMarkdown) : [],
},
releaseGates: {
source: releaseGateMarkdown ? releaseGatePath : null,
items: releaseGateMarkdown ? parseReleaseGateRows(releaseGateMarkdown) : [],
},
planning: {
roadmap: {
source: roadmapMarkdown ? roadmapPath : null,
lastUpdated: roadmapMarkdown ? parsePlanLastUpdated(roadmapMarkdown) : null,
},
nextSteps: {
source: nextStepsMarkdown ? nextStepsPath : null,
lastUpdated: nextStepsMarkdown ? parsePlanLastUpdated(nextStepsMarkdown) : null,
},
},
prMonitor,
graphiti,
runtimeHealth,

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.

⚠️ Potential issue | 🟠 Major

Do not return absolute filesystem paths in API payload.

docsRoot and several source fields can expose host path structure to clients. Return docs-relative identifiers instead.

Proposed fix
+function toPublicPath(docsRoot: string, absolutePath: string | null): string | null {
+  if (!absolutePath) return null;
+  const rel = path.relative(docsRoot, absolutePath).replace(/\\/g, "/");
+  return rel.startsWith("..") ? null : `docs/${rel}`;
+}
+
 export async function GET(request: NextRequest) {
@@
   return NextResponse.json(
     {
       generatedAt: new Date().toISOString(),
-      docsRoot,
+      docsRoot: "docs",
       warnings,
       productionAudit: {
-        source: dashboardMarkdown ? dashboardPath : null,
+        source: toPublicPath(docsRoot, dashboardMarkdown ? dashboardPath : null),
@@
       releaseGates: {
-        source: releaseGateMarkdown ? releaseGatePath : null,
+        source: toPublicPath(docsRoot, releaseGateMarkdown ? releaseGatePath : null),
@@
         roadmap: {
-          source: roadmapMarkdown ? roadmapPath : null,
+          source: toPublicPath(docsRoot, roadmapMarkdown ? roadmapPath : null),
@@
         nextSteps: {
-          source: nextStepsMarkdown ? nextStepsPath : null,
+          source: toPublicPath(docsRoot, nextStepsMarkdown ? nextStepsPath : null),
@@
-      prMonitor,
-      graphiti,
+      prMonitor: { ...prMonitor, source: toPublicPath(docsRoot, prMonitor.source) },
+      graphiti: { ...graphiti, source: toPublicPath(docsRoot, graphiti.source) },
       runtimeHealth,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/ui/app/api/audit/summary/route.ts` around lines 353 - 379, Remove
absolute filesystem exposure by not returning docsRoot and by converting every
source path to a docs-relative identifier: compute a relative path using
path.relative(docsRoot, dashboardPath|releaseGatePath|roadmapPath|nextStepsPath)
(or null if the markdown var is falsy or the path is outside docsRoot), and set
productionAudit.source, releaseGates.source, planning.roadmap.source and
planning.nextSteps.source to that relative identifier instead of the raw
absolute path; ensure docsRoot itself is omitted from the returned payload.

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