Your first analysis¶
Prerequisites
- A running Meridian instance (Docker Compose) with a healthy
/api/cra/health curlandjq(jq is optional but used in examples)- If
MERIDIAN_AUTH_ENABLED=true, theCRA_API_TOKENvalue
What you'll have after
You will have submitted a diff, watched Meridian open an RFC, and read back its verdict — once for a clean change (APPROVED) and once for a risky one (BLOCKED).
Step 1 — Submit a clean diff¶
Meridian's analyze endpoint takes the diff plus a little metadata. Here is a minimal, harmless change:
curl -s -X POST http://localhost:3011/api/cra/analyze \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $CRA_API_TOKEN" \
-d '{
"repo_name": "demo",
"branch": "main",
"commit_message": "docs: fix typo in README",
"diff": "--- a/README.md\n+++ b/README.md\n@@ -1 +1 @@\n-# Helo\n+# Hello\n"
}' | jq
Expected (abridged):
{
"rfc_id": "rfc_01HX...",
"diff_hash": "9f2c...",
"overall_status": "APPROVED",
"gates": {
"risk": { "status": "pass", "findings": [] },
"ast": { "status": "pass", "findings": [] },
"llm": { "status": "pass", "findings": [] }
}
}
Note the rfc_id and diff_hash — both identify this exact change.
Step 2 — Read the RFC back¶
curl -s http://localhost:3011/api/cra/rfc/rfc_01HX... \
-H "Authorization: Bearer $CRA_API_TOKEN" | jq '.overall_status'
Expected:
Always read the status back
Do not assume the POST response is the final word — for longer diffs analysis may still be in progress (DRAFT). Poll GET /api/cra/rfc/<id> until overall_status is terminal (APPROVED, BLOCKED, or OVERRIDDEN).
Step 3 — Submit a risky diff and watch it block¶
This diff hardcodes a secret and shells out with interpolated input — Gate 1 and/or Gate 2 should fire:
curl -s -X POST http://localhost:3011/api/cra/analyze \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $CRA_API_TOKEN" \
-d '{
"repo_name": "demo",
"branch": "feature/x",
"commit_message": "add deploy helper",
"diff": "--- a/deploy.js\n+++ b/deploy.js\n@@\n+const AWS_SECRET = \"AKIAIOSFODNN7EXAMPLE\";\n+require(\"child_process\").exec(\"rm -rf \" + req.query.path);\n"
}' | jq
Expected (abridged):
{
"rfc_id": "rfc_01HY...",
"overall_status": "BLOCKED",
"gates": {
"risk": {
"status": "fail",
"findings": [
{ "id": "secret-aws-access-key", "severity": "critical", "line": 1 },
{ "id": "vuln-command-injection", "severity": "high", "line": 2 }
]
}
}
}
This RFC is now BLOCKED. A CI/pre-receive gate keyed on this RFC would refuse the change.
Step 4 — Decide what to do with a block¶
You have two honest options:
- Fix the code and submit the new diff (a new RFC).
- Override the block with a recorded reason, if it is a false positive or an accepted risk. See Block and override.
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
401 Unauthorized |
Auth on but token missing/wrong | Send Authorization: Bearer $CRA_API_TOKEN |
overall_status stays DRAFT |
Analysis still running (Gate 3 slow) | Poll GET /api/cra/rfc/<id>; check LLM tier reachability |
Clean diff returns BLOCKED |
An overly broad custom rule in MERIDIAN_RULES_PATH |
Review your rules; see Rules schema |
400 Bad Request |
Malformed JSON / unescaped newlines in diff |
Ensure diff is a JSON string with \n escapes |
Next: Health check in depth or wire it into CI.