Ship CLI proof receipts#114
Conversation
📝 WalkthroughWalkthroughRelease 0.3.5 introduces comprehensive proof-receipt enhancements: the CLI gathers expanded run metrics (budget, verification steps, runtime, event timeline), the data model is extended with derived verdict and context fields, and the SVG renderer is rewritten for dark terminal-style visual presentation with metrics sections and event-rail visualization. Complete test coverage validates the new fields, visual constraints, and verdict states. Documentation guides users through receipt generation and specifies design constraints. ChangesProof Receipt 0.3.5 Release
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request upgrades MartinLoop to version 0.3.5, introducing redesigned terminal-style CLI proof receipts and SVG proof cards. The changes add detailed metrics (such as remaining budget, overspend ratio, and verification steps), run context, and an event rail to the proof cards, while updating documentation and tests to reflect these visual and structural enhancements. A review comment identifies a potential runtime TypeError in packages/cli/src/index.ts when accessing payload properties without a truthiness check, and provides a code suggestion to resolve it.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| : loop.events | ||
| .map((event) => event.payload) | ||
| .find((payload) => typeof payload["adapterId"] === "string" || typeof payload["model"] === "string"); |
There was a problem hiding this comment.
If loop.events contains any event with an undefined or null payload, loop.events.map(event => event.payload) will include undefined or null in the resulting array. When .find() iterates over this array, it will pass undefined or null to the callback, causing a TypeError: Cannot read properties of undefined (reading 'adapterId') when attempting to access payload['adapterId']. Adding a truthiness check for payload prevents this potential runtime crash.
| : loop.events | |
| .map((event) => event.payload) | |
| .find((payload) => typeof payload["adapterId"] === "string" || typeof payload["model"] === "string"); | |
| : loop.events | |
| .map((event) => event.payload) | |
| .find((payload) => payload && (typeof payload["adapterId"] === "string" || typeof payload["model"] === "string")); |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/cli/src/proof-card.ts (1)
87-94:⚠️ Potential issue | 🟠 Major | ⚡ Quick winTreat missing receipt integrity as an evidence boundary.
undefinedcurrently counts as trustworthy, and the integrity row is omitted entirely, so any caller that forgets to populatereceiptIntegrityStatecan still getcompleteEvidence = trueandproofVerdict = "VERIFIED".defaultChallengeProofCardInput()currently does exactly that, which means the built-in demo receipt can advertise verified proof with unknown integrity.Suggested fix
export function buildMartinProofCard(input: MartinProofCardInput): MartinProofCard { + const receiptIntegrityState = input.receiptIntegrityState ?? "unsigned"; const generatedAt = sanitizeText(input.generatedAt); const evidenceBoundaryNotes = typeof input.evidenceBoundaryNotes === "string" ? sanitizeText(input.evidenceBoundaryNotes) : input.evidenceBoundaryNotes.map((note) => sanitizeText(note)).join("; "); @@ - ...(input.receiptIntegrityState - ? [ - { - label: FIELD_LABELS.receiptIntegrityState, - value: sanitizeText(input.receiptIntegrityState) - } - ] - : []), + { + label: FIELD_LABELS.receiptIntegrityState, + value: sanitizeText(receiptIntegrityState) + }, @@ - const trustworthyReceipt = - input.receiptIntegrityState === undefined || input.receiptIntegrityState === "verified"; + const trustworthyReceipt = receiptIntegrityState === "verified"; @@ proofVerdict: deriveProofVerdict({ completeEvidence, status: input.status, lifecycle: input.lifecycle, verifierStatus: input.verifierStatus, - receiptIntegrityState: input.receiptIntegrityState + receiptIntegrityState }),Also applies to: 109-139
🤖 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 `@packages/cli/src/proof-card.ts` around lines 87 - 94, The receiptIntegrityState must be treated as an evidence boundary instead of being omitted when undefined: update the code that builds the proof card rows (the conditional around input.receiptIntegrityState that currently pushes {label: FIELD_LABELS.receiptIntegrityState, value: sanitizeText(input.receiptIntegrityState)}) so that the integrity row is always included; set its value to a safe sentinel like sanitizeText(input.receiptIntegrityState ?? "UNKNOWN" or "MISSING") (and make the same change in the other occurrence around lines 109-139), so callers that omit receiptIntegrityState will get an explicit "UNKNOWN"/"MISSING" row rather than silently appearing as verified.
🧹 Nitpick comments (2)
docs/release/VERSION-LEDGER.md (1)
7-8: ⚡ Quick winClarify temporal language in version ledger.
Lines 7-8 use "before the
0.3.5proof receipt release publishes" which will become stale and confusing once this branch merges and 0.3.5 is released. Version ledgers typically describe current state or use conditional language. Consider either removing the "before" clause or updating these lines post-release to reflect the live state.📝 Suggested alternative wording
-- live npm dist-tag `latest`: `0.3.4` before the `0.3.5` proof receipt release publishes -- live public GitHub release: `v0.3.4` before the `v0.3.5` release workflow completes +- live npm dist-tag `latest`: `0.3.5` (updated after proof receipt release) +- live public GitHub release: `v0.3.5` (updated after release workflow completes)Or simply:
-- live npm dist-tag `latest`: `0.3.4` before the `0.3.5` proof receipt release publishes -- live public GitHub release: `v0.3.4` before the `v0.3.5` release workflow completes +- live npm dist-tag `latest`: `0.3.5` +- live public GitHub release: `v0.3.5`🤖 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 `@docs/release/VERSION-LEDGER.md` around lines 7 - 8, Update the two lines that read "live npm dist-tag `latest`: `0.3.4` before the `0.3.5` proof receipt release publishes" and "live public GitHub release: `v0.3.4` before the `v0.3.5` release workflow completes" to remove the temporal "before..." wording; either state the current state explicitly (e.g., "live npm dist-tag `latest`: `0.3.4`" and "live public GitHub release: `v0.3.4`") or use conditional phrasing (e.g., "live npm dist-tag `latest`: `0.3.4` (prior to publishing v0.3.5)" / "live public GitHub release: `v0.3.4` (prior to v0.3.5 release)"), updating the lines containing the exact phrases "live npm dist-tag `latest`" and "live public GitHub release: `v0.3.4`".docs/examples/proof-receipts/live-governed-run-receipt.json (1)
15-15: ⚡ Quick winClarify "runtime" field semantics.
The
runtimefield contains model/provider information ("claude / claude-sonnet-4-6 / agent-cli:claude") rather than execution duration, which could confuse users expecting time metrics. Consider renaming this field toprovider,model, orexecution_context, or adding a duration-basedruntimefield alongside model information.🤖 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 `@docs/examples/proof-receipts/live-governed-run-receipt.json` at line 15, The "runtime" JSON field currently holds model/provider info ("claude / claude-sonnet-4-6 / agent-cli:claude") which is misleading; update the schema and example by renaming the "runtime" key to a clearer identifier such as "model" or "provider" (or add an additional "execution_context" key), and if you need to record elapsed time also add a separate duration field (e.g., "runtime_ms" or "duration_ms"). Modify the JSON example to replace "runtime" with the chosen name (or include both the new model/provider key and a numeric duration key) and update any consumers/tests/docs that reference the "runtime" key accordingly.
🤖 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 `@docs/examples/proof-receipts/live-governed-run-receipt.json`:
- Around line 1-17: Replace the mismatched fields to match the proof-card
schema: rename receiptIntegrity -> receiptIntegrityState, verificationSteps ->
verificationStepCount (use a number), rollback -> rollbackStatus, and verifier
-> verifierStatus; set receiptIntegrityState to one of the allowed values
("verified" | "unsigned" | "tamper_detected") (e.g., "verified" instead of
"signed"); update verifierStatus values to the schema's expected values; add the
missing proof-card fields present in the markdown example (Objective, Status,
Lifecycle, Halt reason, Evidence boundary, Run mode) with appropriate
schema-compliant keys and values, ensure types match the schema (e.g.,
verificationStepCount as an integer) and keep existing metadata like generatedAt
and budget fields unchanged.
In `@docs/examples/proof-receipts/live-governed-run-receipt.md`:
- Line 21: The "Run mode" table row uses "not recorded" but the JSON example
uses "not-recorded" for the rollback value; update the table cell (the Run mode
/ rollback entry) to use "not-recorded" to match the JSON example and maintain
consistent formatting across examples (refer to the rollback field and the Run
mode table row in the document).
In `@packages/cli/src/index.ts`:
- Around line 3007-3009: The computed metric named overspendRatio is actually
actualUsd/maxUsd (so values <1 indicate under budget); update the logic to
either (A) rename the variable to spendRatio (e.g., spendRatio =
loop.budget.maxUsd > 0 ? `${(loop.cost.actualUsd /
loop.budget.maxUsd).toFixed(2)}x` : "unknown" and use that where you mean
"budget utilization"), or (B) keep overspendRatio but only compute/emit it when
loop.cost.actualUsd > loop.budget.maxUsd (e.g., overspendRatio =
loop.cost.actualUsd > loop.budget.maxUsd ? `${(loop.cost.actualUsd /
loop.budget.maxUsd).toFixed(2)}x` : undefined/"0x"). Apply the same change for
the second occurrence using the same symbols (remainingBudget, overspendRatio,
loop.cost.actualUsd, loop.budget.maxUsd).
---
Outside diff comments:
In `@packages/cli/src/proof-card.ts`:
- Around line 87-94: The receiptIntegrityState must be treated as an evidence
boundary instead of being omitted when undefined: update the code that builds
the proof card rows (the conditional around input.receiptIntegrityState that
currently pushes {label: FIELD_LABELS.receiptIntegrityState, value:
sanitizeText(input.receiptIntegrityState)}) so that the integrity row is always
included; set its value to a safe sentinel like
sanitizeText(input.receiptIntegrityState ?? "UNKNOWN" or "MISSING") (and make
the same change in the other occurrence around lines 109-139), so callers that
omit receiptIntegrityState will get an explicit "UNKNOWN"/"MISSING" row rather
than silently appearing as verified.
---
Nitpick comments:
In `@docs/examples/proof-receipts/live-governed-run-receipt.json`:
- Line 15: The "runtime" JSON field currently holds model/provider info ("claude
/ claude-sonnet-4-6 / agent-cli:claude") which is misleading; update the schema
and example by renaming the "runtime" key to a clearer identifier such as
"model" or "provider" (or add an additional "execution_context" key), and if you
need to record elapsed time also add a separate duration field (e.g.,
"runtime_ms" or "duration_ms"). Modify the JSON example to replace "runtime"
with the chosen name (or include both the new model/provider key and a numeric
duration key) and update any consumers/tests/docs that reference the "runtime"
key accordingly.
In `@docs/release/VERSION-LEDGER.md`:
- Around line 7-8: Update the two lines that read "live npm dist-tag `latest`:
`0.3.4` before the `0.3.5` proof receipt release publishes" and "live public
GitHub release: `v0.3.4` before the `v0.3.5` release workflow completes" to
remove the temporal "before..." wording; either state the current state
explicitly (e.g., "live npm dist-tag `latest`: `0.3.4`" and "live public GitHub
release: `v0.3.4`") or use conditional phrasing (e.g., "live npm dist-tag
`latest`: `0.3.4` (prior to publishing v0.3.5)" / "live public GitHub release:
`v0.3.4` (prior to v0.3.5 release)"), updating the lines containing the exact
phrases "live npm dist-tag `latest`" and "live public GitHub release: `v0.3.4`".
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 90b8b051-61d8-4ef6-883b-0f1d9ac4f750
⛔ Files ignored due to path filters (1)
docs/assets/proof-receipt-live-governed.pngis excluded by!**/*.png
📒 Files selected for processing (14)
AGENTS.mdREADME.mddocs/examples/proof-receipts/live-governed-run-receipt.jsondocs/examples/proof-receipts/live-governed-run-receipt.mddocs/oss/AGENT-RUN-RECEIPTS.mddocs/oss/AGENT-START-HERE.mddocs/release/OSS-0.3.5-RELEASE-NOTES.mddocs/release/VERSION-LEDGER.mdpackage.jsonpackages/cli/src/index.tspackages/cli/src/proof-card.tspackages/cli/tests/operator-commands.test.tspackages/cli/tests/proof-card.test.tsscripts/root-release-guard.mjs
| { | ||
| "title": "Martin Loop Proof Receipt", | ||
| "loopId": "loop_82emkgkf", | ||
| "proofVerdict": "EVIDENCE_BOUNDARY", | ||
| "evidenceLine": "Incomplete Martin proof: missing budget, rollback, or verifier evidence.", | ||
| "verifier": "passed", | ||
| "costSpend": "$0.51", | ||
| "budget": "$3.00", | ||
| "remainingBudget": "$2.49", | ||
| "overspendRatio": "0.17x", | ||
| "attempts": "1", | ||
| "rollback": "not-recorded", | ||
| "receiptIntegrity": "signed", | ||
| "verificationSteps": "1", | ||
| "runtime": "claude / claude-sonnet-4-6 / agent-cli:claude", | ||
| "generatedAt": "2026-06-10T20:01:03.635Z" | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Find the JSON serialization logic for proof receipts and verify field naming
# Search for JSON receipt generation/serialization
rg -nP --type=ts -C5 'run-receipt\.json|JSON\.stringify.*proof|toJSON.*receipt'
# Search for the mapping between interface fields and output JSON
ast-grep --pattern 'receiptIntegrity'Repository: Keesan12/martin-loop
Length of output: 787
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find the MartinProofCardInput interface (or equivalent) and its field names
rg -n --type=ts 'interface\s+MartinProofCardInput|type\s+MartinProofCardInput|MartinProofCardInput\s*<' .
# 2) Find where the receipt JSON fields are defined/serialized
rg -n --type=ts 'function\s+buildShareBundle|buildShareBundle\(|shareBundle\.receipt|receipt:\s*' packages/cli/src
# 3) Find any usage of these specific field keys in codegen/rendering
rg -n --type=ts '"receiptIntegrityState"|"verificationStepCount"|"receiptIntegrity"|"verificationSteps"|"costSpend"|"remainingBudget"' packages
# 4) Find the MD example table that the JSON might be mirroring
fd -e md -a . | head -n 200
fd -e md . | rg -n 'proof-receipts|live-governed-run-receipt|Martin'Repository: Keesan12/martin-loop
Length of output: 1314
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show MartinProofCardInput interface
echo "---- packages/cli/src/proof-card.ts (MartinProofCardInput) ----"
sed -n '1,220p' packages/cli/src/proof-card.ts | nl -ba | sed -n '1,220p'
# Show receipt construction path (buildShareBundle) around the receipt assignment
echo
echo "---- packages/cli/src/index.ts (buildShareBundle receipt) ----"
sed -n '3080,3245p' packages/cli/src/index.ts | nl -ba
# Show CliWorkflowReceipt type / receipt shape (workflow-state.ts)
echo
echo "---- packages/cli/src/workflow-state.ts (CliWorkflowReceipt) ----"
rg -n 'type\s+CliWorkflowReceipt|interface\s+CliWorkflowReceipt|export\s+type\s+CliWorkflowReceipt|export\s+interface\s+CliWorkflowReceipt' packages/cli/src/workflow-state.ts
sed -n '1,220p' packages/cli/src/workflow-state.ts | nl -ba | sed -n '1,220p'
# Locate the MD example file for proof receipts and show the relevant table/field names
echo
echo "---- Find proof receipt docs examples ----"
fd -a docs -e md | rg -n 'proof-receipts|live-governed-run-receipt|Martin Loop Proof Receipt|Martin proof receipt' || true
# Specifically print the MD file if present
mdfile="$(fd -a docs -e md -i | rg -n 'proof-receipts|live-governed-run-receipt' | head -n 1 | cut -d: -f1 || true)"
if [ -n "${mdfile:-}" ]; then
echo
echo "---- $mdfile (excerpt) ----"
sed -n '1,220p' "$mdfile" | nl -ba
fi
# Finally: inspect the specific JSON file in question
echo
echo "---- docs/examples/proof-receipts/live-governed-run-receipt.json ----"
sed -n '1,120p' docs/examples/proof-receipts/live-governed-run-receipt.json | nl -baRepository: Keesan12/martin-loop
Length of output: 189
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- packages/cli/src/proof-card.ts (MartinProofCardInput) ----"
cat -n packages/cli/src/proof-card.ts | sed -n '1,240p'
echo
echo "---- packages/cli/src/index.ts (buildShareBundle receipt) ----"
cat -n packages/cli/src/index.ts | sed -n '3060,3225p'
echo
echo "---- packages/cli/src/workflow-state.ts (CliWorkflowReceipt) ----"
rg -n 'CliWorkflowReceipt' packages/cli/src/workflow-state.ts
echo
# show the definition region if present
start="$(rg -n 'CliWorkflowReceipt' packages/cli/src/workflow-state.ts | head -n 1 | cut -d: -f1 | awk '{print $1}')"
if [ -n "${start:-}" ]; then
s=$((start-40))
if [ $s -lt 1 ]; then s=1; fi
cat -n packages/cli/src/workflow-state.ts | sed -n "${s},$((s+220))p"
fi
echo
echo "---- docs/examples/proof-receipts (find relevant MD/JSON) ----"
fd -a docs/examples/proof-receipts -e md -e json
echo
mdfile="$(fd -a docs -e md | rg -n 'proof-receipts|live-governed-run-receipt|Martin Loop Proof Receipt' | head -n 1 | cut -d: -f1 || true)"
if [ -n "${mdfile:-}" ]; then
echo "---- $mdfile (excerpt) ----"
cat -n "$mdfile" | sed -n '1,260p'
fi
echo
echo "---- docs/examples/proof-receipts/live-governed-run-receipt.json ----"
cat -n docs/examples/proof-receipts/live-governed-run-receipt.json | sed -n '1,140p'Repository: Keesan12/martin-loop
Length of output: 28217
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find and print proofCardInputFromLoop (or similarly named function)
echo "---- Search for proofCardInputFromLoop ----"
rg -n --type=ts 'proofCardInputFromLoop' packages/cli/src
func_file="$(rg -n --type=ts 'proofCardInputFromLoop' packages/cli/src | head -n1 | cut -d: -f1 || true)"
if [ -n "${func_file:-}" ]; then
echo "---- snippet around ${func_file} ----"
# print a reasonable region around the first match line
match_line="$(rg -n --type=ts 'proofCardInputFromLoop' packages/cli/src | head -n1 | cut -d: -f2)"
start=$((match_line-80)); if [ $start -lt 1 ]; then start=1; fi
end=$((match_line+120))
sed -n "${start},${end}p" "$func_file" | cat -n
fi
# 2) Read the JSON example in question (with line numbers)
echo
echo "---- docs/examples/proof-receipts/live-governed-run-receipt.json ----"
cat -n docs/examples/proof-receipts/live-governed-run-receipt.json | sed -n '1,200p'
# 3) Find the corresponding Markdown file/table (if it exists)
echo
echo "---- Find docs markdown references to 'Martin Loop Proof Receipt' and 'live-governed-run-receipt' ----"
rg -n --type=md 'Martin Loop Proof Receipt|live-governed-run-receipt|proof-receipts' docs || true
# If any MD file exists under docs/examples/proof-receipts, list them
echo
echo "---- List docs/examples/proof-receipts directory (if present) ----"
ls -la docs/examples/proof-receipts 2>/dev/null || true
# Print all md files under that folder (small output only)
for f in $(ls docs/examples/proof-receipts 2>/dev/null | rg '\.md$' || true); do
echo
echo "---- docs/examples/proof-receipts/$f (excerpt) ----"
cat -n "docs/examples/proof-receipts/$f" | sed -n '1,240p'
doneRepository: Keesan12/martin-loop
Length of output: 11988
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n --hidden --type=ts '"verificationSteps"\s*:' . || true
rg -n --hidden --type=ts '"receiptIntegrity"\s*:' . || true
rg -n --hidden --type=ts '"verifier"\s*:' . || true
rg -n --hidden --type=ts '"rollback"\s*:' . || true
rg -n --hidden --type=ts 'verificationStepCount|receiptIntegrityState' packages/cli/src || true
# also check for a renderer that flattens MartinProofCard fields into JSON-like objects
rg -n --hidden --type=ts 'render.*Proof.*json|Proof.*json|toJSON.*receipt|share-receipt|run-receipt\.json' packages/cli/src || trueRepository: Keesan12/martin-loop
Length of output: 1985
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find the ReceiptIntegrityState definition/value set
rg -n --hidden --type=ts 'ReceiptIntegrityState' . | head -n 200
# 2) Find where CLI outputs JSON for proof cards (flattened vs structured)
rg -n --hidden --type=ts 'proofVerdict|EVIDENCE_BOUNDARY|verificationSteps|receiptIntegrity"\s*:|\"receiptIntegrity\"|\"verificationSteps\"' packages/cli/src || true
# 3) Locate any renderer that produces the flat keys seen in the docs example
rg -n --hidden --type=ts 'verifier"\s*:?|rollback"\s*:?|verificationSteps|receiptIntegrity' packages/cli/src || true
# 4) Find docs example generator references (if any)
rg -n --hidden --type=md 'live-governed-run-receipt' docs || trueRepository: Keesan12/martin-loop
Length of output: 3645
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Flattened key strings as they appear in docs example JSON
rg -n --hidden --type=ts '"receiptIntegrity"\s*:|receiptIntegrity"\s*\)|receiptIntegrity'\''|\"receiptIntegrity\"' packages/cli/src || true
rg -n --hidden --type=ts '"verificationSteps"\s*:|\"verificationSteps\"' packages/cli/src || true
rg -n --hidden --type=ts '"runtime"\s*:|\"runtime\"' packages/cli/src | head -n 50 || true
rg -n --hidden --type=ts '"rollback"\s*:|\"rollback\"' packages/cli/src || true
rg -n --hidden --type=ts '"verifier"\s*:|\"verifier\"' packages/cli/src || true
# Also search for docs file generator / mapping from card.fields -> flat object
rg -n --hidden --type=ts 'fields.*reduce|getFieldValue|card\.fields|buildMartinProofCard|Proof Receipt' packages/cli/src || trueRepository: Keesan12/martin-loop
Length of output: 1617
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Fixed-string searches for the flattened keys present in docs example JSON
rg -n --hidden -F '"receiptIntegrity"' packages/cli/src || true
rg -n --hidden -F '"verificationSteps"' packages/cli/src || true
rg -n --hidden -F '"rollback"' packages/cli/src || true
rg -n --hidden -F '"verifier"' packages/cli/src || true
rg -n --hidden -F '"runtime"' packages/cli/src || true
# Also search for outputting "Martin Loop Proof Receipt" JSON
rg -n --hidden -S 'Martin Loop Proof Receipt' packages/cli/src || true
rg -n --hidden -S 'run-receipt.json' packages/cli/src || true
rg -n --hidden -S 'receiptJson|receiptMarkdown|proofCardSvg' packages/cli/src || true
# Search for docs markdown generator that might produce flat receipt JSON
rg -n --hidden -S 'renderShareReceiptMarkdown|render.*Receipt' packages/cli/src || trueRepository: Keesan12/martin-loop
Length of output: 1645
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find where proofVerdict / evidenceLine are used in JSON-ish outputs
rg -n --hidden --type=ts '"proofVerdict"' packages/cli/src || true
rg -n --hidden --type=ts '"evidenceLine"' packages/cli/src || true
rg -n --hidden --type=ts 'renderMartinProofCardMarkdown|renderMartinProofCardSvg' packages/cli/src || true
# Find CLI command handlers that return JSON for proofs/cards
rg -n --hidden --type=ts 'execute.*Command|command\.format|format === "json"|outputMode' packages/cli/src || true
# Specifically check for "runs verify" / "verify" command implementations
rg -n --hidden --type=ts 'runs verify|execute.*verify|verify\b' packages/cli/src || true
# Search docs generator or tests for snapshot of this JSON
rg -n --hidden --type=ts 'live-governed-run-receipt|run-receipt\.json|proof-receipts' packages/cli/tests packages/cli/src docs || trueRepository: Keesan12/martin-loop
Length of output: 11381
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search for flattened doc-example keys/values across repo
rg -n --hidden -S 'verificationSteps' . || true
rg -n --hidden -S 'receiptIntegrity' . || true
rg -n --hidden -S '"signed"' . || true
# See how the doc example JSON is referenced/produced
rg -n --hidden -S 'live-governed-run-receipt\.json' . || true
rg -n --hidden -S 'live-governed-run-receipt\.md' . || trueRepository: Keesan12/martin-loop
Length of output: 6023
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- docs/oss/AGENT-RUN-RECEIPTS.md (excerpt around receiptIntegrity / example schema) ----"
rg -n 'receiptIntegrity|verificationSteps|verificationStepCount|run-receipt\.json|live-governed-run-receipt\.json' docs/oss/AGENT-RUN-RECEIPTS.md
sed -n '1,120p' docs/oss/AGENT-RUN-RECEIPTS.md | cat -n
sed -n '120,220p' docs/oss/AGENT-RUN-RECEIPTS.md | cat -n
echo
echo "---- docs/examples/proof-receipts/live-governed-run-receipt.md (whole file) ----"
cat -n docs/examples/proof-receipts/live-governed-run-receipt.md
echo
echo "---- README.md (receipt example section) ----"
sed -n '90,140p' README.md | cat -nRepository: Keesan12/martin-loop
Length of output: 10223
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show executeRunsVerifyCommand
echo "---- executeRunsVerifyCommand (packages/cli/src/index.ts) ----"
sed -n '1840,1925p' packages/cli/src/index.ts | cat -n
echo
echo "---- executeShareCommand around JSON output (packages/cli/src/index.ts) ----"
sed -n '3060,3188p' packages/cli/src/index.ts | cat -n
echo
echo "---- executeBadgeCommand around json formatting (packages/cli/src/index.ts) ----"
sed -n '3280,3360p' packages/cli/src/index.ts | cat -nRepository: Keesan12/martin-loop
Length of output: 13288
Fix live-governed-run-receipt.json field names/value to match the proof-card schema
docs/examples/proof-receipts/live-governed-run-receipt.jsonusesreceiptIntegrity,verificationSteps,rollback, andverifier, but the proof-card input schema usesreceiptIntegrityState,verificationStepCount,rollbackStatus, andverifierStatus.- The example sets
receiptIntegrityto"signed", butReceiptIntegrityStateis only"verified" | "unsigned" | "tamper_detected". - The JSON example omits fields that are present in
docs/examples/proof-receipts/live-governed-run-receipt.md(Objective, Status, Lifecycle, Halt reason, Evidence boundary, Run mode), so the JSON doesn’t mirror the documented proof card.
🤖 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 `@docs/examples/proof-receipts/live-governed-run-receipt.json` around lines 1 -
17, Replace the mismatched fields to match the proof-card schema: rename
receiptIntegrity -> receiptIntegrityState, verificationSteps ->
verificationStepCount (use a number), rollback -> rollbackStatus, and verifier
-> verifierStatus; set receiptIntegrityState to one of the allowed values
("verified" | "unsigned" | "tamper_detected") (e.g., "verified" instead of
"signed"); update verifierStatus values to the schema's expected values; add the
missing proof-card fields present in the markdown example (Objective, Status,
Lifecycle, Halt reason, Evidence boundary, Run mode) with appropriate
schema-compliant keys and values, ensure types match the schema (e.g.,
verificationStepCount as an integer) and keep existing metadata like generatedAt
and budget fields unchanged.
| | Remaining budget | $2.49 | | ||
| | Overspend ratio | 0.17x | | ||
| | Verification steps | 1 | | ||
| | Run mode | not recorded | |
There was a problem hiding this comment.
Inconsistent value format with JSON example.
Line 21 shows "not recorded" (space-separated) while the JSON example uses "not-recorded" (hyphenated) for the rollback field. Ensure consistent formatting across example formats.
🔧 Proposed fix for consistency
-| Run mode | not recorded |
+| Run mode | not-recorded |📝 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.
| | Run mode | not recorded | | |
| | Run mode | not-recorded | |
🤖 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 `@docs/examples/proof-receipts/live-governed-run-receipt.md` at line 21, The
"Run mode" table row uses "not recorded" but the JSON example uses
"not-recorded" for the rollback value; update the table cell (the Run mode /
rollback entry) to use "not-recorded" to match the JSON example and maintain
consistent formatting across examples (refer to the rollback field and the Run
mode table row in the document).
| const remainingBudget = Math.max(0, loop.budget.maxUsd - loop.cost.actualUsd); | ||
| const overspendRatio = | ||
| loop.budget.maxUsd > 0 ? `${(loop.cost.actualUsd / loop.budget.maxUsd).toFixed(2)}x` : "unknown"; |
There was a problem hiding this comment.
Rename or recompute the new "overspend ratio" metric.
This is actualUsd / maxUsd, so in-budget runs now emit values like 0.77x. The receipt later renders that under the "Overspend ratio" label, which reads as though the run exceeded budget when it did not. Either rename the field to budget utilization/spend ratio, or only emit an overspend metric once actualUsd > maxUsd.
Also applies to: 3059-3060
🤖 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 `@packages/cli/src/index.ts` around lines 3007 - 3009, The computed metric
named overspendRatio is actually actualUsd/maxUsd (so values <1 indicate under
budget); update the logic to either (A) rename the variable to spendRatio (e.g.,
spendRatio = loop.budget.maxUsd > 0 ? `${(loop.cost.actualUsd /
loop.budget.maxUsd).toFixed(2)}x` : "unknown" and use that where you mean
"budget utilization"), or (B) keep overspendRatio but only compute/emit it when
loop.cost.actualUsd > loop.budget.maxUsd (e.g., overspendRatio =
loop.cost.actualUsd > loop.budget.maxUsd ? `${(loop.cost.actualUsd /
loop.budget.maxUsd).toFixed(2)}x` : undefined/"0x"). Apply the same change for
the second occurrence using the same symbols (remainingBudget, overspendRatio,
loop.cost.actualUsd, loop.budget.maxUsd).
Summary
martin-looppackage to 0.3.5 and documents the releaseValidation
pnpm --filter @martin/cli test -- proof-card.test.tspnpm --filter @martin/cli test -- operator-commands.test.ts -t "writes a shareable receipt bundle"node --test scripts/tests/readme-public-surface.test.mjspnpm public:copy-scanpnpm --filter @martin/cli lintpnpm --filter @martin/cli buildpnpm public:git-surfacepnpm oss:validatepnpm public:smokepnpm lintpnpm testpnpm buildpnpm release:validate-localpnpm release:root:guardpnpm release:validate:platformsRelease
After merge, tag
v0.3.5and let the root release workflow publishmartin-loop@0.3.5through GitHub Actions trusted publishing.Summary by CodeRabbit
New Features
runs verify --latestandshare --latestfor generating shareable receipt bundles (JSON, Markdown, SVG)Documentation
Tests
Chores