feat(log): unified CASAN_LOG_LEVEL across Boss, agent step, harness wrapper
Add a shared log taxonomy (error<warn<info<debug<trace, default info) wired through all three layers, plus a machine-readable per-step run log. - scripts/casan-log.mjs + .specify/scripts/bash/casan-log.sh: shared logger ([LEVEL] ts [component] msg), stderr-only so stdout contracts and exit codes are byte-identical. Node side includes trace-level redaction (secret/PII). - run-casan-pipeline.mjs: per-STEP info line, loop-activation warnings (BACK-TO-PLAN, FAIL->STEP6), debug harness rc + trace_id, trace payload excerpt, end-of-run 13-STEP summary table, and one JSONL line/step in .specify/logs/pipeline-run.jsonl. New --dry-run stubs all agents but keeps the real wrapper in the loop (deterministic, offline, full 13 STEP + loops). - casan-step.mjs: debug logs for judge verdict, checkpoint, rollback; logger import degrades to noop when the file is copied standalone (T1 test). - casan-harness.sh: debug-log each phase H4-in -> H5 -> [H2-gate] -> H6-exec -> H4-out with its rc; optional CASAN_PHASE_REPORT JSON for the Boss. Default level (info) keeps output close to before; behavior opt-in via env. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2f06662f5d
commit
1b61d7f381
@@ -27,6 +27,40 @@ TMP_DIR="$PROJECT_ROOT/.specify/logs/tmp"
|
||||
CACHE_DIR="$PROJECT_ROOT/.specify/logs/idempotency"
|
||||
mkdir -p "$TMP_DIR" "$CACHE_DIR" "$(dirname "$FINAL_OUTPUT")"
|
||||
|
||||
# Shared log taxonomy (error<warn<info<debug<trace via CASAN_LOG_LEVEL).
|
||||
# debug shows each harness phase with its rc; stderr only, stdout untouched.
|
||||
# shellcheck source=casan-log.sh
|
||||
source "$SCRIPT_DIR/casan-log.sh"
|
||||
|
||||
# Optional machine-readable phase report (one JSON object per invocation).
|
||||
# The Boss orchestrator sets CASAN_PHASE_REPORT per step so it can log per-
|
||||
# harness rc at debug level and persist them into pipeline-run.jsonl.
|
||||
PHASE_REPORT="${CASAN_PHASE_REPORT:-}"
|
||||
PHASE_LOG=""
|
||||
CACHE_STATUS="none"
|
||||
|
||||
record_phase() { # <phase-name> <rc>
|
||||
casan_log debug harness "action=$ACTION_NAME phase=$1 rc=$2"
|
||||
PHASE_LOG="${PHASE_LOG:+$PHASE_LOG,}{\"phase\":\"$1\",\"rc\":$2}"
|
||||
}
|
||||
|
||||
write_phase_report() {
|
||||
[[ -n "$PHASE_REPORT" ]] || return 0
|
||||
printf '{"action":"%s","cache":"%s","phases":[%s]}\n' \
|
||||
"$ACTION_NAME" "$CACHE_STATUS" "$PHASE_LOG" > "$PHASE_REPORT" 2>/dev/null || true
|
||||
}
|
||||
|
||||
run_phase() { # <phase-name> <command...> — preserves the failing rc exactly
|
||||
local phase="$1"; shift
|
||||
local rc=0
|
||||
"$@" || rc=$?
|
||||
record_phase "$phase" "$rc"
|
||||
if [[ "$rc" -ne 0 ]]; then
|
||||
write_phase_report
|
||||
exit "$rc"
|
||||
fi
|
||||
}
|
||||
|
||||
hash_text() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum | awk '{print $1}'
|
||||
@@ -47,8 +81,9 @@ SAFE_INPUT="$TMP_DIR/security-input-$TRACE_SUFFIX.txt"
|
||||
APPROVED_INPUT="$TMP_DIR/governance-approved-$TRACE_SUFFIX.txt"
|
||||
RAW_OUTPUT="$TMP_DIR/raw-output-$TRACE_SUFFIX.txt"
|
||||
|
||||
"$SCRIPT_DIR/security-check.sh" "$INPUT_FILE" "$SAFE_INPUT" input
|
||||
"$SCRIPT_DIR/governance-check.sh" "$SAFE_INPUT" "$APPROVED_INPUT" "$ACTION_NAME"
|
||||
casan_log debug harness "action=$ACTION_NAME input=$INPUT_FILE output=$FINAL_OUTPUT key=${IDEMPOTENCY_KEY:0:12}…"
|
||||
run_phase "H4-in" "$SCRIPT_DIR/security-check.sh" "$INPUT_FILE" "$SAFE_INPUT" input
|
||||
run_phase "H5" "$SCRIPT_DIR/governance-check.sh" "$SAFE_INPUT" "$APPROVED_INPUT" "$ACTION_NAME"
|
||||
|
||||
# H2 tool registry gate is in the line of fire for side-effecting actions:
|
||||
# it enforces idempotency key, per-agent permission, and rollback strategy
|
||||
@@ -56,7 +91,7 @@ RAW_OUTPUT="$TMP_DIR/raw-output-$TRACE_SUFFIX.txt"
|
||||
# content-addressed idempotency key above.
|
||||
case "$ACTION_NAME" in
|
||||
write_code|migration|deploy|db_write|external_api|write_file)
|
||||
CASAN_IDEMPOTENCY_KEY="$IDEMPOTENCY_KEY" "$SCRIPT_DIR/tool-registry-gate.sh" "$ACTION_NAME"
|
||||
run_phase "H2-gate" env CASAN_IDEMPOTENCY_KEY="$IDEMPOTENCY_KEY" "$SCRIPT_DIR/tool-registry-gate.sh" "$ACTION_NAME"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -69,18 +104,18 @@ export CASAN_STEP_NAME="${CASAN_STEP_NAME:-$ACTION_NAME}"
|
||||
TOOL_TIMEOUT="${CASAN_TOOL_TIMEOUT_SECONDS:-30}"
|
||||
|
||||
if [[ -f "$CACHE_META" && -f "$CACHE_OUT" ]]; then
|
||||
"$SCRIPT_DIR/agent-metrics.sh" "$APPROVED_INPUT" "$RAW_OUTPUT" -- bash -c 'cp "$1" "$CASAN_OUTPUT"' _ "$CACHE_OUT"
|
||||
CACHE_STATUS="cached"
|
||||
run_phase "H6-exec" "$SCRIPT_DIR/agent-metrics.sh" "$APPROVED_INPUT" "$RAW_OUTPUT" -- bash -c 'cp "$1" "$CASAN_OUTPUT"' _ "$CACHE_OUT"
|
||||
elif [[ "$#" -gt 0 ]]; then
|
||||
"$SCRIPT_DIR/agent-metrics.sh" "$APPROVED_INPUT" "$RAW_OUTPUT" -- \
|
||||
CACHE_STATUS="stored"
|
||||
run_phase "H6-exec" "$SCRIPT_DIR/agent-metrics.sh" "$APPROVED_INPUT" "$RAW_OUTPUT" -- \
|
||||
"$SCRIPT_DIR/tool-exec.sh" "$TOOL_TIMEOUT" -- "$@"
|
||||
CACHE_STATUS="stored"
|
||||
else
|
||||
"$SCRIPT_DIR/agent-metrics.sh" "$APPROVED_INPUT" "$RAW_OUTPUT"
|
||||
CACHE_STATUS="stored"
|
||||
run_phase "H6-exec" "$SCRIPT_DIR/agent-metrics.sh" "$APPROVED_INPUT" "$RAW_OUTPUT"
|
||||
fi
|
||||
|
||||
"$SCRIPT_DIR/security-check.sh" "$RAW_OUTPUT" "$FINAL_OUTPUT" output
|
||||
run_phase "H4-out" "$SCRIPT_DIR/security-check.sh" "$RAW_OUTPUT" "$FINAL_OUTPUT" output
|
||||
|
||||
if [[ "$CACHE_STATUS" == "stored" ]]; then
|
||||
cat <<EOF > "$CACHE_META"
|
||||
@@ -95,4 +130,6 @@ EOF
|
||||
cp "$FINAL_OUTPUT" "$CACHE_OUT"
|
||||
fi
|
||||
|
||||
write_phase_report
|
||||
casan_log debug harness "action=$ACTION_NAME complete cache=$CACHE_STATUS"
|
||||
echo "CASAN_HARNESS_COMPLETE cache=$CACHE_STATUS key=$IDEMPOTENCY_KEY output=$FINAL_OUTPUT"
|
||||
|
||||
Reference in New Issue
Block a user