-
Notifications
You must be signed in to change notification settings - Fork 5
feat(supervisor): structured proof-logs for task completion trust (t218) #921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
… (t218) Adds a proof_logs SQLite table and write_proof_log() function that records immutable evidence at each supervisor decision point. This creates a structured audit trail answering 'why was this task marked complete?' Schema: proof_logs(task_id, event, stage, decision, evidence, decision_maker, pr_url, duration_secs, metadata, timestamp) Instrumented decision points: - evaluate_worker outcome (with evaluation tier used) - complete/retry/blocked/failed decisions in pulse Phase 1 - quality gate escalation - deliverable verification (PR merged + substantive files) - post-merge verify pass/fail (VERIFY.md checks) - lifecycle stage transitions (dispatch, pr_review, merge, deploy, verify) Query interface: supervisor-helper.sh proof-log <task_id> [--json|--timeline] --recent [N] Show recent entries across all tasks --stats Aggregate statistics (event counts, avg stage durations) --timeline Stage timing timeline with durations (t219 prep) Stage timing: _proof_log_stage_duration() calculates elapsed time between proof-log entries, enabling pipeline latency analysis for t219. Design decisions: - Best-effort writes (never block pipeline on proof-log failure) - Immutable append-only (no UPDATE/DELETE on proof_logs) - Auto-migration for existing databases via ensure_db() - Follows existing patterns: local var=$1, explicit returns, sql_escape()
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
WalkthroughThis PR implements a structured proof-log audit trail system (t218) for task verification. It introduces a SQLite Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Tue Feb 10 05:42:14 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In @.agents/scripts/supervisor-helper.sh:
- Around line 1808-1819: The stage duration is being calculated by
_proof_log_stage_duration using "$current_state" but then written to
write_proof_log under stage "$new_state", shifting timing one stage forward; to
fix, ensure the duration is attributed to the same stage you calculate — either
call _proof_log_stage_duration with "$new_state" if you intend to measure the
upcoming stage, or (preferably) keep the current call with "$current_state" and
change the write_proof_log --stage argument to "$current_state" so the --stage
value matches the computed _stage_duration; update the invocation around
_proof_log_stage_duration, write_proof_log, and the variables
task_id/current_state/new_state accordingly.
- Around line 10783-10789: The --limit handling currently assigns limit_n from
the next arg without validation; add a numeric check using the same regex
/^[0-9]+$/ that the positional argument uses and reject or default if it fails.
Specifically, after the argument-parsing loop that sets limit_n (the --limit
branch in the case block) and before the main case "$mode" block, validate
limit_n with the regex and if it does not match set limit_n to a safe default
(e.g., 20) or exit with an error, ensuring LIMIT $limit_n in SQL only ever
receives numeric input.
- Around line 10860-10874: The code builds JSON using manual escaping of
evidence/meta via _esc_evidence and _esc_meta which only replaces quotes and
leaves newlines, backslashes, tabs, etc., unescaped; replace that logic by
passing the raw pevidence and pmeta through the existing JSON escaper `jq -Rs .`
(e.g., set _esc_evidence=$(printf '%s' "$pevidence" | jq -Rs .) and similarly
for _esc_meta) and then use those values in the printf that constructs the
object (update the printf placeholders to accept the jq-escaped strings as-is);
apply the same change to the other block around lines 10949-10963 that uses
_esc_evidence/_esc_meta.
- Around line 323-330: The proof log insertion currently interpolates $duration
directly into the SQL; validate that the value from _proof_log_stage_duration()
(variable duration) is a numeric (integer or float) before using it unquoted,
and if it fails validation treat it as NULL or skip adding duration_secs. Update
the block that builds cols and vals so it first checks duration with a numeric
regex (e.g. /^[0-9]+(\.[0-9]+)?$/) or an arithmetic test, only appends
"duration_secs" and the numeric value to cols/vals when valid, and otherwise
either omit the column or insert NULL (ensuring the SQL value is quoted/escaped
consistently). Also keep the existing metadata handling and the db "INSERT INTO
proof_logs (...) VALUES (...)" invocation unchanged except for using the
validated/quoted duration variable.
| if [[ -n "$duration" ]]; then | ||
| cols="$cols, duration_secs"; vals="$vals, $duration" | ||
| fi | ||
| if [[ -n "$metadata" ]]; then | ||
| cols="$cols, metadata"; vals="$vals, '$e_meta'" | ||
| fi | ||
|
|
||
| db "$SUPERVISOR_DB" "INSERT INTO proof_logs ($cols) VALUES ($vals);" 2>/dev/null || true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n .agents/scripts/supervisor-helper.sh | sed -n '310,340p'Repository: marcusquinn/aidevops
Length of output: 1375
🏁 Script executed:
# Get full context of the write_proof_log function
rg -n "write_proof_log" .agents/scripts/supervisor-helper.sh -A 80 | head -100Repository: marcusquinn/aidevops
Length of output: 3937
🏁 Script executed:
# Check for other numeric field handling patterns in the file
rg -n "duration|limit" .agents/scripts/supervisor-helper.sh | grep -E "(vals|cols|INSERT)" | head -20Repository: marcusquinn/aidevops
Length of output: 128
🏁 Script executed:
# Check where _stage_duration comes from and how it's computed
rg -n "_stage_duration" .agents/scripts/supervisor-helper.sh -B 5 -A 2 | head -60Repository: marcusquinn/aidevops
Length of output: 2799
🏁 Script executed:
# Look for the sql_escape function to understand how text fields are protected
rg -n "sql_escape" .agents/scripts/supervisor-helper.sh -A 8 | head -30Repository: marcusquinn/aidevops
Length of output: 1095
🏁 Script executed:
# Check if there are any tests or validation patterns for numeric fields elsewhere
rg -n "^[0-9]|=~ ^" .agents/scripts/supervisor-helper.sh | grep -E "(regex|validate|numeric)" | head -10Repository: marcusquinn/aidevops
Length of output: 46
🏁 Script executed:
# Get the full _proof_log_stage_duration function to see what it returns
rg -n "_proof_log_stage_duration" .agents/scripts/supervisor-helper.sh -A 30 | head -45Repository: marcusquinn/aidevops
Length of output: 1794
🏁 Script executed:
# Check the db function to understand SQL execution
rg -n "^db()" .agents/scripts/supervisor-helper.sh -A 15Repository: marcusquinn/aidevops
Length of output: 571
🏁 Script executed:
# Check what happens when _proof_log_stage_duration returns empty or invalid
rg -n "local _.*_duration" .agents/scripts/supervisor-helper.sh -B 2 -A 5 | head -40Repository: marcusquinn/aidevops
Length of output: 2174
🏁 Script executed:
# Get the rest of _proof_log_stage_duration to see what it returns
sed -n '341,390p' .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 1397
🏁 Script executed:
# Check if write_proof_log is called from anywhere else with --duration
rg -n "write_proof_log.*--duration" .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 46
🏁 Script executed:
# Verify if there's any validation on duration parameter anywhere in the file
rg -n "duration.*=~|duration.*[0-9]|validate.*duration" .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 634
🏁 Script executed:
# Check for "limit" field mentioned in original scratchpad comments
rg -n "limit.*cols|cols.*limit|vals.*limit" .agents/scripts/supervisor-helper.sh | head -20Repository: marcusquinn/aidevops
Length of output: 46
🏁 Script executed:
# Search for any other unquoted numeric insertions in SQL queries
rg -n "INSERT INTO.*VALUES" .agents/scripts/supervisor-helper.sh -A 2 -B 2 | grep -E "(\$[a-z_]+[^']|, [a-z_]+ [^'])" | head -20Repository: marcusquinn/aidevops
Length of output: 46
🏁 Script executed:
# Verify what ShellCheck would say about unquoted variables in SQL context
cat > /tmp/test_duration.sh << 'EOF'
# Test pattern from supervisor-helper.sh
local duration="$1"
local vals="'value', $duration"
db "INSERT INTO test (col1, col2) VALUES ($vals);"
EOF
# Run shellcheck if available (to understand the pattern)
shellcheck /tmp/test_duration.sh 2>&1 || echo "ShellCheck not available, but checking pattern manually"Repository: marcusquinn/aidevops
Length of output: 724
🏁 Script executed:
# Verify the complete proof_logs schema to understand column types
rg -n "CREATE TABLE proof_logs|duration_secs" .agents/scripts/supervisor-helper.sh -B 3 -A 15 | head -50Repository: marcusquinn/aidevops
Length of output: 2153
🏁 Script executed:
# Final check: see if there are any explicit input validation patterns used elsewhere in the file for numeric values
rg -n "=~ \^[0-9]|numeric|integer" .agents/scripts/supervisor-helper.sh | head -15Repository: marcusquinn/aidevops
Length of output: 199
Validate duration as numeric before SQL interpolation to maintain robust automation standards.
Although _proof_log_stage_duration() currently returns only arithmetic results (guaranteed numeric or empty), inserting duration_secs unquoted into SQL violates defensive coding practices. The guidelines require automation scripts to prioritize robustness, and unquoted dynamic values in SQL are a security anti-pattern. Add validation to future-proof against code changes and maintain A-grade standards.
Suggested fix
- if [[ -n "$duration" ]]; then
- cols="$cols, duration_secs"; vals="$vals, $duration"
- fi
+ if [[ -n "$duration" ]]; then
+ if [[ "$duration" =~ ^[0-9]+$ ]]; then
+ cols="$cols, duration_secs"; vals="$vals, $duration"
+ else
+ log_verbose "proof-log: ignoring non-numeric duration '$duration'"
+ fi
+ fi📝 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.
| if [[ -n "$duration" ]]; then | |
| cols="$cols, duration_secs"; vals="$vals, $duration" | |
| fi | |
| if [[ -n "$metadata" ]]; then | |
| cols="$cols, metadata"; vals="$vals, '$e_meta'" | |
| fi | |
| db "$SUPERVISOR_DB" "INSERT INTO proof_logs ($cols) VALUES ($vals);" 2>/dev/null || true | |
| if [[ -n "$duration" ]]; then | |
| if [[ "$duration" =~ ^[0-9]+$ ]]; then | |
| cols="$cols, duration_secs"; vals="$vals, $duration" | |
| else | |
| log_verbose "proof-log: ignoring non-numeric duration '$duration'" | |
| fi | |
| fi | |
| if [[ -n "$metadata" ]]; then | |
| cols="$cols, metadata"; vals="$vals, '$e_meta'" | |
| fi | |
| db "$SUPERVISOR_DB" "INSERT INTO proof_logs ($cols) VALUES ($vals);" 2>/dev/null || true |
🤖 Prompt for AI Agents
In @.agents/scripts/supervisor-helper.sh around lines 323 - 330, The proof log
insertion currently interpolates $duration directly into the SQL; validate that
the value from _proof_log_stage_duration() (variable duration) is a numeric
(integer or float) before using it unquoted, and if it fails validation treat it
as NULL or skip adding duration_secs. Update the block that builds cols and vals
so it first checks duration with a numeric regex (e.g. /^[0-9]+(\.[0-9]+)?$/) or
an arithmetic test, only appends "duration_secs" and the numeric value to
cols/vals when valid, and otherwise either omit the column or insert NULL
(ensuring the SQL value is quoted/escaped consistently). Also keep the existing
metadata handling and the db "INSERT INTO proof_logs (...) VALUES (...)"
invocation unchanged except for using the validated/quoted duration variable.
| # Proof-log: record lifecycle stage transitions (t218) | ||
| # Only log transitions that represent significant pipeline stages | ||
| # (not every micro-transition, to keep proof-logs focused) | ||
| case "$new_state" in | ||
| dispatched|pr_review|review_triage|merging|merged|deploying|deployed|verifying|verified|verify_failed) | ||
| local _stage_duration | ||
| _stage_duration=$(_proof_log_stage_duration "$task_id" "$current_state") | ||
| write_proof_log --task "$task_id" --event "transition" --stage "$new_state" \ | ||
| --decision "$current_state->$new_state" \ | ||
| --evidence "${error_msg:+error=$error_msg}" \ | ||
| --maker "cmd_transition" \ | ||
| ${pr_url:+--pr-url "$pr_url"} \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stage durations are attributed to the wrong stage.
_proof_log_stage_duration is computed for the current stage, but logged under stage="$new_state", which shifts timings one stage forward in timelines/stats. This undermines the latency analysis objective (t219).
Suggested fix
- write_proof_log --task "$task_id" --event "transition" --stage "$new_state" \
+ write_proof_log --task "$task_id" --event "transition" --stage "$current_state" \
--decision "$current_state->$new_state" \📝 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.
| # Proof-log: record lifecycle stage transitions (t218) | |
| # Only log transitions that represent significant pipeline stages | |
| # (not every micro-transition, to keep proof-logs focused) | |
| case "$new_state" in | |
| dispatched|pr_review|review_triage|merging|merged|deploying|deployed|verifying|verified|verify_failed) | |
| local _stage_duration | |
| _stage_duration=$(_proof_log_stage_duration "$task_id" "$current_state") | |
| write_proof_log --task "$task_id" --event "transition" --stage "$new_state" \ | |
| --decision "$current_state->$new_state" \ | |
| --evidence "${error_msg:+error=$error_msg}" \ | |
| --maker "cmd_transition" \ | |
| ${pr_url:+--pr-url "$pr_url"} \ | |
| # Proof-log: record lifecycle stage transitions (t218) | |
| # Only log transitions that represent significant pipeline stages | |
| # (not every micro-transition, to keep proof-logs focused) | |
| case "$new_state" in | |
| dispatched|pr_review|review_triage|merging|merged|deploying|deployed|verifying|verified|verify_failed) | |
| local _stage_duration | |
| _stage_duration=$(_proof_log_stage_duration "$task_id" "$current_state") | |
| write_proof_log --task "$task_id" --event "transition" --stage "$current_state" \ | |
| --decision "$current_state->$new_state" \ | |
| --evidence "${error_msg:+error=$error_msg}" \ | |
| --maker "cmd_transition" \ | |
| ${pr_url:+--pr-url "$pr_url"} \ |
🤖 Prompt for AI Agents
In @.agents/scripts/supervisor-helper.sh around lines 1808 - 1819, The stage
duration is being calculated by _proof_log_stage_duration using "$current_state"
but then written to write_proof_log under stage "$new_state", shifting timing
one stage forward; to fix, ensure the duration is attributed to the same stage
you calculate — either call _proof_log_stage_duration with "$new_state" if you
intend to measure the upcoming stage, or (preferably) keep the current call with
"$current_state" and change the write_proof_log --stage argument to
"$current_state" so the --stage value matches the computed _stage_duration;
update the invocation around _proof_log_stage_duration, write_proof_log, and the
variables task_id/current_state/new_state accordingly.
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --json) format="json"; shift ;; | ||
| --timeline) mode="timeline"; shift ;; | ||
| --recent) mode="recent"; shift ;; | ||
| --stats) mode="stats"; shift ;; | ||
| --limit) limit_n="${2:-20}"; shift 2 ;; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's check the file size and then examine the specific lines mentioned
wc -l .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 106
🏁 Script executed:
# Get context around the first location (10783-10789)
sed -n '10775,10800p' .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 1210
🏁 Script executed:
# Search for where limit_n is actually used in SQL queries
rg "limit_n" .agents/scripts/supervisor-helper.sh -B 2 -A 2Repository: marcusquinn/aidevops
Length of output: 989
🏁 Script executed:
# Get the secondary location (10876-10890)
sed -n '10870,10900p' .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 1511
🏁 Script executed:
# Search for any validation logic that might occur after the argument parsing
sed -n '10800,10880p' .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 3540
🏁 Script executed:
# Check if there's any validation on limit_n before it's used in SQL
rg "limit_n" .agents/scripts/supervisor-helper.sh -B 5 -A 5 | head -100Repository: marcusquinn/aidevops
Length of output: 1987
🏁 Script executed:
# Check if ShellCheck is available and test the script
which shellcheck && shellcheck .agents/scripts/supervisor-helper.sh 2>&1 | head -50Repository: marcusquinn/aidevops
Length of output: 109
Validate --limit parameter before use in SQL queries.
The --limit option assigns limit_n without validation, unlike the positional argument which validates with ^[0-9]+$. Non-numeric values will cause SQL syntax errors when injected into LIMIT $limit_n;. Add validation to match the existing regex pattern used for positional arguments and ensure query reliability.
Suggested fix
+ # Validate limit_n is numeric before SQL execution
+ if [[ ! "$limit_n" =~ ^[0-9]+$ ]]; then
+ log_error "--limit must be a positive integer"
+ return 1
+ fiInsert after argument parsing (before the case "$mode" block at line ~10815).
Also applies to: 10876-10890
🤖 Prompt for AI Agents
In @.agents/scripts/supervisor-helper.sh around lines 10783 - 10789, The --limit
handling currently assigns limit_n from the next arg without validation; add a
numeric check using the same regex /^[0-9]+$/ that the positional argument uses
and reject or default if it fails. Specifically, after the argument-parsing loop
that sets limit_n (the --limit branch in the case block) and before the main
case "$mode" block, validate limit_n with the regex and if it does not match set
limit_n to a safe default (e.g., 20) or exit with an error, ensuring LIMIT
$limit_n in SQL only ever receives numeric input.
| echo "[" | ||
| local first=true | ||
| while IFS='|' read -r pid ptask pevent pstage pdecision pevidence pmaker ppr pdur pmeta pts; do | ||
| [[ -z "$pid" ]] && continue | ||
| if [[ "$first" != "true" ]]; then echo ","; fi | ||
| first=false | ||
| local _esc_evidence="${pevidence:-}" | ||
| _esc_evidence="${_esc_evidence//\"/\\\"}" | ||
| local _esc_meta="${pmeta:-}" | ||
| _esc_meta="${_esc_meta//\"/\\\"}" | ||
| printf ' {"id":%s,"task_id":"%s","event":"%s","stage":"%s","decision":"%s","evidence":"%s","decision_maker":"%s","pr_url":"%s","duration_secs":%s,"metadata":"%s","timestamp":"%s"}' \ | ||
| "$pid" "$ptask" "$pevent" "${pstage:-}" "${pdecision:-}" \ | ||
| "$_esc_evidence" \ | ||
| "${pmaker:-}" "${ppr:-}" "${pdur:-null}" \ | ||
| "$_esc_meta" "$pts" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, check if the file exists and get its size
wc -l .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 106
🏁 Script executed:
# Read the first code block mentioned (lines 10860-10874)
sed -n '10860,10874p' .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 1043
🏁 Script executed:
# Read the second code block mentioned (lines 10949-10963)
sed -n '10949,10963p' .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 1013
🏁 Script executed:
# Search for jq usage in the script to verify if it's already in use
rg 'jq' .agents/scripts/supervisor-helper.sh -nRepository: marcusquinn/aidevops
Length of output: 5288
🏁 Script executed:
# Check if there are other JSON escaping patterns in the file
rg 'printf.*%s.*\{' .agents/scripts/supervisor-helper.sh -A 2 -B 2 | head -50Repository: marcusquinn/aidevops
Length of output: 2123
🏁 Script executed:
# Get more context around the first location (10850-10880)
sed -n '10850,10880p' .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 1668
🏁 Script executed:
# Get more context around the second location (10940-10970)
sed -n '10940,10970p' .agents/scripts/supervisor-helper.shRepository: marcusquinn/aidevops
Length of output: 1731
🏁 Script executed:
# Test the jq -Rs escaping approach with sample problematic data
cat <<'EOF' > /tmp/test_json_escape.sh
#!/bin/bash
# Test the proposed _json_escape function
_json_escape() { printf '%s' "${1:-}" | jq -Rs .; }
# Test cases with problematic characters
test_data=(
'simple'
'with"quotes'
'with\backslash'
'with
newline'
'with tab'
'with"both\and
newline'
)
echo "Testing _json_escape function:"
for data in "${test_data[@]}"; do
escaped=$(_json_escape "$data")
echo "Input: $data"
echo "Output: $escaped"
echo "---"
done
EOF
bash /tmp/test_json_escape.shRepository: marcusquinn/aidevops
Length of output: 383
🏁 Script executed:
# Verify the current escaping is insufficient
cat <<'EOF' > /tmp/test_current_escape.sh
#!/bin/bash
# Current escaping approach
current_escape() {
local var="${1:-}"
var="${var//\"/\\\"}"
echo "$var"
}
# Test with problematic data
test_with_newline='foo"bar
baz'
test_with_backslash='foo"bar\baz'
echo "Current escaping results:"
echo "With newline: $(current_escape "$test_with_newline")"
echo "With backslash: $(current_escape "$test_with_backslash")"
# Show how this breaks JSON
echo ""
echo "JSON output with current escaping:"
printf '{"data":"%s"}\n' "$(current_escape "$test_with_newline")"
echo "^ Notice: JSON is broken (newline not escaped)"
EOF
bash /tmp/test_current_escape.shRepository: marcusquinn/aidevops
Length of output: 252
JSON export emits invalid JSON for evidence and metadata fields.
The current escaping only removes double quotes via parameter expansion (${var//\"/\\\"}), but leaves newlines, backslashes, tabs, and other control characters unescaped. This breaks JSON structure downstream. Use the proper jq -Rs . JSON escaper (already used throughout the script) for all string values.
Suggested fix
+ _json_escape() { printf '%s' "${1:-}" | jq -Rs .; }
...
- local _esc_evidence="${pevidence:-}"
- _esc_evidence="${_esc_evidence//\"/\\\"}"
- local _esc_meta="${pmeta:-}"
- _esc_meta="${_esc_meta//\"/\\\"}"
- printf ' {"id":%s,"task_id":"%s","event":"%s","stage":"%s","decision":"%s","evidence":"%s","decision_maker":"%s","pr_url":"%s","duration_secs":%s,"metadata":"%s","timestamp":"%s"}' \
- "$pid" "$ptask" "$pevent" "${pstage:-}" "${pdecision:-}" \
- "$_esc_evidence" \
- "${pmaker:-}" "${ppr:-}" "${pdur:-null}" \
- "$_esc_meta" "$pts"
+ printf ' {"id":%s,"task_id":%s,"event":%s,"stage":%s,"decision":%s,"evidence":%s,"decision_maker":%s,"pr_url":%s,"duration_secs":%s,"metadata":%s,"timestamp":%s}' \
+ "$pid" \
+ "$(_json_escape "$ptask")" "$(_json_escape "$pevent")" "$(_json_escape "${pstage:-}")" \
+ "$(_json_escape "${pdecision:-}")" "$(_json_escape "${pevidence:-}")" \
+ "$(_json_escape "${pmaker:-}")" "$(_json_escape "${ppr:-}")" \
+ "${pdur:-null}" "$(_json_escape "${pmeta:-}")" "$(_json_escape "$pts")"Also applies to: 10949-10963
🤖 Prompt for AI Agents
In @.agents/scripts/supervisor-helper.sh around lines 10860 - 10874, The code
builds JSON using manual escaping of evidence/meta via _esc_evidence and
_esc_meta which only replaces quotes and leaves newlines, backslashes, tabs,
etc., unescaped; replace that logic by passing the raw pevidence and pmeta
through the existing JSON escaper `jq -Rs .` (e.g., set _esc_evidence=$(printf
'%s' "$pevidence" | jq -Rs .) and similarly for _esc_meta) and then use those
values in the printf that constructs the object (update the printf placeholders
to accept the jq-escaped strings as-is); apply the same change to the other
block around lines 10949-10963 that uses _esc_evidence/_esc_meta.



Summary
proof_logsSQLite table with structured audit trail for every supervisor decision pointproof-logCLI command with table/JSON/timeline output and aggregate statisticsWhat it does
The existing
state_logtable records state transitions but not why decisions were made. The newproof_logstable captures:eventdecisioncomplete:PR_URL,retry:rate_limited)evidenceexit_code=0, signal=FULL_LOOP_COMPLETE)decision_makerevaluate_worker,quality_gate,pulse:phase1)duration_secsQuery interface
Design decisions
ensure_db()_proof_log_stage_duration()calculates elapsed time between entries (t219 prep)Testing
bash -nsyntax check: PASSCloses
Closes #913 (t218)
Summary by CodeRabbit