@cyanautomation/kaseki-agent 1.64.2 → 1.65.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/kaseki-api-routes.d.ts.map +1 -1
- package/dist/kaseki-api-routes.js +35 -2
- package/dist/kaseki-api-routes.js.map +1 -1
- package/dist/kaseki-api-types.d.ts +10 -0
- package/dist/kaseki-api-types.d.ts.map +1 -1
- package/dist/openapi-spec-generators/paths.d.ts.map +1 -1
- package/dist/openapi-spec-generators/paths.js +26 -0
- package/dist/openapi-spec-generators/paths.js.map +1 -1
- package/dist/pi-event-filter.js +36 -0
- package/dist/pi-event-filter.js.map +1 -1
- package/dist/startup/container-preflight.d.ts +13 -2
- package/dist/startup/container-preflight.d.ts.map +1 -1
- package/dist/startup/container-preflight.js +61 -7
- package/dist/startup/container-preflight.js.map +1 -1
- package/dist/token-usage-aggregator.d.ts +85 -0
- package/dist/token-usage-aggregator.d.ts.map +1 -0
- package/dist/token-usage-aggregator.js +135 -0
- package/dist/token-usage-aggregator.js.map +1 -0
- package/kaseki-agent.sh +385 -383
- package/package.json +2 -2
- package/scripts/docker-entrypoint.sh +54 -5
- package/scripts/kaseki-setup-host.sh +51 -16
- package/scripts/startup-checks.sh +40 -25
package/kaseki-agent.sh
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# shellcheck disable=SC2086,SC2016,SC2027,SC1091
|
|
2
3
|
# NOTE: This script intentionally avoids global `set -e` so each stage can
|
|
3
4
|
# record status/timing artifacts before deciding whether to stop.
|
|
4
5
|
set -uo pipefail
|
|
@@ -74,11 +75,11 @@ KASEKI_AUTO_LINT_CLEANUP_COMMANDS="${KASEKI_AUTO_LINT_CLEANUP_COMMANDS-npm run l
|
|
|
74
75
|
KASEKI_SKIP_MISSING_NPM_SCRIPTS="${KASEKI_SKIP_MISSING_NPM_SCRIPTS:-1}"
|
|
75
76
|
KASEKI_DEBUG_RAW_EVENTS="${KASEKI_DEBUG_RAW_EVENTS:-0}"
|
|
76
77
|
KASEKI_STREAM_PROGRESS="${KASEKI_STREAM_PROGRESS:-1}"
|
|
77
|
-
KASEKI_RESULTS_DIR="${KASEKI_RESULTS_DIR
|
|
78
|
+
KASEKI_RESULTS_DIR="${KASEKI_RESULTS_DIR:-/results}"
|
|
78
79
|
export KASEKI_RESULTS_DIR
|
|
79
80
|
KASEKI_WORKSPACE_DIR="${KASEKI_WORKSPACE_DIR:-/workspace}"
|
|
80
81
|
export KASEKI_WORKSPACE_DIR
|
|
81
|
-
KASEKI_WORKSPACE_BASELINE_DIR="${KASEKI_WORKSPACE_BASELINE_DIR:-${
|
|
82
|
+
KASEKI_WORKSPACE_BASELINE_DIR="${KASEKI_WORKSPACE_BASELINE_DIR:-${KASEKI_WORKSPACE_DIR}/baseline}"
|
|
82
83
|
export KASEKI_WORKSPACE_BASELINE_DIR
|
|
83
84
|
KASEKI_APP_LIB_DIR="${KASEKI_APP_LIB_DIR:-/app/lib}"
|
|
84
85
|
export KASEKI_APP_LIB_DIR
|
|
@@ -270,7 +271,7 @@ LAST_COMMAND_LOG="${KASEKI_RESULTS_DIR}/last-command.log"
|
|
|
270
271
|
# Signal handler for graceful termination
|
|
271
272
|
handle_termination() {
|
|
272
273
|
local signal="$1"
|
|
273
|
-
printf '\nReceived %s; terminating kaseki-agent...\n' "$signal" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
274
|
+
printf '\nReceived %s; terminating kaseki-agent...\n' "$signal" | tee -a "${KASEKI_RESULTS_DIR}"/progress.log
|
|
274
275
|
# Exit with standard code for signal (128 + signal_number)
|
|
275
276
|
# SIGINT = 130, SIGTERM = 143
|
|
276
277
|
if [ "$signal" = "SIGINT" ]; then
|
|
@@ -307,8 +308,8 @@ setup_host_logging_mirror() {
|
|
|
307
308
|
if mkdir -p "$KASEKI_LOG_DIR" 2>/dev/null && [ -w "$KASEKI_LOG_DIR" ]; then
|
|
308
309
|
stamp="$(date -u +%Y%m%dT%H%M%SZ)"
|
|
309
310
|
host_log_file="$KASEKI_LOG_DIR/${base_name}-${stamp}.log"
|
|
310
|
-
exec > >(tee -a ${KASEKI_RESULTS_DIR}/stdout.log | tee -a "$host_log_file") \
|
|
311
|
-
2> >(tee -a ${KASEKI_RESULTS_DIR}/stderr.log | tee -a "$host_log_file" >&2)
|
|
311
|
+
exec > >(tee -a "${KASEKI_RESULTS_DIR}"/stdout.log | tee -a "$host_log_file") \
|
|
312
|
+
2> >(tee -a "${KASEKI_RESULTS_DIR}"/stderr.log | tee -a "$host_log_file" >&2)
|
|
312
313
|
printf 'Host log mirror: %s\n' "$host_log_file"
|
|
313
314
|
return 0
|
|
314
315
|
fi
|
|
@@ -316,7 +317,7 @@ setup_host_logging_mirror() {
|
|
|
316
317
|
printf 'Error: strict host logging enabled, but KASEKI_LOG_DIR is not writable: %s\n' "$KASEKI_LOG_DIR" >&2
|
|
317
318
|
exit 1
|
|
318
319
|
fi
|
|
319
|
-
exec > >(tee -a ${KASEKI_RESULTS_DIR}/stdout.log) 2> >(tee -a ${KASEKI_RESULTS_DIR}/stderr.log >&2)
|
|
320
|
+
exec > >(tee -a "${KASEKI_RESULTS_DIR}"/stdout.log) 2> >(tee -a "${KASEKI_RESULTS_DIR}"/stderr.log >&2)
|
|
320
321
|
printf 'Warning: host log mirror disabled; KASEKI_LOG_DIR is unavailable: %s (set writable KASEKI_LOG_DIR to enable mirror, or set KASEKI_STRICT_HOST_LOGGING=1 to fail fast)\n' "$KASEKI_LOG_DIR" >&2
|
|
321
322
|
}
|
|
322
323
|
|
|
@@ -337,41 +338,41 @@ if ! mkdir -p "${mkdir_paths[@]}"; then
|
|
|
337
338
|
printf 'Error: Failed to create required runtime directories.\n' >&2
|
|
338
339
|
exit 1
|
|
339
340
|
fi
|
|
340
|
-
: > ${KASEKI_RESULTS_DIR}/stdout.log
|
|
341
|
-
: > ${KASEKI_RESULTS_DIR}/stderr.log
|
|
342
|
-
: > ${KASEKI_RESULTS_DIR}/pi-events.jsonl
|
|
343
|
-
: > ${KASEKI_RESULTS_DIR}/pi-summary.json
|
|
344
|
-
: > ${KASEKI_RESULTS_DIR}/scouting-events.jsonl
|
|
345
|
-
: > ${KASEKI_RESULTS_DIR}/scouting-summary.json
|
|
346
|
-
: > ${KASEKI_RESULTS_DIR}/scouting-validation-errors.jsonl
|
|
347
|
-
: > ${KASEKI_RESULTS_DIR}/scouting-validation-summary.txt
|
|
348
|
-
: > ${KASEKI_RESULTS_DIR}/goal-check-events.jsonl
|
|
349
|
-
: > ${KASEKI_RESULTS_DIR}/goal-check-summary.json
|
|
350
|
-
: > ${KASEKI_RESULTS_DIR}/goal-check-stderr.log
|
|
351
|
-
: > ${KASEKI_RESULTS_DIR}/goal-check-validation-errors.jsonl
|
|
352
|
-
: > ${KASEKI_RESULTS_DIR}/goal-check-validation-summary.txt
|
|
353
|
-
: > ${KASEKI_RESULTS_DIR}/goal-check-attempts.jsonl
|
|
354
|
-
: > ${KASEKI_RESULTS_DIR}/goal-check.json
|
|
355
|
-
: > ${KASEKI_RESULTS_DIR}/run-evaluation-events.jsonl
|
|
356
|
-
: > ${KASEKI_RESULTS_DIR}/run-evaluation-summary.json
|
|
357
|
-
: > ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log
|
|
358
|
-
: > ${KASEKI_RESULTS_DIR}/run-evaluation.json
|
|
341
|
+
: > "${KASEKI_RESULTS_DIR}"/stdout.log
|
|
342
|
+
: > "${KASEKI_RESULTS_DIR}"/stderr.log
|
|
343
|
+
: > "${KASEKI_RESULTS_DIR}"/pi-events.jsonl
|
|
344
|
+
: > "${KASEKI_RESULTS_DIR}"/pi-summary.json
|
|
345
|
+
: > "${KASEKI_RESULTS_DIR}"/scouting-events.jsonl
|
|
346
|
+
: > "${KASEKI_RESULTS_DIR}"/scouting-summary.json
|
|
347
|
+
: > "${KASEKI_RESULTS_DIR}"/scouting-validation-errors.jsonl
|
|
348
|
+
: > "${KASEKI_RESULTS_DIR}"/scouting-validation-summary.txt
|
|
349
|
+
: > "${KASEKI_RESULTS_DIR}"/goal-check-events.jsonl
|
|
350
|
+
: > "${KASEKI_RESULTS_DIR}"/goal-check-summary.json
|
|
351
|
+
: > "${KASEKI_RESULTS_DIR}"/goal-check-stderr.log
|
|
352
|
+
: > "${KASEKI_RESULTS_DIR}"/goal-check-validation-errors.jsonl
|
|
353
|
+
: > "${KASEKI_RESULTS_DIR}"/goal-check-validation-summary.txt
|
|
354
|
+
: > "${KASEKI_RESULTS_DIR}"/goal-check-attempts.jsonl
|
|
355
|
+
: > "${KASEKI_RESULTS_DIR}"/goal-check.json
|
|
356
|
+
: > "${KASEKI_RESULTS_DIR}"/run-evaluation-events.jsonl
|
|
357
|
+
: > "${KASEKI_RESULTS_DIR}"/run-evaluation-summary.json
|
|
358
|
+
: > "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log
|
|
359
|
+
: > "${KASEKI_RESULTS_DIR}"/run-evaluation.json
|
|
359
360
|
: > "$TEST_IMPACT_WARNINGS_ARTIFACT"
|
|
360
361
|
: > "$EXPECTATION_MISMATCH_WARNINGS_ARTIFACT"
|
|
361
|
-
: > ${KASEKI_RESULTS_DIR}/validation.log
|
|
362
|
-
: > ${KASEKI_RESULTS_DIR}/pre-validation.log
|
|
362
|
+
: > "${KASEKI_RESULTS_DIR}"/validation.log
|
|
363
|
+
: > "${KASEKI_RESULTS_DIR}"/pre-validation.log
|
|
363
364
|
: > "$PRE_VALIDATION_RAW_LOG"
|
|
364
365
|
: > "$PRE_VALIDATION_ENV_LOG"
|
|
365
366
|
: > "$AUTO_LINT_CLEANUP_LOG"
|
|
366
367
|
: > "$AUTO_LINT_CLEANUP_TIMINGS_FILE"
|
|
367
|
-
: > ${KASEKI_RESULTS_DIR}/quality.log
|
|
368
|
-
: > ${KASEKI_RESULTS_DIR}/secret-scan.log
|
|
369
|
-
: > ${KASEKI_RESULTS_DIR}/git-push.log
|
|
370
|
-
: > ${KASEKI_RESULTS_DIR}/progress.log
|
|
371
|
-
: > ${KASEKI_RESULTS_DIR}/progress.jsonl
|
|
372
|
-
: > ${KASEKI_RESULTS_DIR}/format-check-command.txt
|
|
373
|
-
: > ${KASEKI_RESULTS_DIR}/failure.json
|
|
374
|
-
: > ${KASEKI_RESULTS_DIR}/result-summary.md
|
|
368
|
+
: > "${KASEKI_RESULTS_DIR}"/quality.log
|
|
369
|
+
: > "${KASEKI_RESULTS_DIR}"/secret-scan.log
|
|
370
|
+
: > "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
371
|
+
: > "${KASEKI_RESULTS_DIR}"/progress.log
|
|
372
|
+
: > "${KASEKI_RESULTS_DIR}"/progress.jsonl
|
|
373
|
+
: > "${KASEKI_RESULTS_DIR}"/format-check-command.txt
|
|
374
|
+
: > "${KASEKI_RESULTS_DIR}"/failure.json
|
|
375
|
+
: > "${KASEKI_RESULTS_DIR}"/result-summary.md
|
|
375
376
|
: > "$VALIDATION_TIMINGS_FILE"
|
|
376
377
|
: > "$PRE_VALIDATION_TIMINGS_FILE"
|
|
377
378
|
: >> "$STAGE_TIMINGS_FILE"
|
|
@@ -540,7 +541,7 @@ validate_scouting_artifact_with_node() {
|
|
|
540
541
|
"$validation_error_file" \
|
|
541
542
|
"${KASEKI_RESULTS_DIR}/scouting-validation-errors.jsonl" \
|
|
542
543
|
>/dev/null \
|
|
543
|
-
2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
544
|
+
2>> "${KASEKI_RESULTS_DIR}"/scouting-stderr.log
|
|
544
545
|
}
|
|
545
546
|
|
|
546
547
|
# Validate scouting artifact and emit structured reason code
|
|
@@ -554,7 +555,7 @@ validate_scouting_artifact() {
|
|
|
554
555
|
|
|
555
556
|
: > "$validation_error_file"
|
|
556
557
|
if [ ! -f "$candidate_artifact" ]; then
|
|
557
|
-
if [ -f ${KASEKI_RESULTS_DIR}/filesystem-readonly-reason.txt ]; then
|
|
558
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/filesystem-readonly-reason.txt ]; then
|
|
558
559
|
reason_code="readonly_filesystem"
|
|
559
560
|
reason_details="1 critical scouting validation error: scouting-candidate.json missing due to read-only filesystem"
|
|
560
561
|
else
|
|
@@ -569,8 +570,8 @@ validate_scouting_artifact() {
|
|
|
569
570
|
fi
|
|
570
571
|
|
|
571
572
|
printf '%s\n' "$reason_code" > "$reason_file"
|
|
572
|
-
printf '%s\n' "$reason_details" > ${KASEKI_RESULTS_DIR}/scouting-validation-summary.txt
|
|
573
|
-
printf '[scouting-validation] reason=%s details=%s\n' "$reason_code" "$reason_details" | tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
573
|
+
printf '%s\n' "$reason_details" > "${KASEKI_RESULTS_DIR}"/scouting-validation-summary.txt
|
|
574
|
+
printf '[scouting-validation] reason=%s details=%s\n' "$reason_code" "$reason_details" | tee -a "${KASEKI_RESULTS_DIR}"/scouting-stderr.log
|
|
574
575
|
rm -f "$validation_error_file" 2>/dev/null || true
|
|
575
576
|
[ "$reason_code" = "valid" ]
|
|
576
577
|
}
|
|
@@ -626,6 +627,7 @@ function summarize(errors) {
|
|
|
626
627
|
|
|
627
628
|
function fail(reasonHint, errors) {
|
|
628
629
|
for (const error of errors) appendValidationFailure(error);
|
|
630
|
+
fs.mkdirSync(path.dirname(errorLog), { recursive: true });
|
|
629
631
|
fs.writeFileSync(errorLog, JSON.stringify({
|
|
630
632
|
reason_hint: reasonHint,
|
|
631
633
|
details: summarize(errors),
|
|
@@ -643,7 +645,7 @@ try {
|
|
|
643
645
|
expected: "valid JSON object",
|
|
644
646
|
actual: error && error.message ? String(error.message) : String(error),
|
|
645
647
|
severity: "critical",
|
|
646
|
-
suggestion:
|
|
648
|
+
suggestion: `ensure exactly one valid JSON object is written to ${resultsDir}/goal-check-candidate.json`,
|
|
647
649
|
}]);
|
|
648
650
|
}
|
|
649
651
|
|
|
@@ -720,7 +722,7 @@ validate_goal_check_artifact() {
|
|
|
720
722
|
reason_code="missing_file"
|
|
721
723
|
reason_details="1 critical goal-check validation error: goal-check-candidate.json"
|
|
722
724
|
# shellcheck disable=SC2016
|
|
723
|
-
node -e 'const fs=require("node:fs"); const candidate=process.argv[1]; const attempt=Number(process.argv[2]); const error={timestamp:new Date().toISOString(),attempt,field:"goal-check-candidate.json",expected:"file at ${KASEKI_RESULTS_DIR}/goal-check-candidate.json",actual:`missing: ${candidate}`,severity:"critical",suggestion:"ensure the goal-check Pi writes exactly one valid JSON object to ${KASEKI_RESULTS_DIR}/goal-check-candidate.json before exiting successfully"}; fs.appendFileSync(process.env.KASEKI_RESULTS_DIR + "/goal-check-validation-errors.jsonl", JSON.stringify(error)+"\n");' "$candidate_artifact" "$attempt" 2>> ${KASEKI_RESULTS_DIR}/goal-check-stderr.log || true
|
|
725
|
+
node -e 'const fs=require("node:fs"); const candidate=process.argv[1]; const attempt=Number(process.argv[2]); const error={timestamp:new Date().toISOString(),attempt,field:"goal-check-candidate.json",expected:"file at "${KASEKI_RESULTS_DIR}"/goal-check-candidate.json",actual:`missing: ${candidate}`,severity:"critical",suggestion:"ensure the goal-check Pi writes exactly one valid JSON object to ${KASEKI_RESULTS_DIR}/goal-check-candidate.json before exiting successfully"}; fs.appendFileSync(process.env.KASEKI_RESULTS_DIR + "/goal-check-validation-errors.jsonl", JSON.stringify(error)+"\n");' "$candidate_artifact" "$attempt" 2>> "${KASEKI_RESULTS_DIR}"/goal-check-stderr.log || true
|
|
724
726
|
elif ! validate_goal_check_artifact_with_node "$candidate_artifact" "$final_artifact" "$attempt" "$validation_error_file"; then
|
|
725
727
|
reason_code="$(node -e 'try{const v=JSON.parse(require("node:fs").readFileSync(process.argv[1],"utf8")); const hint=String(v.reason_hint||""); process.stdout.write(hint === "malformed_json" ? "malformed_json" : "schema_mismatch");}catch{process.stdout.write("schema_mismatch");}' "$validation_error_file" 2>/dev/null || printf 'schema_mismatch')"
|
|
726
728
|
reason_details="$(node -e 'try{const v=JSON.parse(require("node:fs").readFileSync(process.argv[1],"utf8")); process.stdout.write(String(v.details||"goal-check artifact validation failed"));}catch{process.stdout.write("goal-check artifact validation failed");}' "$validation_error_file" 2>/dev/null || printf 'goal-check artifact validation failed')"
|
|
@@ -728,7 +730,7 @@ validate_goal_check_artifact() {
|
|
|
728
730
|
|
|
729
731
|
printf '%s\n' "$reason_code" > "$reason_file"
|
|
730
732
|
printf '%s\n' "$reason_details" > "$summary_file"
|
|
731
|
-
printf '[goal-check-validation] reason=%s details=%s\n' "$reason_code" "$reason_details" | tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log
|
|
733
|
+
printf '[goal-check-validation] reason=%s details=%s\n' "$reason_code" "$reason_details" | tee -a "${KASEKI_RESULTS_DIR}"/goal-check-stderr.log
|
|
732
734
|
rm -f "$validation_error_file" 2>/dev/null || true
|
|
733
735
|
[ "$reason_code" = "valid" ]
|
|
734
736
|
}
|
|
@@ -737,20 +739,20 @@ emit_progress() {
|
|
|
737
739
|
local stage="$1"
|
|
738
740
|
local detail="$2"
|
|
739
741
|
local status="${3:-info}"
|
|
740
|
-
append_jsonl_object ${KASEKI_RESULTS_DIR}/progress.jsonl \
|
|
742
|
+
append_jsonl_object "${KASEKI_RESULTS_DIR}"/progress.jsonl \
|
|
741
743
|
"timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
742
744
|
"component=kaseki-agent" \
|
|
743
745
|
"stage=$stage" \
|
|
744
746
|
"status=$status" \
|
|
745
747
|
"instance=$INSTANCE_NAME" \
|
|
746
748
|
"detail=$detail"
|
|
747
|
-
printf '[progress] %s %s: %s\n' "$stage" "$status" "$detail" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
749
|
+
printf '[progress] %s %s: %s\n' "$stage" "$status" "$detail" | tee -a "${KASEKI_RESULTS_DIR}"/progress.log
|
|
748
750
|
}
|
|
749
751
|
|
|
750
752
|
emit_event() {
|
|
751
753
|
local event_type="$1"
|
|
752
754
|
shift
|
|
753
|
-
append_jsonl_object ${KASEKI_RESULTS_DIR}/progress.jsonl \
|
|
755
|
+
append_jsonl_object "${KASEKI_RESULTS_DIR}"/progress.jsonl \
|
|
754
756
|
"timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
755
757
|
"component=kaseki-agent" \
|
|
756
758
|
"event_type=$event_type" \
|
|
@@ -763,7 +765,7 @@ emit_error_event() {
|
|
|
763
765
|
local detail="$2"
|
|
764
766
|
local recovery="${3:-continue}"
|
|
765
767
|
emit_event "error" "error_type=$error_type" "detail=$detail" "recovery_action=$recovery"
|
|
766
|
-
printf '[error] %s: %s (recovery: %s)\n' "$error_type" "$detail" "$recovery" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
768
|
+
printf '[error] %s: %s (recovery: %s)\n' "$error_type" "$detail" "$recovery" | tee -a "${KASEKI_RESULTS_DIR}"/progress.log
|
|
767
769
|
}
|
|
768
770
|
|
|
769
771
|
write_metadata() {
|
|
@@ -781,7 +783,7 @@ write_metadata() {
|
|
|
781
783
|
stages_json="[\"unknown\"]"
|
|
782
784
|
fi
|
|
783
785
|
|
|
784
|
-
cat > ${KASEKI_RESULTS_DIR}/metadata.json <<META
|
|
786
|
+
cat > "${KASEKI_RESULTS_DIR}"/metadata.json <<META
|
|
785
787
|
{
|
|
786
788
|
"instance": $(printf '%s' "$INSTANCE_NAME" | json_encode),
|
|
787
789
|
"repo_url": $(printf '%s' "$REPO_URL" | json_encode),
|
|
@@ -902,7 +904,7 @@ write_metadata() {
|
|
|
902
904
|
"stages": $stages_json
|
|
903
905
|
}
|
|
904
906
|
META
|
|
905
|
-
printf '%s\n' "$exit_code" > ${KASEKI_RESULTS_DIR}/exit_code
|
|
907
|
+
printf '%s\n' "$exit_code" > "${KASEKI_RESULTS_DIR}"/exit_code
|
|
906
908
|
}
|
|
907
909
|
|
|
908
910
|
set_current_stage() {
|
|
@@ -957,7 +959,7 @@ build_stages_array() {
|
|
|
957
959
|
|
|
958
960
|
write_result_summary() {
|
|
959
961
|
local changed_files changed_files_markdown validation_status pr_status github_skip_reasons_summary goal_check_status
|
|
960
|
-
changed_files="$(cat ${KASEKI_RESULTS_DIR}/changed-files.txt 2>/dev/null || true)"
|
|
962
|
+
changed_files="$(cat "${KASEKI_RESULTS_DIR}"/changed-files.txt 2>/dev/null || true)"
|
|
961
963
|
if [ -n "$changed_files" ]; then
|
|
962
964
|
changed_files_markdown="$(printf '%s\n' "$changed_files" | sed 's/^/ - /')"
|
|
963
965
|
else
|
|
@@ -1010,7 +1012,7 @@ write_result_summary() {
|
|
|
1010
1012
|
goal_check_status="not reached"
|
|
1011
1013
|
fi
|
|
1012
1014
|
|
|
1013
|
-
cat > ${KASEKI_RESULTS_DIR}/result-summary.md <<SUMMARY
|
|
1015
|
+
cat > "${KASEKI_RESULTS_DIR}"/result-summary.md <<SUMMARY
|
|
1014
1016
|
# Kaseki Result: $INSTANCE_NAME
|
|
1015
1017
|
|
|
1016
1018
|
- Status: $(if [ "$STATUS" -eq 0 ]; then printf 'passed'; else printf 'failed'; fi)
|
|
@@ -1035,7 +1037,7 @@ $(if [ -n "$VALIDATION_ALLOWLIST_FAILURE_REASON" ]; then printf ' - Allowlist r
|
|
|
1035
1037
|
$(if [ "$KASEKI_VALIDATION_RUN_ALL_COMMANDS" -eq 1 ]; then printf -- '- **ℹ️ Validation mode: Comprehensive** (KASEKI_VALIDATION_RUN_ALL_COMMANDS=1) - all %d commands executed\n' "$(echo "$KASEKI_VALIDATION_COMMANDS" | tr ';' '\n' | grep -c .)"; elif [ "$VALIDATION_STOPPED_EARLY" = "true" ]; then printf -- '- **⚠️ Validation stopped early** (fail-fast mode): %s of %s commands ran\n' "$VALIDATION_COMMANDS_ATTEMPTED" "$(echo "$KASEKI_VALIDATION_COMMANDS" | tr ';' '\n' | grep -c .)"; fi)
|
|
1036
1038
|
- Test failure analysis: $TEST_FAILURE_CLASSIFICATION_STATUS
|
|
1037
1039
|
$(if [ "$TEST_FAILURE_CLASSIFICATION_STATUS" = "completed" ] && [ "$NEWLY_INTRODUCED_FAILURES_COUNT" -gt 0 ]; then printf ' - ⚠️ **Newly introduced failures: %d**\n' "$NEWLY_INTRODUCED_FAILURES_COUNT"; fi)
|
|
1038
|
-
$(if [ "$TEST_FAILURE_CLASSIFICATION_STATUS" = "completed" ] && [ -f ${KASEKI_RESULTS_DIR}/test-baseline-comparison.json ]; then printf ' - See test-baseline-comparison.json for full breakdown\n'; fi)
|
|
1040
|
+
$(if [ "$TEST_FAILURE_CLASSIFICATION_STATUS" = "completed" ] && [ -f "${KASEKI_RESULTS_DIR}"/test-baseline-comparison.json ]; then printf ' - See test-baseline-comparison.json for full breakdown\n'; fi)
|
|
1039
1041
|
- Quality checks: $QUALITY_EXIT
|
|
1040
1042
|
- Secret scan: $SECRET_SCAN_EXIT
|
|
1041
1043
|
- GitHub PR: $pr_status
|
|
@@ -1077,12 +1079,12 @@ SUMMARY
|
|
|
1077
1079
|
write_failure_json() {
|
|
1078
1080
|
local exit_code="$1"
|
|
1079
1081
|
local stderr_tail
|
|
1080
|
-
stderr_tail="$(tail -20 ${KASEKI_RESULTS_DIR}/stderr.log 2>/dev/null || true)"
|
|
1082
|
+
stderr_tail="$(tail -20 "${KASEKI_RESULTS_DIR}"/stderr.log 2>/dev/null || true)"
|
|
1081
1083
|
if [ "$exit_code" -eq 0 ]; then
|
|
1082
|
-
: > ${KASEKI_RESULTS_DIR}/failure.json
|
|
1084
|
+
: > "${KASEKI_RESULTS_DIR}"/failure.json
|
|
1083
1085
|
return 0
|
|
1084
1086
|
fi
|
|
1085
|
-
cat > ${KASEKI_RESULTS_DIR}/failure.json <<FAILURE
|
|
1087
|
+
cat > "${KASEKI_RESULTS_DIR}"/failure.json <<FAILURE
|
|
1086
1088
|
{
|
|
1087
1089
|
"instance": $(printf '%s' "$INSTANCE_NAME" | json_encode),
|
|
1088
1090
|
"exit_code": $exit_code,
|
|
@@ -1112,21 +1114,21 @@ FAILURE
|
|
|
1112
1114
|
|
|
1113
1115
|
collect_git_artifacts() {
|
|
1114
1116
|
DIFF_NONEMPTY=false
|
|
1115
|
-
if [ -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
1117
|
+
if [ -d "${KASEKI_WORKSPACE_DIR}"/repo/.git ]; then
|
|
1116
1118
|
while IFS= read -r untracked_file || [ -n "$untracked_file" ]; do
|
|
1117
1119
|
[ -z "$untracked_file" ] && continue
|
|
1118
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo add -N -- "$untracked_file" 2>/dev/null || true
|
|
1119
|
-
done < <(git -C ${KASEKI_WORKSPACE_DIR}/repo ls-files --others --exclude-standard 2>/dev/null || true)
|
|
1120
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo status --short > ${KASEKI_RESULTS_DIR}/git.status 2>/dev/null || true
|
|
1121
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo diff -- . > ${KASEKI_RESULTS_DIR}/git.diff 2>/dev/null || true
|
|
1122
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo diff --name-only -- . > ${KASEKI_RESULTS_DIR}/changed-files.txt 2>/dev/null || true
|
|
1123
|
-
if [ -s ${KASEKI_RESULTS_DIR}/git.diff ]; then
|
|
1120
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo add -N -- "$untracked_file" 2>/dev/null || true
|
|
1121
|
+
done < <(git -C "${KASEKI_WORKSPACE_DIR}"/repo ls-files --others --exclude-standard 2>/dev/null || true)
|
|
1122
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo status --short > "${KASEKI_RESULTS_DIR}"/git.status 2>/dev/null || true
|
|
1123
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo diff -- . > "${KASEKI_RESULTS_DIR}"/git.diff 2>/dev/null || true
|
|
1124
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo diff --name-only -- . > "${KASEKI_RESULTS_DIR}"/changed-files.txt 2>/dev/null || true
|
|
1125
|
+
if [ -s "${KASEKI_RESULTS_DIR}"/git.diff ]; then
|
|
1124
1126
|
DIFF_NONEMPTY=true
|
|
1125
1127
|
fi
|
|
1126
1128
|
else
|
|
1127
|
-
: > ${KASEKI_RESULTS_DIR}/git.status
|
|
1128
|
-
: > ${KASEKI_RESULTS_DIR}/git.diff
|
|
1129
|
-
: > ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
1129
|
+
: > "${KASEKI_RESULTS_DIR}"/git.status
|
|
1130
|
+
: > "${KASEKI_RESULTS_DIR}"/git.diff
|
|
1131
|
+
: > "${KASEKI_RESULTS_DIR}"/changed-files.txt
|
|
1130
1132
|
fi
|
|
1131
1133
|
}
|
|
1132
1134
|
|
|
@@ -1175,7 +1177,7 @@ run_static_test_impact_check() {
|
|
|
1175
1177
|
"warning_type=test_impact_without_tests" \
|
|
1176
1178
|
"artifact=$artifact" \
|
|
1177
1179
|
"detail=$warning_detail"
|
|
1178
|
-
printf '[warning] test-impact: %s (artifact: %s)\n' "$warning_detail" "$artifact" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
1180
|
+
printf '[warning] test-impact: %s (artifact: %s)\n' "$warning_detail" "$artifact" | tee -a "${KASEKI_RESULTS_DIR}"/progress.log
|
|
1179
1181
|
return 0
|
|
1180
1182
|
}
|
|
1181
1183
|
|
|
@@ -1188,21 +1190,22 @@ run_expectation_mismatch_detector() {
|
|
|
1188
1190
|
fi
|
|
1189
1191
|
|
|
1190
1192
|
: > "$EXPECTATION_MISMATCH_WARNINGS_ARTIFACT"
|
|
1191
|
-
if [ ! -s ${KASEKI_RESULTS_DIR}/git.diff ]; then
|
|
1192
|
-
|
|
1193
|
+
if [ ! -s "${KASEKI_RESULTS_DIR}"/git.diff ]; then
|
|
1194
|
+
# shellcheck disable=SC2086
|
|
1195
|
+
printf '[expectation-mismatch] skipped: "${KASEKI_RESULTS_DIR}"/git.diff is empty\n' >> ${KASEKI_RESULTS_DIR}/progress.log
|
|
1193
1196
|
return 0
|
|
1194
1197
|
fi
|
|
1195
1198
|
if [ ! -f "$detector_script" ]; then
|
|
1196
|
-
printf '[expectation-mismatch] skipped: detector script not found (%s)\n' "$detector_script" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
1199
|
+
printf '[expectation-mismatch] skipped: detector script not found (%s)\n' "$detector_script" | tee -a "${KASEKI_RESULTS_DIR}"/progress.log
|
|
1197
1200
|
return 0
|
|
1198
1201
|
fi
|
|
1199
1202
|
|
|
1200
1203
|
if ! node "$detector_script" \
|
|
1201
|
-
--repo ${KASEKI_WORKSPACE_DIR}/repo \
|
|
1202
|
-
--diff ${KASEKI_RESULTS_DIR}/git.diff \
|
|
1204
|
+
--repo "${KASEKI_WORKSPACE_DIR}"/repo \
|
|
1205
|
+
--diff "${KASEKI_RESULTS_DIR}"/git.diff \
|
|
1203
1206
|
--output "$EXPECTATION_MISMATCH_WARNINGS_ARTIFACT" \
|
|
1204
|
-
--progress ${KASEKI_RESULTS_DIR}/progress.log; then
|
|
1205
|
-
printf '[expectation-mismatch] warning: detector failed; continuing to validation\n' | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
1207
|
+
--progress "${KASEKI_RESULTS_DIR}"/progress.log; then
|
|
1208
|
+
printf '[expectation-mismatch] warning: detector failed; continuing to validation\n' | tee -a "${KASEKI_RESULTS_DIR}"/progress.log
|
|
1206
1209
|
fi
|
|
1207
1210
|
}
|
|
1208
1211
|
|
|
@@ -1313,7 +1316,7 @@ run_scouting_allowlist_coverage() {
|
|
|
1313
1316
|
local scouting_artifact agent_patterns validation_patterns
|
|
1314
1317
|
scouting_artifact="${1:?missing scouting artifact path}"
|
|
1315
1318
|
|
|
1316
|
-
if [ ! -f "$scouting_artifact" ] || [ ! -f ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
1319
|
+
if [ ! -f "$scouting_artifact" ] || [ ! -f "${KASEKI_RESULTS_DIR}"/changed-files.txt ]; then
|
|
1317
1320
|
return 0
|
|
1318
1321
|
fi
|
|
1319
1322
|
|
|
@@ -1374,12 +1377,12 @@ run_scouting_allowlist_coverage() {
|
|
|
1374
1377
|
if [ -n "$validation_warnings" ]; then
|
|
1375
1378
|
printf ' ⚠ validation_phase warning: %s\n' "$validation_warnings"
|
|
1376
1379
|
fi
|
|
1377
|
-
} | tee -a ${KASEKI_RESULTS_DIR}/scouting-report.md >> ${KASEKI_RESULTS_DIR}/quality.log
|
|
1380
|
+
} | tee -a "${KASEKI_RESULTS_DIR}"/scouting-report.md >> "${KASEKI_RESULTS_DIR}"/quality.log
|
|
1378
1381
|
fi
|
|
1379
1382
|
}
|
|
1380
1383
|
|
|
1381
1384
|
restore_disallowed_changes() {
|
|
1382
|
-
if [ "$KASEKI_RESTORE_DISALLOWED_CHANGES" != "1" ] || [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
1385
|
+
if [ "$KASEKI_RESTORE_DISALLOWED_CHANGES" != "1" ] || [ ! -d "${KASEKI_WORKSPACE_DIR}"/repo/.git ]; then
|
|
1383
1386
|
return 0
|
|
1384
1387
|
fi
|
|
1385
1388
|
|
|
@@ -1392,7 +1395,7 @@ restore_disallowed_changes() {
|
|
|
1392
1395
|
coverage=0
|
|
1393
1396
|
|
|
1394
1397
|
# Initialize restoration tracking file
|
|
1395
|
-
: > ${KASEKI_RESULTS_DIR}/restoration.jsonl
|
|
1398
|
+
: > "${KASEKI_RESULTS_DIR}"/restoration.jsonl
|
|
1396
1399
|
|
|
1397
1400
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
1398
1401
|
[ -z "$changed_file" ] && continue
|
|
@@ -1402,21 +1405,21 @@ restore_disallowed_changes() {
|
|
|
1402
1405
|
{
|
|
1403
1406
|
printf '{"timestamp":"%s","event":"file_evaluated","file":"%s","status":"kept","reason":"matched_allowlist"}\n' \
|
|
1404
1407
|
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$(printf '%s' "$changed_file" | sed 's/"/\\"/g')"
|
|
1405
|
-
} >> ${KASEKI_RESULTS_DIR}/restoration.jsonl
|
|
1408
|
+
} >> "${KASEKI_RESULTS_DIR}"/restoration.jsonl
|
|
1406
1409
|
continue
|
|
1407
1410
|
fi
|
|
1408
1411
|
# File did not match allowlist - restore it
|
|
1409
1412
|
restored_count=$((restored_count + 1))
|
|
1410
|
-
printf -- 'Restoring changed file outside allowlist before validation: %s\n' "$changed_file" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
1413
|
+
printf -- 'Restoring changed file outside allowlist before validation: %s\n' "$changed_file" | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
1411
1414
|
emit_event "quality_gate_rule_evaluated" "rule=allowlist_restore" "passed=true" "file=$changed_file"
|
|
1412
1415
|
{
|
|
1413
1416
|
printf '{"timestamp":"%s","event":"file_restored","file":"%s","status":"restored","reason":"not_in_allowlist"}\n' \
|
|
1414
1417
|
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$(printf '%s' "$changed_file" | sed 's/"/\\"/g')"
|
|
1415
|
-
} >> ${KASEKI_RESULTS_DIR}/restoration.jsonl
|
|
1416
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo restore --staged --worktree -- "$changed_file" 2>/dev/null || true
|
|
1417
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo clean -f -- "$changed_file" 2>/dev/null || true
|
|
1418
|
+
} >> "${KASEKI_RESULTS_DIR}"/restoration.jsonl
|
|
1419
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo restore --staged --worktree -- "$changed_file" 2>/dev/null || true
|
|
1420
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo clean -f -- "$changed_file" 2>/dev/null || true
|
|
1418
1421
|
restored_any=1
|
|
1419
|
-
done < ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
1422
|
+
done < "${KASEKI_RESULTS_DIR}"/changed-files.txt
|
|
1420
1423
|
|
|
1421
1424
|
# Emit restoration summary to quality.log with actionable guidance
|
|
1422
1425
|
if [ $((restored_count + kept_count)) -gt 0 ]; then
|
|
@@ -1432,7 +1435,7 @@ restore_disallowed_changes() {
|
|
|
1432
1435
|
printf ' 3. Update KASEKI_CHANGED_FILES_ALLOWLIST and re-run\n'
|
|
1433
1436
|
printf 'See docs/QUALITY_GATES.md for more guidance.\n'
|
|
1434
1437
|
fi
|
|
1435
|
-
} | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
1438
|
+
} | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
1436
1439
|
emit_event "allowlist_restoration_complete" "restored=$restored_count" "kept=$kept_count" "coverage=$coverage"
|
|
1437
1440
|
fi
|
|
1438
1441
|
|
|
@@ -1442,7 +1445,7 @@ restore_disallowed_changes() {
|
|
|
1442
1445
|
}
|
|
1443
1446
|
|
|
1444
1447
|
generate_restoration_report() {
|
|
1445
|
-
if [ ! -f ${KASEKI_RESULTS_DIR}/restoration.jsonl ]; then
|
|
1448
|
+
if [ ! -f "${KASEKI_RESULTS_DIR}"/restoration.jsonl ]; then
|
|
1446
1449
|
printf '[debug] restoration report: skipping - restoration.jsonl not found\n' >&2
|
|
1447
1450
|
return 0
|
|
1448
1451
|
fi
|
|
@@ -1451,7 +1454,7 @@ generate_restoration_report() {
|
|
|
1451
1454
|
|
|
1452
1455
|
# Safely extract counts from restoration.jsonl with validation
|
|
1453
1456
|
printf '[debug] restoration report: extracting counts from restoration.jsonl\n' >&2
|
|
1454
|
-
restored_count=$(grep -c '"status":"restored"' ${KASEKI_RESULTS_DIR}/restoration.jsonl 2>/dev/null || true)
|
|
1457
|
+
restored_count=$(grep -c '"status":"restored"' "${KASEKI_RESULTS_DIR}"/restoration.jsonl 2>/dev/null || true)
|
|
1455
1458
|
restored_count=${restored_count:-0}
|
|
1456
1459
|
printf '[debug] restoration report: restored_count="%s"\n' "$restored_count" >&2
|
|
1457
1460
|
if ! validate_numeric "restored_count" "$restored_count"; then
|
|
@@ -1459,7 +1462,7 @@ generate_restoration_report() {
|
|
|
1459
1462
|
return 1
|
|
1460
1463
|
fi
|
|
1461
1464
|
|
|
1462
|
-
kept_count=$(grep -c '"status":"kept"' ${KASEKI_RESULTS_DIR}/restoration.jsonl 2>/dev/null || true)
|
|
1465
|
+
kept_count=$(grep -c '"status":"kept"' "${KASEKI_RESULTS_DIR}"/restoration.jsonl 2>/dev/null || true)
|
|
1463
1466
|
kept_count=${kept_count:-0}
|
|
1464
1467
|
printf '[debug] restoration report: kept_count="%s"\n' "$kept_count" >&2
|
|
1465
1468
|
if ! validate_numeric "kept_count" "$kept_count"; then
|
|
@@ -1497,12 +1500,12 @@ generate_restoration_report() {
|
|
|
1497
1500
|
if [ "$restored_count" -gt 0 ]; then
|
|
1498
1501
|
printf '## Restored Files\n\n'
|
|
1499
1502
|
printf 'These files were modified by the agent but restored because they fall outside the allowlist:\n\n'
|
|
1500
|
-
grep '"status":"restored"' ${KASEKI_RESULTS_DIR}/restoration.jsonl | \
|
|
1503
|
+
grep '"status":"restored"' "${KASEKI_RESULTS_DIR}"/restoration.jsonl | \
|
|
1501
1504
|
sed "s/.*\"file\":\"\([^\"]*\)\".*/- \`\1\`/" | \
|
|
1502
|
-
sort | uniq >> ${KASEKI_RESULTS_DIR}/restoration-report.md.tmp 2>/dev/null || true
|
|
1503
|
-
if [ -f ${KASEKI_RESULTS_DIR}/restoration-report.md.tmp ]; then
|
|
1504
|
-
cat ${KASEKI_RESULTS_DIR}/restoration-report.md.tmp
|
|
1505
|
-
rm -f ${KASEKI_RESULTS_DIR}/restoration-report.md.tmp
|
|
1505
|
+
sort | uniq >> "${KASEKI_RESULTS_DIR}"/restoration-report.md.tmp 2>/dev/null || true
|
|
1506
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/restoration-report.md.tmp ]; then
|
|
1507
|
+
cat "${KASEKI_RESULTS_DIR}"/restoration-report.md.tmp
|
|
1508
|
+
rm -f "${KASEKI_RESULTS_DIR}"/restoration-report.md.tmp
|
|
1506
1509
|
fi
|
|
1507
1510
|
printf '\n'
|
|
1508
1511
|
fi
|
|
@@ -1510,12 +1513,12 @@ generate_restoration_report() {
|
|
|
1510
1513
|
if [ "$kept_count" -gt 0 ]; then
|
|
1511
1514
|
printf '## Kept Files (Allowlist Matches)\n\n'
|
|
1512
1515
|
printf 'These files were in the allowlist and were kept:\n\n'
|
|
1513
|
-
grep '"status":"kept"' ${KASEKI_RESULTS_DIR}/restoration.jsonl | \
|
|
1516
|
+
grep '"status":"kept"' "${KASEKI_RESULTS_DIR}"/restoration.jsonl | \
|
|
1514
1517
|
sed "s/.*\"file\":\"\([^\"]*\)\".*/- \`\1\`/" | \
|
|
1515
|
-
sort | uniq >> ${KASEKI_RESULTS_DIR}/restoration-report.md.tmp 2>/dev/null || true
|
|
1516
|
-
if [ -f ${KASEKI_RESULTS_DIR}/restoration-report.md.tmp ]; then
|
|
1517
|
-
cat ${KASEKI_RESULTS_DIR}/restoration-report.md.tmp
|
|
1518
|
-
rm -f ${KASEKI_RESULTS_DIR}/restoration-report.md.tmp
|
|
1518
|
+
sort | uniq >> "${KASEKI_RESULTS_DIR}"/restoration-report.md.tmp 2>/dev/null || true
|
|
1519
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/restoration-report.md.tmp ]; then
|
|
1520
|
+
cat "${KASEKI_RESULTS_DIR}"/restoration-report.md.tmp
|
|
1521
|
+
rm -f "${KASEKI_RESULTS_DIR}"/restoration-report.md.tmp
|
|
1519
1522
|
fi
|
|
1520
1523
|
printf '\n'
|
|
1521
1524
|
fi
|
|
@@ -1533,14 +1536,14 @@ generate_restoration_report() {
|
|
|
1533
1536
|
printf 'KASEKI_CHANGED_FILES_ALLOWLIST="<your-pattern>" ./run-kaseki.sh\n'
|
|
1534
1537
|
printf '```\n\n'
|
|
1535
1538
|
printf "For help on allowlist patterns, see \`docs/QUALITY_GATES.md\`.\n"
|
|
1536
|
-
} > ${KASEKI_RESULTS_DIR}/restoration-report.md
|
|
1539
|
+
} > "${KASEKI_RESULTS_DIR}"/restoration-report.md
|
|
1537
1540
|
}
|
|
1538
1541
|
|
|
1539
1542
|
check_validation_allowlist() {
|
|
1540
1543
|
if [ -z "$KASEKI_VALIDATION_ALLOWLIST" ]; then
|
|
1541
1544
|
return 0
|
|
1542
1545
|
fi
|
|
1543
|
-
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
1546
|
+
if [ ! -d "${KASEKI_WORKSPACE_DIR}"/repo/.git ]; then
|
|
1544
1547
|
return 0
|
|
1545
1548
|
fi
|
|
1546
1549
|
|
|
@@ -1566,14 +1569,14 @@ check_validation_allowlist() {
|
|
|
1566
1569
|
}
|
|
1567
1570
|
}
|
|
1568
1571
|
' "$validation_before_state_file" "$validation_after_state_file" | LC_ALL=C sort -u > "$validation_changed_file"
|
|
1569
|
-
elif [ -f ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
1570
|
-
cp ${KASEKI_RESULTS_DIR}/changed-files.txt "$validation_changed_file"
|
|
1572
|
+
elif [ -f "${KASEKI_RESULTS_DIR}"/changed-files.txt ]; then
|
|
1573
|
+
cp "${KASEKI_RESULTS_DIR}"/changed-files.txt "$validation_changed_file"
|
|
1571
1574
|
fi
|
|
1572
1575
|
|
|
1573
1576
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
1574
1577
|
[ -z "$changed_file" ] && continue
|
|
1575
1578
|
if ! printf '%s\n' "$changed_file" | grep -Eq "^(${allowlist_regex})$"; then
|
|
1576
|
-
printf 'Validation-phase file outside allowlist: %s\n' "$changed_file" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
1579
|
+
printf 'Validation-phase file outside allowlist: %s\n' "$changed_file" | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
1577
1580
|
validation_violation_count=$((validation_violation_count + 1))
|
|
1578
1581
|
emit_event "quality_gate_rule_evaluated" "rule=validation_allowlist" "passed=false" "file=$changed_file"
|
|
1579
1582
|
else
|
|
@@ -1585,7 +1588,7 @@ check_validation_allowlist() {
|
|
|
1585
1588
|
QUALITY_EXIT=7
|
|
1586
1589
|
VALIDATION_ALLOWLIST_FAILURE_REASON="validation_allowlist_check: $validation_violation_count file(s) changed during validation outside KASEKI_VALIDATION_ALLOWLIST"
|
|
1587
1590
|
QUALITY_FAILURE_REASON="$VALIDATION_ALLOWLIST_FAILURE_REASON"
|
|
1588
|
-
printf '\n[validation-allowlist] %d file(s) modified during validation outside allowlist\n' "$validation_violation_count" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
1591
|
+
printf '\n[validation-allowlist] %d file(s) modified during validation outside allowlist\n' "$validation_violation_count" | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
1589
1592
|
return 1
|
|
1590
1593
|
fi
|
|
1591
1594
|
return 0
|
|
@@ -1605,7 +1608,7 @@ check_secret_scan_allowlist() {
|
|
|
1605
1608
|
|
|
1606
1609
|
# Read the log into a temp variable to avoid SC2094 (read-write in same pipeline)
|
|
1607
1610
|
local temp_log
|
|
1608
|
-
temp_log=$(cat ${KASEKI_RESULTS_DIR}/secret-scan.log)
|
|
1611
|
+
temp_log=$(cat "${KASEKI_RESULTS_DIR}"/secret-scan.log)
|
|
1609
1612
|
|
|
1610
1613
|
while IFS= read -r match_line || [ -n "$match_line" ]; do
|
|
1611
1614
|
[ -z "$match_line" ] && continue
|
|
@@ -1619,8 +1622,8 @@ check_secret_scan_allowlist() {
|
|
|
1619
1622
|
|
|
1620
1623
|
[ -z "$pattern" ] && continue
|
|
1621
1624
|
|
|
1622
|
-
# Normalize file path: remove leading ${KASEKI_WORKSPACE_DIR}/repo/, repo/, and ./ if present
|
|
1623
|
-
file_path="${file_path
|
|
1625
|
+
# Normalize file path: remove leading "${KASEKI_WORKSPACE_DIR}"/repo/, repo/, and ./ if present
|
|
1626
|
+
file_path="${file_path#"${KASEKI_WORKSPACE_DIR}"/repo/}"
|
|
1624
1627
|
file_path="${file_path#repo/}"
|
|
1625
1628
|
file_path="${file_path#./}"
|
|
1626
1629
|
|
|
@@ -1645,7 +1648,7 @@ check_secret_scan_allowlist() {
|
|
|
1645
1648
|
for match in "${secret_matches[@]}"; do
|
|
1646
1649
|
printf '%s\n' "$match"
|
|
1647
1650
|
done
|
|
1648
|
-
} > ${KASEKI_RESULTS_DIR}/secret-scan.log
|
|
1651
|
+
} > "${KASEKI_RESULTS_DIR}"/secret-scan.log
|
|
1649
1652
|
|
|
1650
1653
|
# Exit code 6 only if there are unallowlisted matches
|
|
1651
1654
|
if [ "$unallowlisted_count" -gt 0 ]; then
|
|
@@ -1679,9 +1682,9 @@ finish() {
|
|
|
1679
1682
|
printf '[unexpected-failure] Exit code: %d\n' "$code"
|
|
1680
1683
|
printf '[unexpected-failure] Last command: %s\n' "$LAST_COMMAND"
|
|
1681
1684
|
printf '[unexpected-failure] Current stage: %s\n' "$CURRENT_STAGE"
|
|
1682
|
-
if [ -f ${KASEKI_RESULTS_DIR}/progress.log ]; then
|
|
1685
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/progress.log ]; then
|
|
1683
1686
|
printf '[unexpected-failure] Last 5 progress entries:\n'
|
|
1684
|
-
tail -5 ${KASEKI_RESULTS_DIR}/progress.log | sed 's/^/ /'
|
|
1687
|
+
tail -5 "${KASEKI_RESULTS_DIR}"/progress.log | sed 's/^/ /'
|
|
1685
1688
|
fi
|
|
1686
1689
|
} | tee -a "$LAST_COMMAND_LOG" >&2
|
|
1687
1690
|
emit_error_event "unexpected_shell_failure" "Uncaught shell error (exit $code) in stage '$CURRENT_STAGE'. Last command: $LAST_COMMAND. See $LAST_COMMAND_LOG for context." "exit"
|
|
@@ -1690,16 +1693,16 @@ finish() {
|
|
|
1690
1693
|
maybe_call_finish_helper collect_git_artifacts
|
|
1691
1694
|
|
|
1692
1695
|
# Analyze test failures and compare baseline vs. working results
|
|
1693
|
-
if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ] && [ -f ${KASEKI_RESULTS_DIR}/validation-baseline.log ] && [ -f ${KASEKI_RESULTS_DIR}/pre-validation.log ]; then
|
|
1696
|
+
if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ] && [ -f "${KASEKI_RESULTS_DIR}"/validation-baseline.log ] && [ -f ${KASEKI_RESULTS_DIR}/pre-validation.log ]; then
|
|
1694
1697
|
set_current_stage "test failure analysis"
|
|
1695
1698
|
if analyze_test_failures_baseline; then
|
|
1696
1699
|
TEST_FAILURE_CLASSIFICATION_STATUS="completed"
|
|
1697
1700
|
# Try to extract newly_introduced_failures_count from JSON output (if jq available)
|
|
1698
|
-
if [ -f ${KASEKI_RESULTS_DIR}/test-baseline-comparison.json ] && command -v jq >/dev/null 2>&1; then
|
|
1699
|
-
NEWLY_INTRODUCED_FAILURES_COUNT=$(jq -r '.summary.total_newly_introduced // 0' ${KASEKI_RESULTS_DIR}/test-baseline-comparison.json 2>/dev/null || printf '0')
|
|
1700
|
-
elif [ -f ${KASEKI_RESULTS_DIR}/test-baseline-comparison.json ]; then
|
|
1701
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/test-baseline-comparison.json ] && command -v jq >/dev/null 2>&1; then
|
|
1702
|
+
NEWLY_INTRODUCED_FAILURES_COUNT=$(jq -r '.summary.total_newly_introduced // 0' "${KASEKI_RESULTS_DIR}"/test-baseline-comparison.json 2>/dev/null || printf '0')
|
|
1703
|
+
elif [ -f "${KASEKI_RESULTS_DIR}"/test-baseline-comparison.json ]; then
|
|
1701
1704
|
# Fallback: try to extract with grep/sed if jq not available
|
|
1702
|
-
NEWLY_INTRODUCED_FAILURES_COUNT=$(grep -o '"total_newly_introduced": [0-9]*' ${KASEKI_RESULTS_DIR}/test-baseline-comparison.json 2>/dev/null | grep -o '[0-9]*$' || printf '0')
|
|
1705
|
+
NEWLY_INTRODUCED_FAILURES_COUNT=$(grep -o '"total_newly_introduced": [0-9]*' "${KASEKI_RESULTS_DIR}"/test-baseline-comparison.json 2>/dev/null | grep -o '[0-9]*$' || printf '0')
|
|
1703
1706
|
fi
|
|
1704
1707
|
else
|
|
1705
1708
|
TEST_FAILURE_CLASSIFICATION_STATUS="failed"
|
|
@@ -1713,8 +1716,8 @@ finish() {
|
|
|
1713
1716
|
fi
|
|
1714
1717
|
|
|
1715
1718
|
# Debug output for restoration report generation
|
|
1716
|
-
if [ -f ${KASEKI_RESULTS_DIR}/restoration.jsonl ]; then
|
|
1717
|
-
printf '[debug] restoration.jsonl exists (size=%d bytes)\n' "$(wc -c < ${KASEKI_RESULTS_DIR}/restoration.jsonl)" >&2
|
|
1719
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/restoration.jsonl ]; then
|
|
1720
|
+
printf '[debug] restoration.jsonl exists (size=%d bytes)\n' "$(wc -c < "${KASEKI_RESULTS_DIR}"/restoration.jsonl)" >&2
|
|
1718
1721
|
else
|
|
1719
1722
|
printf '[debug] restoration.jsonl does not exist\n' >&2
|
|
1720
1723
|
fi
|
|
@@ -1732,12 +1735,12 @@ finish() {
|
|
|
1732
1735
|
|
|
1733
1736
|
# Calculate and record maturity score
|
|
1734
1737
|
if [ -x /app/scripts/kaseki-maturity-score.sh ]; then
|
|
1735
|
-
/app/scripts/kaseki-maturity-score.sh ${KASEKI_WORKSPACE_DIR}/repo ${KASEKI_RESULTS_DIR}/maturity-score.json 2>/dev/null || true
|
|
1738
|
+
/app/scripts/kaseki-maturity-score.sh "${KASEKI_WORKSPACE_DIR}"/repo "${KASEKI_RESULTS_DIR}"/maturity-score.json 2>/dev/null || true
|
|
1736
1739
|
fi
|
|
1737
1740
|
|
|
1738
1741
|
# Calculate and record performance metrics
|
|
1739
|
-
if [ -x /app/scripts/kaseki-performance-metrics.sh ] && [ -f ${KASEKI_RESULTS_DIR}/stage-timings.tsv ]; then
|
|
1740
|
-
/app/scripts/kaseki-performance-metrics.sh ${KASEKI_RESULTS_DIR}/stage-timings.tsv ${KASEKI_RESULTS_DIR}/performance-metrics.json 2>/dev/null || true
|
|
1742
|
+
if [ -x /app/scripts/kaseki-performance-metrics.sh ] && [ -f "${KASEKI_RESULTS_DIR}"/stage-timings.tsv ]; then
|
|
1743
|
+
/app/scripts/kaseki-performance-metrics.sh "${KASEKI_RESULTS_DIR}"/stage-timings.tsv ${KASEKI_RESULTS_DIR}/performance-metrics.json 2>/dev/null || true
|
|
1741
1744
|
fi
|
|
1742
1745
|
|
|
1743
1746
|
maybe_call_finish_helper write_result_summary
|
|
@@ -1790,7 +1793,7 @@ run_step_dry() {
|
|
|
1790
1793
|
printf '\n==> %s (DRY-RUN: simulated)\n' "$label"
|
|
1791
1794
|
emit_progress "$label" "started (dry-run)"
|
|
1792
1795
|
# Show what commands would be run without executing them
|
|
1793
|
-
printf '%s\n' "$@" >> ${KASEKI_RESULTS_DIR}/validation.log
|
|
1796
|
+
printf '%s\n' "$@" >> "${KASEKI_RESULTS_DIR}"/validation.log
|
|
1794
1797
|
step_end="$(date +%s)"
|
|
1795
1798
|
emit_progress "$label" "finished (dry-run, simulated exit 0)"
|
|
1796
1799
|
record_stage_timing "$label" "0" "$((step_end - step_start))" "dry-run"
|
|
@@ -1825,9 +1828,9 @@ is_valid_git_mirror() {
|
|
|
1825
1828
|
}
|
|
1826
1829
|
|
|
1827
1830
|
run_direct_clone() {
|
|
1828
|
-
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1831
|
+
rm -rf "${KASEKI_WORKSPACE_DIR}"/repo
|
|
1829
1832
|
GIT_CLONE_STRATEGY="direct_shallow"
|
|
1830
|
-
git clone --depth 1 --branch "$GIT_REF" "$REPO_URL" ${KASEKI_WORKSPACE_DIR}/repo
|
|
1833
|
+
git clone --depth 1 --branch "$GIT_REF" "$REPO_URL" "${KASEKI_WORKSPACE_DIR}"/repo
|
|
1831
1834
|
}
|
|
1832
1835
|
|
|
1833
1836
|
clone_with_git_cache() {
|
|
@@ -1904,25 +1907,25 @@ clone_with_git_cache() {
|
|
|
1904
1907
|
fi
|
|
1905
1908
|
flock -u 9 || true
|
|
1906
1909
|
|
|
1907
|
-
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1910
|
+
rm -rf "${KASEKI_WORKSPACE_DIR}"/repo
|
|
1908
1911
|
GIT_CLONE_STRATEGY="reference_shallow"
|
|
1909
|
-
git clone --reference-if-able "$mirror" --depth 1 --branch "$GIT_REF" "$REPO_URL" ${KASEKI_WORKSPACE_DIR}/repo
|
|
1912
|
+
git clone --reference-if-able "$mirror" --depth 1 --branch "$GIT_REF" "$REPO_URL" "${KASEKI_WORKSPACE_DIR}"/repo
|
|
1910
1913
|
clone_rc=$?
|
|
1911
1914
|
if [ "$clone_rc" -eq 0 ]; then
|
|
1912
1915
|
return 0
|
|
1913
1916
|
fi
|
|
1914
1917
|
|
|
1915
|
-
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1918
|
+
rm -rf "${KASEKI_WORKSPACE_DIR}"/repo
|
|
1916
1919
|
GIT_CLONE_STRATEGY="mirror_local"
|
|
1917
1920
|
emit_error_event "git_cache_reference_clone_failed" "Reference clone failed for key=$GIT_CACHE_KEY exit=$clone_rc; trying local mirror clone" "try_mirror_clone"
|
|
1918
|
-
git clone --branch "$GIT_REF" "$mirror" ${KASEKI_WORKSPACE_DIR}/repo
|
|
1921
|
+
git clone --branch "$GIT_REF" "$mirror" "${KASEKI_WORKSPACE_DIR}"/repo
|
|
1919
1922
|
clone_rc=$?
|
|
1920
|
-
if [ "$clone_rc" -eq 0 ] && git -C ${KASEKI_WORKSPACE_DIR}/repo rev-parse --verify HEAD >/dev/null 2>&1; then
|
|
1921
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo remote set-url origin "$REPO_URL" >/dev/null 2>&1 || true
|
|
1923
|
+
if [ "$clone_rc" -eq 0 ] && git -C "${KASEKI_WORKSPACE_DIR}"/repo rev-parse --verify HEAD >/dev/null 2>&1; then
|
|
1924
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo remote set-url origin "$REPO_URL" >/dev/null 2>&1 || true
|
|
1922
1925
|
return 0
|
|
1923
1926
|
fi
|
|
1924
1927
|
|
|
1925
|
-
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1928
|
+
rm -rf "${KASEKI_WORKSPACE_DIR}"/repo
|
|
1926
1929
|
GIT_CACHE_STATUS="mirror_clone_failed"
|
|
1927
1930
|
emit_error_event "git_cache_mirror_clone_failed" "Mirror clone failed for key=$GIT_CACHE_KEY exit=$clone_rc; using direct clone" "fallback_direct_clone"
|
|
1928
1931
|
run_direct_clone
|
|
@@ -2302,9 +2305,9 @@ run_typescript_precheck() {
|
|
|
2302
2305
|
if ! has_npm_build_command "$KASEKI_TS_CHECK_COMMAND"; then
|
|
2303
2306
|
local missing_script
|
|
2304
2307
|
missing_script="$(npm_run_script_name "$KASEKI_TS_CHECK_COMMAND")" || missing_script="$KASEKI_TS_CHECK_COMMAND"
|
|
2305
|
-
printf '\n==> TypeScript pre-check\n' | tee -a ${KASEKI_RESULTS_DIR}/pre-validation-ts-check.log
|
|
2306
|
-
printf 'Command: %s\n' "$KASEKI_TS_CHECK_COMMAND" | tee -a ${KASEKI_RESULTS_DIR}/pre-validation-ts-check.log
|
|
2307
|
-
printf 'skipped: npm script "%s" not found in package.json\n' "$missing_script" | tee -a ${KASEKI_RESULTS_DIR}/pre-validation-ts-check.log
|
|
2308
|
+
printf '\n==> TypeScript pre-check\n' | tee -a "${KASEKI_RESULTS_DIR}"/pre-validation-ts-check.log
|
|
2309
|
+
printf 'Command: %s\n' "$KASEKI_TS_CHECK_COMMAND" | tee -a "${KASEKI_RESULTS_DIR}"/pre-validation-ts-check.log
|
|
2310
|
+
printf 'skipped: npm script "%s" not found in package.json\n' "$missing_script" | tee -a "${KASEKI_RESULTS_DIR}"/pre-validation-ts-check.log
|
|
2308
2311
|
emit_error_event "typescript_precheck_skipped_missing_script" "TypeScript check skipped: npm script '$missing_script' not defined" "continue"
|
|
2309
2312
|
emit_progress "typescript precheck" "skipped (npm script '$missing_script' not found)"
|
|
2310
2313
|
record_stage_timing "typescript precheck" 0 0 "skipped_missing_script"
|
|
@@ -2319,8 +2322,8 @@ run_typescript_precheck() {
|
|
|
2319
2322
|
{
|
|
2320
2323
|
printf '\n==> TypeScript pre-check\n'
|
|
2321
2324
|
printf 'Command: %s\n' "$KASEKI_TS_CHECK_COMMAND"
|
|
2322
|
-
eval "cd ${KASEKI_WORKSPACE_DIR}/repo && $KASEKI_TS_CHECK_COMMAND" 2>&1
|
|
2323
|
-
} 2>&1 | tee -a ${KASEKI_RESULTS_DIR}/pre-validation-ts-check.log
|
|
2325
|
+
eval "cd "${KASEKI_WORKSPACE_DIR}"/repo && $KASEKI_TS_CHECK_COMMAND" 2>&1
|
|
2326
|
+
} 2>&1 | tee -a "${KASEKI_RESULTS_DIR}"/pre-validation-ts-check.log
|
|
2324
2327
|
ts_check_exit="${PIPESTATUS[0]}"
|
|
2325
2328
|
|
|
2326
2329
|
ts_check_end="$(date +%s)"
|
|
@@ -2393,14 +2396,14 @@ run_trailing_whitespace_cleanup_for_changed_tracked_text_files() {
|
|
|
2393
2396
|
collect_changed_file_set() {
|
|
2394
2397
|
local output_file="$1"
|
|
2395
2398
|
: > "$output_file"
|
|
2396
|
-
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
2399
|
+
if [ ! -d "${KASEKI_WORKSPACE_DIR}"/repo/.git ]; then
|
|
2397
2400
|
return 0
|
|
2398
2401
|
fi
|
|
2399
2402
|
|
|
2400
2403
|
{
|
|
2401
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo diff --name-only -- . 2>/dev/null || true
|
|
2402
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo diff --name-only --cached -- . 2>/dev/null || true
|
|
2403
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo ls-files --others --exclude-standard 2>/dev/null || true
|
|
2404
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo diff --name-only -- . 2>/dev/null || true
|
|
2405
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo diff --name-only --cached -- . 2>/dev/null || true
|
|
2406
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo ls-files --others --exclude-standard 2>/dev/null || true
|
|
2404
2407
|
} | sed '/^$/d' | LC_ALL=C sort -u > "$output_file"
|
|
2405
2408
|
}
|
|
2406
2409
|
|
|
@@ -2408,7 +2411,7 @@ collect_changed_file_state() {
|
|
|
2408
2411
|
local output_file="$1"
|
|
2409
2412
|
local changed_files_file path staged_hash unstaged_hash content_hash state
|
|
2410
2413
|
: > "$output_file"
|
|
2411
|
-
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
2414
|
+
if [ ! -d "${KASEKI_WORKSPACE_DIR}"/repo/.git ]; then
|
|
2412
2415
|
return 0
|
|
2413
2416
|
fi
|
|
2414
2417
|
|
|
@@ -2417,12 +2420,12 @@ collect_changed_file_state() {
|
|
|
2417
2420
|
|
|
2418
2421
|
while IFS= read -r path || [ -n "$path" ]; do
|
|
2419
2422
|
[ -z "$path" ] && continue
|
|
2420
|
-
if git -C ${KASEKI_WORKSPACE_DIR}/repo ls-files --error-unmatch -- "$path" >/dev/null 2>&1; then
|
|
2421
|
-
staged_hash="$(git -C ${KASEKI_WORKSPACE_DIR}/repo diff --binary --cached -- "$path" 2>/dev/null | sha256sum | awk '{print $1}')"
|
|
2422
|
-
unstaged_hash="$(git -C ${KASEKI_WORKSPACE_DIR}/repo diff --binary -- "$path" 2>/dev/null | sha256sum | awk '{print $1}')"
|
|
2423
|
+
if git -C "${KASEKI_WORKSPACE_DIR}"/repo ls-files --error-unmatch -- "$path" >/dev/null 2>&1; then
|
|
2424
|
+
staged_hash="$(git -C "${KASEKI_WORKSPACE_DIR}"/repo diff --binary --cached -- "$path" 2>/dev/null | sha256sum | awk '{print $1}')"
|
|
2425
|
+
unstaged_hash="$(git -C "${KASEKI_WORKSPACE_DIR}"/repo diff --binary -- "$path" 2>/dev/null | sha256sum | awk '{print $1}')"
|
|
2423
2426
|
state="tracked:staged=${staged_hash}:unstaged=${unstaged_hash}"
|
|
2424
2427
|
elif [ -f "${KASEKI_WORKSPACE_DIR}/repo/$path" ]; then
|
|
2425
|
-
content_hash="$(git -C ${KASEKI_WORKSPACE_DIR}/repo hash-object --no-filters -- "$path" 2>/dev/null || sha256sum "${KASEKI_WORKSPACE_DIR}/repo/$path" 2>/dev/null | awk '{print $1}')"
|
|
2428
|
+
content_hash="$(git -C "${KASEKI_WORKSPACE_DIR}"/repo hash-object --no-filters -- "$path" 2>/dev/null || sha256sum "${KASEKI_WORKSPACE_DIR}/repo/$path" 2>/dev/null | awk '{print $1}')"
|
|
2426
2429
|
state="untracked:file=${content_hash}"
|
|
2427
2430
|
elif [ -d "${KASEKI_WORKSPACE_DIR}/repo/$path" ]; then
|
|
2428
2431
|
state="untracked:directory"
|
|
@@ -2442,10 +2445,10 @@ restore_cleanup_disallowed_changes() {
|
|
|
2442
2445
|
|
|
2443
2446
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
2444
2447
|
[ -z "$changed_file" ] && continue
|
|
2445
|
-
printf 'Restoring cleanup-created file outside allowlist: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" ${KASEKI_RESULTS_DIR}/quality.log
|
|
2448
|
+
printf 'Restoring cleanup-created file outside allowlist: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" "${KASEKI_RESULTS_DIR}"/quality.log
|
|
2446
2449
|
emit_event "auto_lint_cleanup_file_restored" "file=$changed_file" "reason=not_in_cleanup_allowlist"
|
|
2447
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo restore --staged --worktree -- "$changed_file" 2>/dev/null || true
|
|
2448
|
-
git -C ${KASEKI_WORKSPACE_DIR}/repo clean -f -- "$changed_file" 2>/dev/null || true
|
|
2450
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo restore --staged --worktree -- "$changed_file" 2>/dev/null || true
|
|
2451
|
+
git -C "${KASEKI_WORKSPACE_DIR}"/repo clean -f -- "$changed_file" 2>/dev/null || true
|
|
2449
2452
|
done < "$disallowed_file"
|
|
2450
2453
|
}
|
|
2451
2454
|
|
|
@@ -2460,7 +2463,7 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2460
2463
|
: > "$cleanup_created_file"
|
|
2461
2464
|
: > "$disallowed_file"
|
|
2462
2465
|
: > "$post_restore_file"
|
|
2463
|
-
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
2466
|
+
if [ ! -d "${KASEKI_WORKSPACE_DIR}"/repo/.git ]; then
|
|
2464
2467
|
return 0
|
|
2465
2468
|
fi
|
|
2466
2469
|
|
|
@@ -2475,7 +2478,7 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2475
2478
|
if [ -n "$allowlist_regex" ] && printf '%s\n' "$changed_file" | grep -Eq "^(${allowlist_regex})$"; then
|
|
2476
2479
|
emit_event "quality_gate_rule_evaluated" "rule=auto_lint_cleanup_allowlist" "passed=true" "file=$changed_file"
|
|
2477
2480
|
else
|
|
2478
|
-
printf 'Auto lint cleanup created changed file outside allowlist: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" ${KASEKI_RESULTS_DIR}/quality.log
|
|
2481
|
+
printf 'Auto lint cleanup created changed file outside allowlist: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" "${KASEKI_RESULTS_DIR}"/quality.log
|
|
2479
2482
|
printf '%s\n' "$changed_file" >> "$disallowed_file"
|
|
2480
2483
|
emit_event "quality_gate_rule_evaluated" "rule=auto_lint_cleanup_allowlist" "passed=false" "file=$changed_file"
|
|
2481
2484
|
fi
|
|
@@ -2492,12 +2495,12 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2492
2495
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
2493
2496
|
[ -z "$changed_file" ] && continue
|
|
2494
2497
|
if grep -Fxq -- "$changed_file" "$post_restore_file"; then
|
|
2495
|
-
printf 'ERROR: Cleanup-created disallowed change could not be restored: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" ${KASEKI_RESULTS_DIR}/quality.log
|
|
2498
|
+
printf 'ERROR: Cleanup-created disallowed change could not be restored: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" "${KASEKI_RESULTS_DIR}"/quality.log
|
|
2496
2499
|
unrestored_count=$((unrestored_count + 1))
|
|
2497
2500
|
fi
|
|
2498
2501
|
done < "$disallowed_file"
|
|
2499
2502
|
if [ "$unrestored_count" -eq 0 ]; then
|
|
2500
|
-
printf 'Auto lint cleanup restored %s cleanup-created file(s) outside allowlist.\n' "$disallowed_count" | tee -a "$AUTO_LINT_CLEANUP_LOG" ${KASEKI_RESULTS_DIR}/quality.log
|
|
2503
|
+
printf 'Auto lint cleanup restored %s cleanup-created file(s) outside allowlist.\n' "$disallowed_count" | tee -a "$AUTO_LINT_CLEANUP_LOG" "${KASEKI_RESULTS_DIR}"/quality.log
|
|
2501
2504
|
emit_event "auto_lint_cleanup_allowlist_restoration_complete" "restored=$disallowed_count" "unrestored=0"
|
|
2502
2505
|
collect_git_artifacts
|
|
2503
2506
|
return 0
|
|
@@ -2510,7 +2513,7 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2510
2513
|
AUTO_LINT_CLEANUP_FAILURE_CLASSIFICATION="cleanup_allowlist_failed"
|
|
2511
2514
|
QUALITY_EXIT=7
|
|
2512
2515
|
QUALITY_FAILURE_REASON="auto_lint_cleanup_allowlist: $disallowed_count cleanup-created file(s) outside KASEKI_CHANGED_FILES_ALLOWLIST/KASEKI_VALIDATION_ALLOWLIST"
|
|
2513
|
-
printf 'ERROR: %s\n' "$QUALITY_FAILURE_REASON" | tee -a "$AUTO_LINT_CLEANUP_LOG" ${KASEKI_RESULTS_DIR}/quality.log
|
|
2516
|
+
printf 'ERROR: %s\n' "$QUALITY_FAILURE_REASON" | tee -a "$AUTO_LINT_CLEANUP_LOG" "${KASEKI_RESULTS_DIR}"/quality.log
|
|
2514
2517
|
emit_error_event "auto_lint_cleanup_allowlist_failed" "$QUALITY_FAILURE_REASON" "continue"
|
|
2515
2518
|
return 1
|
|
2516
2519
|
}
|
|
@@ -2570,12 +2573,12 @@ run_auto_lint_cleanup() {
|
|
|
2570
2573
|
return 0
|
|
2571
2574
|
fi
|
|
2572
2575
|
|
|
2573
|
-
if ! [ -d ${KASEKI_WORKSPACE_DIR}/repo ]; then
|
|
2576
|
+
if ! [ -d "${KASEKI_WORKSPACE_DIR}"/repo ]; then
|
|
2574
2577
|
AUTO_LINT_CLEANUP_EXIT=1
|
|
2575
2578
|
AUTO_LINT_CLEANUP_RESULT="failed"
|
|
2576
2579
|
AUTO_LINT_CLEANUP_CLASSIFICATION="directory_missing"
|
|
2577
2580
|
AUTO_LINT_CLEANUP_FAILURE_CLASSIFICATION="directory_missing"
|
|
2578
|
-
printf 'ERROR: Working directory ${KASEKI_WORKSPACE_DIR}/repo does not exist before auto lint cleanup.\n' | tee -a "$AUTO_LINT_CLEANUP_LOG"
|
|
2581
|
+
printf 'ERROR: Working directory "${KASEKI_WORKSPACE_DIR}"/repo does not exist before auto lint cleanup.\n' | tee -a "$AUTO_LINT_CLEANUP_LOG"
|
|
2579
2582
|
printf 'workspace_missing\t%s\t0\tclassification=directory_missing\n' "$AUTO_LINT_CLEANUP_EXIT" >> "$AUTO_LINT_CLEANUP_TIMINGS_FILE"
|
|
2580
2583
|
record_stage_timing "$stage_label" "$AUTO_LINT_CLEANUP_EXIT" "$(($(date +%s) - stage_start))" "directory_missing classification=directory_missing"
|
|
2581
2584
|
emit_event "auto_lint_cleanup_finished" "exit_code=$AUTO_LINT_CLEANUP_EXIT" "result=failed" "classification=directory_missing" "reason=directory_missing"
|
|
@@ -2710,17 +2713,17 @@ restore_baseline_validation_from_cache() {
|
|
|
2710
2713
|
# Restore cached files to results directory
|
|
2711
2714
|
mkdir -p ${KASEKI_RESULTS_DIR}
|
|
2712
2715
|
|
|
2713
|
-
if ! cp "$cache_dir/validation.log" ${KASEKI_RESULTS_DIR}/validation-baseline.log 2>/dev/null; then
|
|
2716
|
+
if ! cp "$cache_dir/validation.log" "${KASEKI_RESULTS_DIR}"/validation-baseline.log 2>/dev/null; then
|
|
2714
2717
|
return 1
|
|
2715
2718
|
fi
|
|
2716
|
-
if ! cp "$cache_dir/validation-raw.log" ${KASEKI_RESULTS_DIR}/validation-baseline-raw.log 2>/dev/null; then
|
|
2719
|
+
if ! cp "$cache_dir/validation-raw.log" "${KASEKI_RESULTS_DIR}"/validation-baseline-raw.log 2>/dev/null; then
|
|
2717
2720
|
return 1
|
|
2718
2721
|
fi
|
|
2719
|
-
if ! cp "$cache_dir/validation-timings.tsv" ${KASEKI_RESULTS_DIR}/validation-baseline-timings.tsv 2>/dev/null; then
|
|
2722
|
+
if ! cp "$cache_dir/validation-timings.tsv" "${KASEKI_RESULTS_DIR}"/validation-baseline-timings.tsv 2>/dev/null; then
|
|
2720
2723
|
return 1
|
|
2721
2724
|
fi
|
|
2722
2725
|
if [ -f "$cache_dir/validation-env.log" ]; then
|
|
2723
|
-
cp "$cache_dir/validation-env.log" ${KASEKI_RESULTS_DIR}/validation-baseline-env.log 2>/dev/null || true
|
|
2726
|
+
cp "$cache_dir/validation-env.log" "${KASEKI_RESULTS_DIR}"/validation-baseline-env.log 2>/dev/null || true
|
|
2724
2727
|
fi
|
|
2725
2728
|
|
|
2726
2729
|
return 0
|
|
@@ -2737,20 +2740,20 @@ save_baseline_validation_to_cache() {
|
|
|
2737
2740
|
mkdir -p "$cache_dir" || return 1
|
|
2738
2741
|
|
|
2739
2742
|
# Save validation results to cache
|
|
2740
|
-
if [ -f ${KASEKI_RESULTS_DIR}/validation-baseline.log ]; then
|
|
2741
|
-
cp ${KASEKI_RESULTS_DIR}/validation-baseline.log "$cache_dir/validation.log" || return 1
|
|
2743
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/validation-baseline.log ]; then
|
|
2744
|
+
cp "${KASEKI_RESULTS_DIR}"/validation-baseline.log "$cache_dir/validation.log" || return 1
|
|
2742
2745
|
fi
|
|
2743
2746
|
|
|
2744
|
-
if [ -f ${KASEKI_RESULTS_DIR}/validation-baseline-raw.log ]; then
|
|
2745
|
-
cp ${KASEKI_RESULTS_DIR}/validation-baseline-raw.log "$cache_dir/validation-raw.log" || return 1
|
|
2747
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/validation-baseline-raw.log ]; then
|
|
2748
|
+
cp "${KASEKI_RESULTS_DIR}"/validation-baseline-raw.log "$cache_dir/validation-raw.log" || return 1
|
|
2746
2749
|
fi
|
|
2747
2750
|
|
|
2748
|
-
if [ -f ${KASEKI_RESULTS_DIR}/validation-baseline-timings.tsv ]; then
|
|
2749
|
-
cp ${KASEKI_RESULTS_DIR}/validation-baseline-timings.tsv "$cache_dir/validation-timings.tsv" || return 1
|
|
2751
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/validation-baseline-timings.tsv ]; then
|
|
2752
|
+
cp "${KASEKI_RESULTS_DIR}"/validation-baseline-timings.tsv "$cache_dir/validation-timings.tsv" || return 1
|
|
2750
2753
|
fi
|
|
2751
2754
|
|
|
2752
|
-
if [ -f ${KASEKI_RESULTS_DIR}/validation-baseline-env.log ]; then
|
|
2753
|
-
cp ${KASEKI_RESULTS_DIR}/validation-baseline-env.log "$cache_dir/validation-env.log" 2>/dev/null || true
|
|
2755
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/validation-baseline-env.log ]; then
|
|
2756
|
+
cp "${KASEKI_RESULTS_DIR}"/validation-baseline-env.log "$cache_dir/validation-env.log" 2>/dev/null || true
|
|
2754
2757
|
fi
|
|
2755
2758
|
|
|
2756
2759
|
return 0
|
|
@@ -2776,10 +2779,10 @@ checkout_baseline_repo() {
|
|
|
2776
2779
|
emit_progress "baseline preparation" "installing baseline dependencies"
|
|
2777
2780
|
if ! cd "$baseline_dir" && npm ci --prefer-offline 2>>"$KASEKI_LOG_DIR/baseline-npm-ci.log"; then
|
|
2778
2781
|
emit_error_event "baseline_deps_failed" "Failed to install baseline dependencies" "continue"
|
|
2779
|
-
cd ${KASEKI_WORKSPACE_DIR}/repo
|
|
2782
|
+
cd "${KASEKI_WORKSPACE_DIR}"/repo
|
|
2780
2783
|
return 1
|
|
2781
2784
|
fi
|
|
2782
|
-
cd ${KASEKI_WORKSPACE_DIR}/repo
|
|
2785
|
+
cd "${KASEKI_WORKSPACE_DIR}"/repo
|
|
2783
2786
|
fi
|
|
2784
2787
|
|
|
2785
2788
|
return 0
|
|
@@ -3025,13 +3028,13 @@ run_validation_commands() {
|
|
|
3025
3028
|
record_stage_timing "$stage_label" 0 0 "skipped_by_config"
|
|
3026
3029
|
else
|
|
3027
3030
|
# Checkpoint: Verify working directory exists before validation.
|
|
3028
|
-
if ! [ -d ${KASEKI_WORKSPACE_DIR}/repo ]; then
|
|
3029
|
-
printf 'ERROR: Working directory ${KASEKI_WORKSPACE_DIR}/repo does not exist before %s\n' "$stage_label" | tee -a "$log_file"
|
|
3031
|
+
if ! [ -d "${KASEKI_WORKSPACE_DIR}"/repo ]; then
|
|
3032
|
+
printf 'ERROR: Working directory "${KASEKI_WORKSPACE_DIR}"/repo does not exist before %s\n' "$stage_label" | tee -a "$log_file"
|
|
3030
3033
|
printf 'Current pwd: %s\n' "$(pwd 2>&1 || echo '<pwd failed>')" | tee -a "$log_file"
|
|
3031
3034
|
printf 'Filesystem state:\n' | tee -a "$log_file"
|
|
3032
3035
|
find /workspace -maxdepth 3 -type f 2>&1 | head -100 | tee -a "$log_file"
|
|
3033
3036
|
validation_exit_ref=1
|
|
3034
|
-
validation_detail_ref="Working directory ${KASEKI_WORKSPACE_DIR}/repo missing before $stage_label"
|
|
3037
|
+
validation_detail_ref="Working directory "${KASEKI_WORKSPACE_DIR}"/repo missing before $stage_label"
|
|
3035
3038
|
validation_reason_ref="$failure_reason_prefix: workspace_missing"
|
|
3036
3039
|
record_stage_timing "$stage_label" "$validation_exit_ref" "$(($(date +%s) - stage_start))" "directory_missing"
|
|
3037
3040
|
else
|
|
@@ -3057,7 +3060,7 @@ run_validation_commands() {
|
|
|
3057
3060
|
printf '[validation command] working_directory=%s\n' "$(pwd 2>&1 || echo '<pwd failed>')"
|
|
3058
3061
|
printf '[validation command] node_version=%s\n' "$(node --version 2>&1 || echo '<node not found>')"
|
|
3059
3062
|
printf '[validation command] npm_version=%s\n' "$(npm --version 2>&1 || echo '<npm not found>')"
|
|
3060
|
-
printf '[validation command] disk_available=%s\n' "$(df -h ${KASEKI_RESULTS_DIR} 2>/dev/null | tail -1 | awk '{print $4}' || echo '<df failed>')"
|
|
3063
|
+
printf '[validation command] disk_available=%s\n' "$(df -h "${KASEKI_RESULTS_DIR}" 2>/dev/null | tail -1 | awk '{print $4}' || echo '<df failed>')"
|
|
3061
3064
|
} | tee -a "$env_log"
|
|
3062
3065
|
# Use pipefail to catch errors in any stage of the pipe.
|
|
3063
3066
|
pipefail_was_enabled=0
|
|
@@ -3119,7 +3122,7 @@ run_validation_commands() {
|
|
|
3119
3122
|
{
|
|
3120
3123
|
printf '\n[DIAGNOSTICS] Validation pipeline stderr from filter/tee (last 50 lines):\n'
|
|
3121
3124
|
printf '%s\n' "$FILTER_STDERR_TAIL"
|
|
3122
|
-
} | tee -a "$log_file" ${KASEKI_RESULTS_DIR}/quality.log
|
|
3125
|
+
} | tee -a "$log_file" "${KASEKI_RESULTS_DIR}"/quality.log
|
|
3123
3126
|
{
|
|
3124
3127
|
printf '\n[validation pipeline stderr tail]\n'
|
|
3125
3128
|
printf '%s\n' "$FILTER_STDERR_TAIL"
|
|
@@ -3147,7 +3150,7 @@ run_validation_commands() {
|
|
|
3147
3150
|
else
|
|
3148
3151
|
printf ' (No stderr captured from filter/tee)\n'
|
|
3149
3152
|
fi
|
|
3150
|
-
} | tee -a "$log_file" ${KASEKI_RESULTS_DIR}/quality.log "$FILTER_DIAGNOSTICS_LOG"
|
|
3153
|
+
} | tee -a "$log_file" "${KASEKI_RESULTS_DIR}"/quality.log "$FILTER_DIAGNOSTICS_LOG"
|
|
3151
3154
|
fi
|
|
3152
3155
|
|
|
3153
3156
|
if [ "$validation_infra_failure" = "true" ] && [ "$validation_exit_ref" -eq 0 ]; then
|
|
@@ -3171,13 +3174,13 @@ run_validation_commands() {
|
|
|
3171
3174
|
printf '\n[DIAGNOSTICS] Validation command failed with directory access error:\n'
|
|
3172
3175
|
printf 'Working directory status:\n'
|
|
3173
3176
|
printf ' Current pwd: %s\n' "$(pwd 2>&1 || echo '<pwd failed>')"
|
|
3174
|
-
printf ' ${KASEKI_WORKSPACE_DIR}/repo exists: %s\n' "$([ -d ${KASEKI_WORKSPACE_DIR}/repo ] && echo 'yes' || echo 'no')"
|
|
3175
|
-
if [ -L ${KASEKI_WORKSPACE_DIR}/repo/node_modules ]; then
|
|
3176
|
-
printf ' node_modules is symlink → %s\n' "$(readlink ${KASEKI_WORKSPACE_DIR}/repo/node_modules 2>&1 || echo '<readlink failed>')"
|
|
3177
|
+
printf ' "${KASEKI_WORKSPACE_DIR}"/repo exists: %s\n' "$([ -d ${KASEKI_WORKSPACE_DIR}/repo ] && echo 'yes' || echo 'no')"
|
|
3178
|
+
if [ -L "${KASEKI_WORKSPACE_DIR}"/repo/node_modules ]; then
|
|
3179
|
+
printf ' node_modules is symlink → %s\n' "$(readlink "${KASEKI_WORKSPACE_DIR}"/repo/node_modules 2>&1 || echo '<readlink failed>')"
|
|
3177
3180
|
fi
|
|
3178
3181
|
printf 'Last 20 lines of validation log:\n'
|
|
3179
3182
|
tail -20 "$log_file"
|
|
3180
|
-
} | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
3183
|
+
} | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
3181
3184
|
fi
|
|
3182
3185
|
# Fail-fast: if enabled, stop validation loop at first failure.
|
|
3183
3186
|
if [ "$KASEKI_VALIDATION_FAIL_FAST" -eq 1 ]; then
|
|
@@ -3258,7 +3261,7 @@ write_repo_memory_summary() {
|
|
|
3258
3261
|
return 0
|
|
3259
3262
|
fi
|
|
3260
3263
|
local updated_at
|
|
3261
|
-
REPO_MEMORY_COMMIT_SHA="$(git -C ${KASEKI_WORKSPACE_DIR}/repo rev-parse HEAD 2>/dev/null || printf 'unknown')"
|
|
3264
|
+
REPO_MEMORY_COMMIT_SHA="$(git -C "${KASEKI_WORKSPACE_DIR}"/repo rev-parse HEAD 2>/dev/null || printf 'unknown')"
|
|
3262
3265
|
updated_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
3263
3266
|
node - "$KASEKI_REPO_MEMORY_MAX_BYTES" "$REPO_MEMORY_FILE" "$KASEKI_RESULTS_DIR" "$REPO_URL" "$GIT_REF" "$REPO_MEMORY_COMMIT_SHA" "$updated_at" "$KASEKI_TASK_MODE" "$STATUS" "$PI_EXIT" "$VALIDATION_EXIT" "$QUALITY_EXIT" "$SECRET_SCAN_EXIT" <<'NODE' || {
|
|
3264
3267
|
const fs = require('fs');
|
|
@@ -3438,9 +3441,9 @@ is_transient_goal_setting_failure() {
|
|
|
3438
3441
|
local stderr_content="$2"
|
|
3439
3442
|
|
|
3440
3443
|
# First, check if we have an explicit validation reason code from our helper
|
|
3441
|
-
if [ -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt ]; then
|
|
3444
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/goal-setting-validation-reason.txt ]; then
|
|
3442
3445
|
local reason_code
|
|
3443
|
-
reason_code=$(cat ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || echo "")
|
|
3446
|
+
reason_code=$(cat "${KASEKI_RESULTS_DIR}"/goal-setting-validation-reason.txt 2>/dev/null || echo "")
|
|
3444
3447
|
case "$reason_code" in
|
|
3445
3448
|
valid)
|
|
3446
3449
|
return 1
|
|
@@ -3619,7 +3622,7 @@ validate_goal_setting_artifact() {
|
|
|
3619
3622
|
local candidate_artifact="$1"
|
|
3620
3623
|
local final_artifact="$2"
|
|
3621
3624
|
local reason_file="$3"
|
|
3622
|
-
local results_dir="$
|
|
3625
|
+
local results_dir="$KASEKI_RESULTS_DIR"
|
|
3623
3626
|
|
|
3624
3627
|
if ! [ -f "$candidate_artifact" ]; then
|
|
3625
3628
|
{
|
|
@@ -3659,7 +3662,7 @@ validate_goal_setting_artifact() {
|
|
|
3659
3662
|
validate_goal_setting_artifact_with_node() {
|
|
3660
3663
|
local candidate_artifact="$1"
|
|
3661
3664
|
local reason_file="$2"
|
|
3662
|
-
local results_dir="$
|
|
3665
|
+
local results_dir="$KASEKI_RESULTS_DIR"
|
|
3663
3666
|
|
|
3664
3667
|
local validation_output
|
|
3665
3668
|
validation_output=$(node -e "
|
|
@@ -3844,13 +3847,13 @@ run_goal_setting_agent() {
|
|
|
3844
3847
|
set_current_stage "pi goal-setting agent"
|
|
3845
3848
|
|
|
3846
3849
|
if [ "$KASEKI_GOAL_SETTING" = "0" ]; then
|
|
3847
|
-
printf 'Pi goal-setting agent skipped because KASEKI_GOAL_SETTING=0.\n' | tee -a ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log
|
|
3850
|
+
printf 'Pi goal-setting agent skipped because KASEKI_GOAL_SETTING=0.\n' | tee -a "${KASEKI_RESULTS_DIR}"/goal-setting-stderr.log
|
|
3848
3851
|
record_stage_timing "pi goal-setting agent" 0 0 "skipped_by_config"
|
|
3849
3852
|
return 0
|
|
3850
3853
|
fi
|
|
3851
3854
|
|
|
3852
3855
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
3853
|
-
printf 'DRY-RUN: Pi goal-setting agent would upgrade the task prompt into a mature goal.\n' | tee -a ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log
|
|
3856
|
+
printf 'DRY-RUN: Pi goal-setting agent would upgrade the task prompt into a mature goal.\n' | tee -a "${KASEKI_RESULTS_DIR}"/goal-setting-stderr.log
|
|
3854
3857
|
record_stage_timing "pi goal-setting agent" 0 0 "dry_run=true"
|
|
3855
3858
|
return 0
|
|
3856
3859
|
fi
|
|
@@ -3862,9 +3865,9 @@ run_goal_setting_agent() {
|
|
|
3862
3865
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
3863
3866
|
timeout --signal=SIGTERM "$KASEKI_GOAL_SETTING_TIMEOUT_SECONDS" \
|
|
3864
3867
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_GOAL_SETTING_MODEL" "$goal_setting_prompt" \
|
|
3865
|
-
2> >(tee -a ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log >&2) \
|
|
3868
|
+
2> >(tee -a "${KASEKI_RESULTS_DIR}"/goal-setting-stderr.log >&2) \
|
|
3866
3869
|
| tee "$GOAL_SETTING_RAW_EVENTS" \
|
|
3867
|
-
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
3870
|
+
| kaseki-pi-progress-stream "${KASEKI_RESULTS_DIR}"/progress.jsonl "${KASEKI_RESULTS_DIR}"/progress.log
|
|
3868
3871
|
GOAL_SETTING_EXIT="${PIPESTATUS[0]}"
|
|
3869
3872
|
GOAL_SETTING_DURATION_SECONDS=$(($(date +%s) - goal_setting_start))
|
|
3870
3873
|
unset goal_setting_prompt
|
|
@@ -3872,12 +3875,12 @@ run_goal_setting_agent() {
|
|
|
3872
3875
|
|
|
3873
3876
|
if [ "$GOAL_SETTING_EXIT" -eq 0 ] && ! validate_goal_setting_artifact "$GOAL_SETTING_CANDIDATE_ARTIFACT" "$GOAL_SETTING_ARTIFACT" "${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt"; then
|
|
3874
3877
|
GOAL_SETTING_EXIT=86
|
|
3875
|
-
goal_setting_validation_summary="$(cat ${KASEKI_RESULTS_DIR}/goal-setting-validation-summary.txt 2>/dev/null || printf 'goal-setting artifact validation failed')"
|
|
3876
|
-
emit_error_event "pi_goal_setting_artifact_invalid" "Pi goal-setting artifact invalid: $goal_setting_validation_summary (full details: ${KASEKI_RESULTS_DIR}/goal-setting-validation-errors.jsonl)" "continue"
|
|
3878
|
+
goal_setting_validation_summary="$(cat "${KASEKI_RESULTS_DIR}"/goal-setting-validation-summary.txt 2>/dev/null || printf 'goal-setting artifact validation failed')"
|
|
3879
|
+
emit_error_event "pi_goal_setting_artifact_invalid" "Pi goal-setting artifact invalid: $goal_setting_validation_summary (full details: "${KASEKI_RESULTS_DIR}"/goal-setting-validation-errors.jsonl)" "continue"
|
|
3877
3880
|
fi
|
|
3878
3881
|
|
|
3879
3882
|
rm -f "$GOAL_SETTING_CANDIDATE_ARTIFACT"
|
|
3880
|
-
kaseki-pi-event-filter "$GOAL_SETTING_RAW_EVENTS" ${KASEKI_RESULTS_DIR}/goal-setting-events.jsonl ${KASEKI_RESULTS_DIR}/goal-setting-summary.json 2>> ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log || cp "$GOAL_SETTING_RAW_EVENTS" ${KASEKI_RESULTS_DIR}/goal-setting-events.raw.jsonl 2>/dev/null || true
|
|
3883
|
+
kaseki-pi-event-filter "$GOAL_SETTING_RAW_EVENTS" "${KASEKI_RESULTS_DIR}"/goal-setting-events.jsonl ${KASEKI_RESULTS_DIR}/goal-setting-summary.json 2>> "${KASEKI_RESULTS_DIR}"/goal-setting-stderr.log || cp "$GOAL_SETTING_RAW_EVENTS" ${KASEKI_RESULTS_DIR}/goal-setting-events.raw.jsonl 2>/dev/null || true
|
|
3881
3884
|
GOAL_SETTING_ACTUAL_MODEL="$(node -e 'try { const s=require(process.env.KASEKI_RESULTS_DIR + "/goal-setting-summary.json"); const v=String(s.selected_model || s.model || "").trim(); console.log(v && v !== "unknown" && v !== "null" ? v : "unknown"); } catch { console.log("unknown"); }' 2>/dev/null)"
|
|
3882
3885
|
|
|
3883
3886
|
record_stage_timing "pi goal-setting agent" "$GOAL_SETTING_EXIT" "$GOAL_SETTING_DURATION_SECONDS" "artifact=$GOAL_SETTING_ARTIFACT timeout_seconds=$KASEKI_GOAL_SETTING_TIMEOUT_SECONDS"
|
|
@@ -3888,7 +3891,7 @@ run_goal_setting_agent() {
|
|
|
3888
3891
|
fi
|
|
3889
3892
|
|
|
3890
3893
|
emit_progress "pi goal-setting agent" "wrote goal-setting artifact"
|
|
3891
|
-
rm -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || true
|
|
3894
|
+
rm -f "${KASEKI_RESULTS_DIR}"/goal-setting-validation-reason.txt 2>/dev/null || true
|
|
3892
3895
|
|
|
3893
3896
|
return 0
|
|
3894
3897
|
}
|
|
@@ -3939,7 +3942,7 @@ write_goal_setting_metrics() {
|
|
|
3939
3942
|
printf ' "model": "%s",\n' "${GOAL_SETTING_ACTUAL_MODEL:-unknown}"
|
|
3940
3943
|
printf ' "timeout_seconds": %d\n' "${KASEKI_GOAL_SETTING_TIMEOUT_SECONDS:-300}"
|
|
3941
3944
|
printf '}\n'
|
|
3942
|
-
} > ${KASEKI_RESULTS_DIR}/goal-setting-metrics.json
|
|
3945
|
+
} > "${KASEKI_RESULTS_DIR}"/goal-setting-metrics.json
|
|
3943
3946
|
}
|
|
3944
3947
|
}
|
|
3945
3948
|
|
|
@@ -3948,9 +3951,9 @@ classify_goal_setting_error() {
|
|
|
3948
3951
|
local stderr_content="$2"
|
|
3949
3952
|
|
|
3950
3953
|
# Check validation reason file first (most authoritative)
|
|
3951
|
-
if [ -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt ]; then
|
|
3954
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/goal-setting-validation-reason.txt ]; then
|
|
3952
3955
|
local reason_code
|
|
3953
|
-
reason_code=$(cat ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || echo "")
|
|
3956
|
+
reason_code=$(cat "${KASEKI_RESULTS_DIR}"/goal-setting-validation-reason.txt 2>/dev/null || echo "")
|
|
3954
3957
|
case "$reason_code" in
|
|
3955
3958
|
schema_mismatch)
|
|
3956
3959
|
echo "GOAL_SETTING_SCHEMA_MISMATCH"
|
|
@@ -4029,7 +4032,7 @@ run_goal_setting_agent_with_retry() {
|
|
|
4029
4032
|
set -e
|
|
4030
4033
|
|
|
4031
4034
|
# Append stderr to results for logging
|
|
4032
|
-
cat "$goal_setting_stderr_capture" >> ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log 2>/dev/null || true
|
|
4035
|
+
cat "$goal_setting_stderr_capture" >> "${KASEKI_RESULTS_DIR}"/goal-setting-stderr.log 2>/dev/null || true
|
|
4033
4036
|
goal_setting_last_stderr="$(cat "$goal_setting_stderr_capture" 2>/dev/null || true)"
|
|
4034
4037
|
rm -f "$goal_setting_stderr_capture"
|
|
4035
4038
|
|
|
@@ -4061,7 +4064,7 @@ run_goal_setting_agent_with_retry() {
|
|
|
4061
4064
|
attempt=$((attempt + 1))
|
|
4062
4065
|
# Reset goal-setting artifacts for retry
|
|
4063
4066
|
rm -f "$GOAL_SETTING_ARTIFACT" "$GOAL_SETTING_RAW_EVENTS" 2>/dev/null || true
|
|
4064
|
-
rm -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || true
|
|
4067
|
+
rm -f "${KASEKI_RESULTS_DIR}"/goal-setting-validation-reason.txt 2>/dev/null || true
|
|
4065
4068
|
continue
|
|
4066
4069
|
fi
|
|
4067
4070
|
else
|
|
@@ -4095,9 +4098,9 @@ is_transient_scouting_failure() {
|
|
|
4095
4098
|
local stderr_content="$2"
|
|
4096
4099
|
|
|
4097
4100
|
# First, check if we have an explicit validation reason code from our helper
|
|
4098
|
-
if [ -f ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt ]; then
|
|
4101
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/scouting-validation-reason.txt ]; then
|
|
4099
4102
|
local reason_code
|
|
4100
|
-
reason_code=$(cat ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt 2>/dev/null || echo "")
|
|
4103
|
+
reason_code=$(cat "${KASEKI_RESULTS_DIR}"/scouting-validation-reason.txt 2>/dev/null || echo "")
|
|
4101
4104
|
case "$reason_code" in
|
|
4102
4105
|
valid)
|
|
4103
4106
|
# This shouldn't happen when exit_code=86, but just in case
|
|
@@ -4232,47 +4235,47 @@ run_scouting_agent() {
|
|
|
4232
4235
|
printf '\n==> pi scouting agent\n'
|
|
4233
4236
|
set_current_stage "pi scouting agent"
|
|
4234
4237
|
if [ "$KASEKI_SCOUTING" = "0" ]; then
|
|
4235
|
-
printf 'Pi scouting agent skipped because KASEKI_SCOUTING=0.\n' | tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
4238
|
+
printf 'Pi scouting agent skipped because KASEKI_SCOUTING=0.\n' | tee -a "${KASEKI_RESULTS_DIR}"/scouting-stderr.log
|
|
4236
4239
|
record_stage_timing "pi scouting agent" 0 0 "skipped_by_config"
|
|
4237
4240
|
return 0
|
|
4238
4241
|
fi
|
|
4239
4242
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
4240
|
-
printf 'DRY-RUN: Pi scouting agent would inspect the task before coding.\n' | tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
4243
|
+
printf 'DRY-RUN: Pi scouting agent would inspect the task before coding.\n' | tee -a "${KASEKI_RESULTS_DIR}"/scouting-stderr.log
|
|
4241
4244
|
record_stage_timing "pi scouting agent" 0 0 "dry_run=true"
|
|
4242
4245
|
return 0
|
|
4243
4246
|
fi
|
|
4244
4247
|
|
|
4245
4248
|
scouting_prompt="$(build_scouting_prompt)"
|
|
4246
4249
|
scouting_start="$(date +%s)"
|
|
4247
|
-
scout_dirty_before="$(git status --porcelain 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true)"
|
|
4248
|
-
chmod -R a-w ${KASEKI_WORKSPACE_DIR}/repo 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true
|
|
4250
|
+
scout_dirty_before="$(git status --porcelain 2>> "${KASEKI_RESULTS_DIR}"/scouting-stderr.log || true)"
|
|
4251
|
+
chmod -R a-w "${KASEKI_WORKSPACE_DIR}"/repo 2>> "${KASEKI_RESULTS_DIR}"/scouting-stderr.log || true
|
|
4249
4252
|
set +e
|
|
4250
4253
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
4251
4254
|
timeout --signal=SIGTERM "$KASEKI_SCOUTING_TIMEOUT_SECONDS" \
|
|
4252
4255
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_SCOUTING_MODEL" "$scouting_prompt" \
|
|
4253
|
-
2> >(tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log >&2) \
|
|
4256
|
+
2> >(tee -a "${KASEKI_RESULTS_DIR}"/scouting-stderr.log >&2) \
|
|
4254
4257
|
| tee "$SCOUTING_RAW_EVENTS" \
|
|
4255
|
-
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
4258
|
+
| kaseki-pi-progress-stream "${KASEKI_RESULTS_DIR}"/progress.jsonl "${KASEKI_RESULTS_DIR}"/progress.log
|
|
4256
4259
|
SCOUTING_EXIT="${PIPESTATUS[0]}"
|
|
4257
4260
|
SCOUTING_DURATION_SECONDS=$(($(date +%s) - scouting_start))
|
|
4258
4261
|
unset scouting_prompt
|
|
4259
4262
|
set +e
|
|
4260
|
-
chmod -R u+w ${KASEKI_WORKSPACE_DIR}/repo 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true
|
|
4263
|
+
chmod -R u+w "${KASEKI_WORKSPACE_DIR}"/repo 2>> "${KASEKI_RESULTS_DIR}"/scouting-stderr.log || true
|
|
4261
4264
|
|
|
4262
4265
|
if [ "$SCOUTING_EXIT" -eq 0 ] && ! validate_scouting_artifact "$SCOUTING_CANDIDATE_ARTIFACT" "$SCOUTING_ARTIFACT" "${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt"; then
|
|
4263
4266
|
SCOUTING_EXIT=86
|
|
4264
|
-
scouting_validation_summary="$(cat ${KASEKI_RESULTS_DIR}/scouting-validation-summary.txt 2>/dev/null || printf 'scouting artifact validation failed')"
|
|
4265
|
-
emit_error_event "pi_scouting_artifact_invalid" "Pi scouting handoff invalid: $scouting_validation_summary (full details: ${KASEKI_RESULTS_DIR}/scouting-validation-errors.jsonl)" "exit"
|
|
4267
|
+
scouting_validation_summary="$(cat "${KASEKI_RESULTS_DIR}"/scouting-validation-summary.txt 2>/dev/null || printf 'scouting artifact validation failed')"
|
|
4268
|
+
emit_error_event "pi_scouting_artifact_invalid" "Pi scouting handoff invalid: $scouting_validation_summary (full details: "${KASEKI_RESULTS_DIR}"/scouting-validation-errors.jsonl)" "exit"
|
|
4266
4269
|
fi
|
|
4267
|
-
scout_dirty_after="$(git status --porcelain 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true)"
|
|
4270
|
+
scout_dirty_after="$(git status --porcelain 2>> "${KASEKI_RESULTS_DIR}"/scouting-stderr.log || true)"
|
|
4268
4271
|
if [ "$SCOUTING_EXIT" -eq 0 ] && [ "$scout_dirty_before" != "$scout_dirty_after" ]; then
|
|
4269
4272
|
SCOUTING_EXIT=86
|
|
4270
4273
|
emit_error_event "pi_scouting_workspace_modified" "Read-only scouting changed repository state before coding" "exit"
|
|
4271
4274
|
fi
|
|
4272
4275
|
rm -f "$SCOUTING_CANDIDATE_ARTIFACT"
|
|
4273
|
-
git reset --hard -q HEAD 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true
|
|
4274
|
-
git clean -fd -q 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true
|
|
4275
|
-
kaseki-pi-event-filter "$SCOUTING_RAW_EVENTS" ${KASEKI_RESULTS_DIR}/scouting-events.jsonl ${KASEKI_RESULTS_DIR}/scouting-summary.json 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || cp "$SCOUTING_RAW_EVENTS" ${KASEKI_RESULTS_DIR}/scouting-events.raw.jsonl 2>/dev/null || true
|
|
4276
|
+
git reset --hard -q HEAD 2>> "${KASEKI_RESULTS_DIR}"/scouting-stderr.log || true
|
|
4277
|
+
git clean -fd -q 2>> "${KASEKI_RESULTS_DIR}"/scouting-stderr.log || true
|
|
4278
|
+
kaseki-pi-event-filter "$SCOUTING_RAW_EVENTS" "${KASEKI_RESULTS_DIR}"/scouting-events.jsonl ${KASEKI_RESULTS_DIR}/scouting-summary.json 2>> "${KASEKI_RESULTS_DIR}"/scouting-stderr.log || cp "$SCOUTING_RAW_EVENTS" ${KASEKI_RESULTS_DIR}/scouting-events.raw.jsonl 2>/dev/null || true
|
|
4276
4279
|
SCOUTING_ACTUAL_MODEL="$(node -e 'try { const s=require(process.env.KASEKI_RESULTS_DIR + "/scouting-summary.json"); const v=String(s.selected_model || s.model || "").trim(); console.log(v && v !== "unknown" && v !== "null" ? v : "unknown"); } catch { console.log("unknown"); }' 2>/dev/null)"
|
|
4277
4280
|
record_stage_timing "pi scouting agent" "$SCOUTING_EXIT" "$SCOUTING_DURATION_SECONDS" "artifact=$SCOUTING_ARTIFACT timeout_seconds=$KASEKI_SCOUTING_TIMEOUT_SECONDS"
|
|
4278
4281
|
if [ "$SCOUTING_EXIT" -ne 0 ]; then
|
|
@@ -4283,7 +4286,7 @@ run_scouting_agent() {
|
|
|
4283
4286
|
fi
|
|
4284
4287
|
emit_progress "pi scouting agent" "wrote scouting artifact"
|
|
4285
4288
|
# Clean up validation reason file on success
|
|
4286
|
-
rm -f ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt 2>/dev/null || true
|
|
4289
|
+
rm -f "${KASEKI_RESULTS_DIR}"/scouting-validation-reason.txt 2>/dev/null || true
|
|
4287
4290
|
return 0
|
|
4288
4291
|
}
|
|
4289
4292
|
|
|
@@ -4311,7 +4314,7 @@ run_scouting_agent_with_retry() {
|
|
|
4311
4314
|
set -e
|
|
4312
4315
|
|
|
4313
4316
|
# Append stderr to results for logging
|
|
4314
|
-
cat "$scouting_stderr_capture" >> ${KASEKI_RESULTS_DIR}/scouting-stderr.log 2>/dev/null || true
|
|
4317
|
+
cat "$scouting_stderr_capture" >> "${KASEKI_RESULTS_DIR}"/scouting-stderr.log 2>/dev/null || true
|
|
4315
4318
|
scouting_last_stderr="$(cat "$scouting_stderr_capture" 2>/dev/null || true)"
|
|
4316
4319
|
rm -f "$scouting_stderr_capture"
|
|
4317
4320
|
|
|
@@ -4330,7 +4333,7 @@ run_scouting_agent_with_retry() {
|
|
|
4330
4333
|
# Reset scouting artifacts for retry
|
|
4331
4334
|
rm -f "$SCOUTING_ARTIFACT" "$SCOUTING_RAW_EVENTS" 2>/dev/null || true
|
|
4332
4335
|
# Clean up validation reason file from previous attempt
|
|
4333
|
-
rm -f ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt 2>/dev/null || true
|
|
4336
|
+
rm -f "${KASEKI_RESULTS_DIR}"/scouting-validation-reason.txt 2>/dev/null || true
|
|
4334
4337
|
continue
|
|
4335
4338
|
fi
|
|
4336
4339
|
else
|
|
@@ -4368,7 +4371,7 @@ snapshot_attempt_artifacts() {
|
|
|
4368
4371
|
collect_goal_check_feedback() {
|
|
4369
4372
|
local instance_name="$1"
|
|
4370
4373
|
local goal_setting_path="$GOAL_SETTING_ARTIFACT"
|
|
4371
|
-
local results_dir="$
|
|
4374
|
+
local results_dir="$KASEKI_RESULTS_DIR"
|
|
4372
4375
|
local goal_check_path="$results_dir/goal-check.json"
|
|
4373
4376
|
local metadata_path="$results_dir/metadata.json"
|
|
4374
4377
|
local feedback_file="$results_dir/goal-feedback.jsonl"
|
|
@@ -4379,7 +4382,7 @@ collect_goal_check_feedback() {
|
|
|
4379
4382
|
fi
|
|
4380
4383
|
|
|
4381
4384
|
# Use node script to collect feedback, append as JSONL
|
|
4382
|
-
node "$SCRIPT_DIR/collect-feedback.js" goal-check "$instance_name" "$goal_setting_path" "$goal_check_path" "$metadata_path" 2>/dev/null | tee -a "$feedback_file" >/dev/null || true
|
|
4385
|
+
node "$SCRIPT_DIR/scripts/collect-feedback.js" goal-check "$instance_name" "$goal_setting_path" "$goal_check_path" "$metadata_path" 2>/dev/null | tee -a "$feedback_file" >/dev/null || true
|
|
4383
4386
|
}
|
|
4384
4387
|
|
|
4385
4388
|
collect_run_evaluation_feedback() {
|
|
@@ -4394,20 +4397,20 @@ collect_run_evaluation_feedback() {
|
|
|
4394
4397
|
fi
|
|
4395
4398
|
|
|
4396
4399
|
# Use node script to collect feedback, append as JSONL
|
|
4397
|
-
node "$SCRIPT_DIR/collect-feedback.js" run-evaluation "$instance_name" "$run_evaluation_path" "$metadata_path" 2>/dev/null | tee -a "$feedback_file" >/dev/null || true
|
|
4400
|
+
node "$SCRIPT_DIR/scripts/collect-feedback.js" run-evaluation "$instance_name" "$run_evaluation_path" "$metadata_path" 2>/dev/null | tee -a "$feedback_file" >/dev/null || true
|
|
4398
4401
|
}
|
|
4399
4402
|
|
|
4400
4403
|
|
|
4401
4404
|
build_goal_check_prompt() {
|
|
4402
4405
|
local validation_tail progress_tail goal_setting_context validation_context test_impact_context causality_context
|
|
4403
|
-
validation_tail="$(tail -80 ${KASEKI_RESULTS_DIR}/validation.log 2>/dev/null || true)"
|
|
4406
|
+
validation_tail="$(tail -80 "${KASEKI_RESULTS_DIR}"/validation.log 2>/dev/null || true)"
|
|
4404
4407
|
if [ -n "$(printf '%s' "$validation_tail" | tr -d '[:space:]')" ]; then
|
|
4405
4408
|
validation_context="Validation log tail (last 80 lines):
|
|
4406
4409
|
$validation_tail"
|
|
4407
4410
|
else
|
|
4408
|
-
validation_context="Validation log: ${KASEKI_RESULTS_DIR}/validation.log is empty or has not been produced yet. Treat validation logs as optional evidence for this pre-validation check; rely on the goal-setting output, scouting output, changed files, and git diff to determine whether the goal requirements are satisfied."
|
|
4411
|
+
validation_context="Validation log: "${KASEKI_RESULTS_DIR}"/validation.log is empty or has not been produced yet. Treat validation logs as optional evidence for this pre-validation check; rely on the goal-setting output, scouting output, changed files, and git diff to determine whether the goal requirements are satisfied."
|
|
4409
4412
|
fi
|
|
4410
|
-
progress_tail="$(tail -80 ${KASEKI_RESULTS_DIR}/progress.log 2>/dev/null || true)"
|
|
4413
|
+
progress_tail="$(tail -80 "${KASEKI_RESULTS_DIR}"/progress.log 2>/dev/null || true)"
|
|
4411
4414
|
if [ -s "$TEST_IMPACT_WARNINGS_ARTIFACT" ]; then
|
|
4412
4415
|
test_impact_context="Static test-impact warnings artifact ($TEST_IMPACT_WARNINGS_ARTIFACT):
|
|
4413
4416
|
$(cat "$TEST_IMPACT_WARNINGS_ARTIFACT" 2>/dev/null)
|
|
@@ -4433,7 +4436,7 @@ $(head -n 200 "$GOAL_SETTING_ARTIFACT" 2>/dev/null)
|
|
|
4433
4436
|
fi
|
|
4434
4437
|
|
|
4435
4438
|
# Include causality assessment if available (helps interpret validation failures)
|
|
4436
|
-
if [ -f ${KASEKI_RESULTS_DIR}/validation-causality-analysis.json ]; then
|
|
4439
|
+
if [ -f "${KASEKI_RESULTS_DIR}"/validation-causality-analysis.json ]; then
|
|
4437
4440
|
# shellcheck disable=SC2016
|
|
4438
4441
|
causality_context="VALIDATION FAILURE CAUSALITY ASSESSMENT:
|
|
4439
4442
|
|
|
@@ -4493,11 +4496,11 @@ Determine if the agent successfully met the requirements specified in the goal-s
|
|
|
4493
4496
|
|
|
4494
4497
|
**Agent Artifacts** (use to verify requirements were met):
|
|
4495
4498
|
- Scouting report: $SCOUTING_ARTIFACT
|
|
4496
|
-
- Changed files: ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
4497
|
-
- Git diff: ${KASEKI_RESULTS_DIR}/git.diff
|
|
4498
|
-
- Validation outcomes (optional evidence; may be absent during pre-validation checks): ${KASEKI_RESULTS_DIR}/validation-timings.tsv and ${KASEKI_RESULTS_DIR}/validation.log
|
|
4499
|
+
- Changed files: "${KASEKI_RESULTS_DIR}"/changed-files.txt
|
|
4500
|
+
- Git diff: "${KASEKI_RESULTS_DIR}"/git.diff
|
|
4501
|
+
- Validation outcomes (optional evidence; may be absent during pre-validation checks): "${KASEKI_RESULTS_DIR}"/validation-timings.tsv and ${KASEKI_RESULTS_DIR}/validation.log
|
|
4499
4502
|
- Static test-impact warnings (non-blocking): $TEST_IMPACT_WARNINGS_ARTIFACT
|
|
4500
|
-
- Coding-agent events: ${KASEKI_RESULTS_DIR}/pi-summary.json and ${KASEKI_RESULTS_DIR}/pi-events.jsonl
|
|
4503
|
+
- Coding-agent events: "${KASEKI_RESULTS_DIR}"/pi-summary.json and ${KASEKI_RESULTS_DIR}/pi-events.jsonl
|
|
4501
4504
|
|
|
4502
4505
|
## Evaluation Framework: SMART Criteria Check
|
|
4503
4506
|
|
|
@@ -4556,7 +4559,7 @@ Example: "Null handling is done (parseRole returns 'Unnamed Role'), but test cov
|
|
|
4556
4559
|
- Do not print, inspect, or expose environment variables, secrets, credentials, API keys, or mounted secret files.
|
|
4557
4560
|
- Decide whether the goal requirements were realized. Do not evaluate code style, architecture, or elegance.
|
|
4558
4561
|
- If anti-patterns were specified in goal-setting (do_not_modify, do_not_break), verify they were respected.
|
|
4559
|
-
- Validation logs are optional evidence. If ${KASEKI_RESULTS_DIR}/validation.log is empty or absent, do not fail solely because validation evidence is unavailable; rely on goal-setting output, scouting output, changed files, and git diff.
|
|
4562
|
+
- Validation logs are optional evidence. If "${KASEKI_RESULTS_DIR}"/validation.log is empty or absent, do not fail solely because validation evidence is unavailable; rely on goal-setting output, scouting output, changed files, and git diff.
|
|
4560
4563
|
|
|
4561
4564
|
## Required JSON artifact
|
|
4562
4565
|
|
|
@@ -4607,12 +4610,12 @@ run_goal_check() {
|
|
|
4607
4610
|
printf '\n==> goal check\n'
|
|
4608
4611
|
set_current_stage "goal check"
|
|
4609
4612
|
if [ "$KASEKI_GOAL_CHECK" != "1" ]; then
|
|
4610
|
-
printf 'Goal check skipped because KASEKI_GOAL_CHECK=%s.\n' "$KASEKI_GOAL_CHECK" | tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log
|
|
4613
|
+
printf 'Goal check skipped because KASEKI_GOAL_CHECK=%s.\n' "$KASEKI_GOAL_CHECK" | tee -a "${KASEKI_RESULTS_DIR}"/goal-check-stderr.log
|
|
4611
4614
|
record_stage_timing "goal check" 0 0 "skipped_by_config attempt=$attempt"
|
|
4612
4615
|
return 0
|
|
4613
4616
|
fi
|
|
4614
4617
|
if [ ! -s "$SCOUTING_ARTIFACT" ]; then
|
|
4615
|
-
printf 'Goal check skipped because scouting artifact is unavailable.\n' | tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log
|
|
4618
|
+
printf 'Goal check skipped because scouting artifact is unavailable.\n' | tee -a "${KASEKI_RESULTS_DIR}"/goal-check-stderr.log
|
|
4616
4619
|
record_stage_timing "goal check" 0 0 "skipped_no_scouting attempt=$attempt"
|
|
4617
4620
|
return 0
|
|
4618
4621
|
fi
|
|
@@ -4623,15 +4626,15 @@ run_goal_check() {
|
|
|
4623
4626
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
4624
4627
|
timeout --signal=SIGTERM "$KASEKI_GOAL_CHECK_TIMEOUT_SECONDS" \
|
|
4625
4628
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_GOAL_CHECK_MODEL" "$goal_prompt" \
|
|
4626
|
-
2> >(tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log >&2) \
|
|
4629
|
+
2> >(tee -a "${KASEKI_RESULTS_DIR}"/goal-check-stderr.log >&2) \
|
|
4627
4630
|
| tee "$GOAL_CHECK_RAW_EVENTS" \
|
|
4628
|
-
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
4631
|
+
| kaseki-pi-progress-stream "${KASEKI_RESULTS_DIR}"/progress.jsonl "${KASEKI_RESULTS_DIR}"/progress.log
|
|
4629
4632
|
GOAL_CHECK_EXIT="${PIPESTATUS[0]}"
|
|
4630
4633
|
unset goal_prompt
|
|
4631
4634
|
GOAL_CHECK_DURATION_SECONDS=$((GOAL_CHECK_DURATION_SECONDS + $(date +%s) - goal_start))
|
|
4632
4635
|
set +e
|
|
4633
4636
|
|
|
4634
|
-
kaseki-pi-event-filter "$GOAL_CHECK_RAW_EVENTS" ${KASEKI_RESULTS_DIR}/goal-check-events.jsonl ${KASEKI_RESULTS_DIR}/goal-check-summary.json 2>> ${KASEKI_RESULTS_DIR}/goal-check-stderr.log || true
|
|
4637
|
+
kaseki-pi-event-filter "$GOAL_CHECK_RAW_EVENTS" "${KASEKI_RESULTS_DIR}"/goal-check-events.jsonl ${KASEKI_RESULTS_DIR}/goal-check-summary.json 2>> "${KASEKI_RESULTS_DIR}"/goal-check-stderr.log || true
|
|
4635
4638
|
|
|
4636
4639
|
if [ "$GOAL_CHECK_EXIT" -eq 0 ] && [ ! -f "$GOAL_CHECK_CANDIDATE_ARTIFACT" ]; then
|
|
4637
4640
|
# Recover from goal-check agents that printed the verdict in assistant text instead of writing the artifact.
|
|
@@ -4731,25 +4734,25 @@ if (valid.size === 1) {
|
|
|
4731
4734
|
const note = { timestamp: new Date().toISOString(), attempt, event: "goal_check_artifact_recovered_from_assistant_text", artifact: candidatePath, raw_events: rawPath, filtered_events: filteredPath };
|
|
4732
4735
|
fs.appendFileSync(process.env.KASEKI_RESULTS_DIR + "/goal-check-stderr.log", JSON.stringify(note) + "\n");
|
|
4733
4736
|
}
|
|
4734
|
-
' "$GOAL_CHECK_CANDIDATE_ARTIFACT" "$GOAL_CHECK_RAW_EVENTS" ${KASEKI_RESULTS_DIR}/goal-check-events.jsonl "$attempt" 2>> ${KASEKI_RESULTS_DIR}/goal-check-stderr.log || true
|
|
4737
|
+
' "$GOAL_CHECK_CANDIDATE_ARTIFACT" "$GOAL_CHECK_RAW_EVENTS" "${KASEKI_RESULTS_DIR}"/goal-check-events.jsonl "$attempt" 2>> "${KASEKI_RESULTS_DIR}"/goal-check-stderr.log || true
|
|
4735
4738
|
fi
|
|
4736
4739
|
|
|
4737
|
-
if [ "$GOAL_CHECK_EXIT" -eq 0 ] && ! validate_goal_check_artifact "$GOAL_CHECK_CANDIDATE_ARTIFACT" ${KASEKI_RESULTS_DIR}/goal-check.json "$attempt" ${KASEKI_RESULTS_DIR}/goal-check-validation-reason.txt; then
|
|
4740
|
+
if [ "$GOAL_CHECK_EXIT" -eq 0 ] && ! validate_goal_check_artifact "$GOAL_CHECK_CANDIDATE_ARTIFACT" "${KASEKI_RESULTS_DIR}"/goal-check.json "$attempt" ${KASEKI_RESULTS_DIR}/goal-check-validation-reason.txt; then
|
|
4738
4741
|
GOAL_CHECK_EXIT=86
|
|
4739
|
-
goal_check_validation_reason="$(cat ${KASEKI_RESULTS_DIR}/goal-check-validation-reason.txt 2>/dev/null || printf 'schema_mismatch')"
|
|
4740
|
-
goal_check_validation_summary="$(cat ${KASEKI_RESULTS_DIR}/goal-check-validation-summary.txt 2>/dev/null || printf 'goal-check artifact validation failed')"
|
|
4742
|
+
goal_check_validation_reason="$(cat "${KASEKI_RESULTS_DIR}"/goal-check-validation-reason.txt 2>/dev/null || printf 'schema_mismatch')"
|
|
4743
|
+
goal_check_validation_summary="$(cat "${KASEKI_RESULTS_DIR}"/goal-check-validation-summary.txt 2>/dev/null || printf 'goal-check artifact validation failed')"
|
|
4741
4744
|
case "$goal_check_validation_reason" in
|
|
4742
4745
|
missing_file)
|
|
4743
4746
|
GOAL_CHECK_FAILURE_REASON="goal_check_artifact_missing"
|
|
4744
|
-
emit_error_event "goal_check_artifact_missing" "Goal-check candidate artifact was missing: $GOAL_CHECK_CANDIDATE_ARTIFACT ($goal_check_validation_summary; full details: ${KASEKI_RESULTS_DIR}/goal-check-validation-errors.jsonl)" "continue"
|
|
4747
|
+
emit_error_event "goal_check_artifact_missing" "Goal-check candidate artifact was missing: $GOAL_CHECK_CANDIDATE_ARTIFACT ($goal_check_validation_summary; full details: "${KASEKI_RESULTS_DIR}"/goal-check-validation-errors.jsonl)" "continue"
|
|
4745
4748
|
;;
|
|
4746
4749
|
malformed_json)
|
|
4747
4750
|
GOAL_CHECK_FAILURE_REASON="goal_check_artifact_malformed"
|
|
4748
|
-
emit_error_event "goal_check_artifact_malformed" "Goal-check Pi wrote malformed JSON: $goal_check_validation_summary (full details: ${KASEKI_RESULTS_DIR}/goal-check-validation-errors.jsonl)" "continue"
|
|
4751
|
+
emit_error_event "goal_check_artifact_malformed" "Goal-check Pi wrote malformed JSON: $goal_check_validation_summary (full details: "${KASEKI_RESULTS_DIR}"/goal-check-validation-errors.jsonl)" "continue"
|
|
4749
4752
|
;;
|
|
4750
4753
|
*)
|
|
4751
4754
|
GOAL_CHECK_FAILURE_REASON="goal_check_artifact_invalid"
|
|
4752
|
-
emit_error_event "goal_check_artifact_invalid" "Goal-check Pi did not write a schema-valid JSON verdict: $goal_check_validation_summary (full details: ${KASEKI_RESULTS_DIR}/goal-check-validation-errors.jsonl)" "continue"
|
|
4755
|
+
emit_error_event "goal_check_artifact_invalid" "Goal-check Pi did not write a schema-valid JSON verdict: $goal_check_validation_summary (full details: "${KASEKI_RESULTS_DIR}"/goal-check-validation-errors.jsonl)" "continue"
|
|
4753
4756
|
;;
|
|
4754
4757
|
esac
|
|
4755
4758
|
fi
|
|
@@ -4783,12 +4786,12 @@ if (valid.size === 1) {
|
|
|
4783
4786
|
|
|
4784
4787
|
build_run_evaluation_prompt() {
|
|
4785
4788
|
local validation_tail progress_tail stage_timings dependency_cache restoration_report draft_pr_body metadata_text goal_setting_context test_impact_context
|
|
4786
|
-
validation_tail="$(tail -80 ${KASEKI_RESULTS_DIR}/validation.log 2>/dev/null || true)"
|
|
4787
|
-
progress_tail="$(tail -80 ${KASEKI_RESULTS_DIR}/progress.log 2>/dev/null || true)"
|
|
4788
|
-
stage_timings="$(tail -80 ${KASEKI_RESULTS_DIR}/stage-timings.tsv 2>/dev/null || true)"
|
|
4789
|
-
dependency_cache="$(tail -80 ${KASEKI_RESULTS_DIR}/dependency-cache.log 2>/dev/null || true)"
|
|
4790
|
-
restoration_report="$(tail -80 ${KASEKI_RESULTS_DIR}/restoration-report.md 2>/dev/null || true)"
|
|
4791
|
-
metadata_text="$(cat ${KASEKI_RESULTS_DIR}/metadata.json 2>/dev/null || true)"
|
|
4789
|
+
validation_tail="$(tail -80 "${KASEKI_RESULTS_DIR}"/validation.log 2>/dev/null || true)"
|
|
4790
|
+
progress_tail="$(tail -80 "${KASEKI_RESULTS_DIR}"/progress.log 2>/dev/null || true)"
|
|
4791
|
+
stage_timings="$(tail -80 "${KASEKI_RESULTS_DIR}"/stage-timings.tsv 2>/dev/null || true)"
|
|
4792
|
+
dependency_cache="$(tail -80 "${KASEKI_RESULTS_DIR}"/dependency-cache.log 2>/dev/null || true)"
|
|
4793
|
+
restoration_report="$(tail -80 "${KASEKI_RESULTS_DIR}"/restoration-report.md 2>/dev/null || true)"
|
|
4794
|
+
metadata_text="$(cat "${KASEKI_RESULTS_DIR}"/metadata.json 2>/dev/null || true)"
|
|
4792
4795
|
draft_pr_body="$(build_pr_body)"
|
|
4793
4796
|
if [ -s "$TEST_IMPACT_WARNINGS_ARTIFACT" ]; then
|
|
4794
4797
|
test_impact_context="Static test-impact warnings artifact ($TEST_IMPACT_WARNINGS_ARTIFACT):
|
|
@@ -4834,15 +4837,15 @@ This is NOT another goal-check. The goal-check evaluator already determined if t
|
|
|
4834
4837
|
- Quality metrics, SMART criteria, anti-patterns
|
|
4835
4838
|
|
|
4836
4839
|
**Agent Artifacts** (verify goal was realized):
|
|
4837
|
-
- Goal-check verdict: ${KASEKI_RESULTS_DIR}/goal-check.json
|
|
4838
|
-
- Scouting report: ${KASEKI_RESULTS_DIR}/scouting.json
|
|
4839
|
-
- Changed files: ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
4840
|
-
- Git diff and status: ${KASEKI_RESULTS_DIR}/git.diff, ${KASEKI_RESULTS_DIR}/git.status
|
|
4841
|
-
- Validation timings/logs: ${KASEKI_RESULTS_DIR}/pre-validation-timings.tsv, ${KASEKI_RESULTS_DIR}/validation-timings.tsv, ${KASEKI_RESULTS_DIR}/validation.log
|
|
4840
|
+
- Goal-check verdict: "${KASEKI_RESULTS_DIR}"/goal-check.json
|
|
4841
|
+
- Scouting report: "${KASEKI_RESULTS_DIR}"/scouting.json
|
|
4842
|
+
- Changed files: "${KASEKI_RESULTS_DIR}"/changed-files.txt
|
|
4843
|
+
- Git diff and status: "${KASEKI_RESULTS_DIR}"/git.diff, ${KASEKI_RESULTS_DIR}/git.status
|
|
4844
|
+
- Validation timings/logs: "${KASEKI_RESULTS_DIR}"/pre-validation-timings.tsv, ${KASEKI_RESULTS_DIR}/validation-timings.tsv, ${KASEKI_RESULTS_DIR}/validation.log
|
|
4842
4845
|
- Static test-impact warnings (non-blocking): $TEST_IMPACT_WARNINGS_ARTIFACT
|
|
4843
|
-
- Stage timings: ${KASEKI_RESULTS_DIR}/stage-timings.tsv
|
|
4844
|
-
- Progress log: ${KASEKI_RESULTS_DIR}/progress.log
|
|
4845
|
-
- Metadata: ${KASEKI_RESULTS_DIR}/metadata.json
|
|
4846
|
+
- Stage timings: "${KASEKI_RESULTS_DIR}"/stage-timings.tsv
|
|
4847
|
+
- Progress log: "${KASEKI_RESULTS_DIR}"/progress.log
|
|
4848
|
+
- Metadata: "${KASEKI_RESULTS_DIR}"/metadata.json
|
|
4846
4849
|
|
|
4847
4850
|
## Evaluation Framework
|
|
4848
4851
|
|
|
@@ -5056,12 +5059,12 @@ run_run_evaluation() {
|
|
|
5056
5059
|
printf '\n==> run evaluation\n'
|
|
5057
5060
|
set_current_stage "run evaluation"
|
|
5058
5061
|
if [ "$KASEKI_RUN_EVALUATION" != "1" ]; then
|
|
5059
|
-
printf 'Run evaluation skipped because KASEKI_RUN_EVALUATION=%s.\n' "$KASEKI_RUN_EVALUATION" | tee -a ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log
|
|
5062
|
+
printf 'Run evaluation skipped because KASEKI_RUN_EVALUATION=%s.\n' "$KASEKI_RUN_EVALUATION" | tee -a "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log
|
|
5060
5063
|
record_stage_timing "run evaluation" 0 0 "skipped_by_config"
|
|
5061
5064
|
return 0
|
|
5062
5065
|
fi
|
|
5063
5066
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
5064
|
-
printf 'Run evaluation skipped for dry-run/startup-check mode.\n' | tee -a ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log
|
|
5067
|
+
printf 'Run evaluation skipped for dry-run/startup-check mode.\n' | tee -a "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log
|
|
5065
5068
|
record_stage_timing "run evaluation" 0 0 "dry_run=true"
|
|
5066
5069
|
return 0
|
|
5067
5070
|
fi
|
|
@@ -5070,19 +5073,19 @@ run_run_evaluation() {
|
|
|
5070
5073
|
write_metadata "$STATUS"
|
|
5071
5074
|
evaluation_prompt="$(build_run_evaluation_prompt)"
|
|
5072
5075
|
evaluation_start="$(date +%s)"
|
|
5073
|
-
eval_dirty_before="$(git status --porcelain 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true)"
|
|
5074
|
-
chmod -R a-w ${KASEKI_WORKSPACE_DIR}/repo 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true
|
|
5076
|
+
eval_dirty_before="$(git status --porcelain 2>> "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log || true)"
|
|
5077
|
+
chmod -R a-w "${KASEKI_WORKSPACE_DIR}"/repo 2>> "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log || true
|
|
5075
5078
|
set +e
|
|
5076
5079
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
5077
5080
|
timeout --signal=SIGTERM "$KASEKI_RUN_EVALUATION_TIMEOUT_SECONDS" \
|
|
5078
5081
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_RUN_EVALUATION_MODEL" "$evaluation_prompt" \
|
|
5079
|
-
2> >(tee -a ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log >&2) \
|
|
5082
|
+
2> >(tee -a "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log >&2) \
|
|
5080
5083
|
| tee "$RUN_EVALUATION_RAW_EVENTS" \
|
|
5081
|
-
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
5084
|
+
| kaseki-pi-progress-stream "${KASEKI_RESULTS_DIR}"/progress.jsonl "${KASEKI_RESULTS_DIR}"/progress.log
|
|
5082
5085
|
RUN_EVALUATION_EXIT="${PIPESTATUS[0]}"
|
|
5083
5086
|
unset evaluation_prompt
|
|
5084
5087
|
RUN_EVALUATION_DURATION_SECONDS=$((RUN_EVALUATION_DURATION_SECONDS + $(date +%s) - evaluation_start))
|
|
5085
|
-
chmod -R u+w ${KASEKI_WORKSPACE_DIR}/repo 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true
|
|
5088
|
+
chmod -R u+w "${KASEKI_WORKSPACE_DIR}"/repo 2>> "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log || true
|
|
5086
5089
|
set +e
|
|
5087
5090
|
|
|
5088
5091
|
if [ "$RUN_EVALUATION_EXIT" -eq 0 ] && ! node -e '
|
|
@@ -5112,15 +5115,15 @@ artifact.timestamp = new Date().toISOString();
|
|
|
5112
5115
|
artifact.model = model;
|
|
5113
5116
|
artifact.actual_model = actualModel;
|
|
5114
5117
|
fs.writeFileSync(output, JSON.stringify(artifact, null, 2) + "\n");
|
|
5115
|
-
' "$RUN_EVALUATION_CANDIDATE_ARTIFACT" "$RUN_EVALUATION_ARTIFACT" "$KASEKI_RUN_EVALUATION_MODEL" "$RUN_EVALUATION_ACTUAL_MODEL" 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log; then
|
|
5118
|
+
' "$RUN_EVALUATION_CANDIDATE_ARTIFACT" "$RUN_EVALUATION_ARTIFACT" "$KASEKI_RUN_EVALUATION_MODEL" "$RUN_EVALUATION_ACTUAL_MODEL" 2>> "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log; then
|
|
5116
5119
|
RUN_EVALUATION_EXIT=86
|
|
5117
5120
|
emit_error_event "run_evaluation_artifact_invalid" "Run-evaluation Pi did not write a schema-valid JSON artifact" "continue"
|
|
5118
5121
|
fi
|
|
5119
5122
|
rm -f "$RUN_EVALUATION_CANDIDATE_ARTIFACT"
|
|
5120
|
-
kaseki-pi-event-filter "$RUN_EVALUATION_RAW_EVENTS" ${KASEKI_RESULTS_DIR}/run-evaluation-events.jsonl ${KASEKI_RESULTS_DIR}/run-evaluation-summary.json 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true
|
|
5123
|
+
kaseki-pi-event-filter "$RUN_EVALUATION_RAW_EVENTS" "${KASEKI_RESULTS_DIR}"/run-evaluation-events.jsonl ${KASEKI_RESULTS_DIR}/run-evaluation-summary.json 2>> "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log || true
|
|
5121
5124
|
RUN_EVALUATION_ACTUAL_MODEL="$(node -e 'try { const s=require(process.env.KASEKI_RESULTS_DIR + "/run-evaluation-summary.json"); const v=String(s.selected_model || s.model || "").trim(); console.log(v && v !== "unknown" && v !== "null" ? v : "unknown"); } catch { console.log("unknown"); }' 2>/dev/null)"
|
|
5122
5125
|
if [ -s "$RUN_EVALUATION_ARTIFACT" ]; then
|
|
5123
|
-
node - "$RUN_EVALUATION_ARTIFACT" "$RUN_EVALUATION_ACTUAL_MODEL" <<'NODE' 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true
|
|
5126
|
+
node - "$RUN_EVALUATION_ARTIFACT" "$RUN_EVALUATION_ACTUAL_MODEL" <<'NODE' 2>> "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log || true
|
|
5124
5127
|
const fs = require('fs');
|
|
5125
5128
|
const [file, actualModel] = process.argv.slice(2);
|
|
5126
5129
|
const artifact = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
@@ -5129,12 +5132,12 @@ fs.writeFileSync(file, JSON.stringify(artifact, null, 2) + '\n');
|
|
|
5129
5132
|
NODE
|
|
5130
5133
|
fi
|
|
5131
5134
|
|
|
5132
|
-
eval_dirty_after="$(git status --porcelain 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true)"
|
|
5135
|
+
eval_dirty_after="$(git status --porcelain 2>> "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log || true)"
|
|
5133
5136
|
if [ "$eval_dirty_before" != "$eval_dirty_after" ]; then
|
|
5134
5137
|
RUN_EVALUATION_EXIT=86
|
|
5135
5138
|
emit_error_event "run_evaluation_workspace_modified" "Read-only run evaluation changed repository state; restoring workspace" "continue"
|
|
5136
|
-
git reset --hard -q HEAD 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true
|
|
5137
|
-
git clean -fd -q 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true
|
|
5139
|
+
git reset --hard -q HEAD 2>> "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log || true
|
|
5140
|
+
git clean -fd -q 2>> "${KASEKI_RESULTS_DIR}"/run-evaluation-stderr.log || true
|
|
5138
5141
|
fi
|
|
5139
5142
|
|
|
5140
5143
|
if [ "$RUN_EVALUATION_EXIT" -ne 0 ] || [ ! -s "$RUN_EVALUATION_ARTIFACT" ]; then
|
|
@@ -5995,7 +5998,7 @@ derive_pr_title() {
|
|
|
5995
5998
|
|
|
5996
5999
|
candidate="$(printf '%s' "${TASK_PROMPT:-}" | sanitize_pr_metadata_text)"
|
|
5997
6000
|
prompt_for_prefix="$candidate"
|
|
5998
|
-
if [ -s ${KASEKI_RESULTS_DIR}/result-summary.md ]; then
|
|
6001
|
+
if [ -s "${KASEKI_RESULTS_DIR}"/result-summary.md ]; then
|
|
5999
6002
|
summary_candidate="$(
|
|
6000
6003
|
awk '
|
|
6001
6004
|
/^##[[:space:]]+Summary[[:space:]]*$/ { in_summary=1; next }
|
|
@@ -6006,13 +6009,13 @@ derive_pr_title() {
|
|
|
6006
6009
|
sub(/^[[:space:]]*[0-9]+[.)][[:space:]]+/, "", line)
|
|
6007
6010
|
if (line !~ /^[[:space:]]*$/) { print line; exit }
|
|
6008
6011
|
}
|
|
6009
|
-
' ${KASEKI_RESULTS_DIR}/result-summary.md 2>/dev/null | sanitize_pr_metadata_text
|
|
6012
|
+
' "${KASEKI_RESULTS_DIR}"/result-summary.md 2>/dev/null | sanitize_pr_metadata_text
|
|
6010
6013
|
)"
|
|
6011
6014
|
fi
|
|
6012
6015
|
if [ -n "$summary_candidate" ]; then
|
|
6013
6016
|
candidate="$summary_candidate"
|
|
6014
|
-
elif [ -z "$candidate" ] && [ -s ${KASEKI_RESULTS_DIR}/result-summary.md ]; then
|
|
6015
|
-
candidate="$(sed -n '/^- Status:/p; /^- Changed files:/p; /^- Validation:/p' ${KASEKI_RESULTS_DIR}/result-summary.md 2>/dev/null | head -n 3 | sanitize_pr_metadata_text)"
|
|
6017
|
+
elif [ -z "$candidate" ] && [ -s "${KASEKI_RESULTS_DIR}"/result-summary.md ]; then
|
|
6018
|
+
candidate="$(sed -n '/^- Status:/p; /^- Changed files:/p; /^- Validation:/p' "${KASEKI_RESULTS_DIR}"/result-summary.md 2>/dev/null | head -n 3 | sanitize_pr_metadata_text)"
|
|
6016
6019
|
fi
|
|
6017
6020
|
|
|
6018
6021
|
candidate="$(printf '%s' "$candidate" | sed -E 's/^[[:space:]]*([0-9]+[.)]|[-*])[[:space:]]+//' | tr '\n' ' ' | sed -E 's/[[:space:]]+/ /g; s/(^|[[:space:]])[0-9]+[.)][[:space:]]+/\1/g; s/(^|[[:space:]])[-*][[:space:]]+/\1/g; s/userfacing/user-facing/Ig; s/customerfacing/customer-facing/Ig; s/front[ -]?end/frontend/Ig; s/back[ -]?end/backend/Ig; s/full[ -]?stack/full-stack/Ig; s/^[[:space:]]+//; s/[[:space:]]+$//')"
|
|
@@ -6022,8 +6025,8 @@ derive_pr_title() {
|
|
|
6022
6025
|
candidate="$stripped"
|
|
6023
6026
|
fi
|
|
6024
6027
|
|
|
6025
|
-
if [ -s ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
6026
|
-
changed_files="$(sanitize_pr_metadata_text < ${KASEKI_RESULTS_DIR}/changed-files.txt || true)"
|
|
6028
|
+
if [ -s "${KASEKI_RESULTS_DIR}"/changed-files.txt ]; then
|
|
6029
|
+
changed_files="$(sanitize_pr_metadata_text < "${KASEKI_RESULTS_DIR}"/changed-files.txt || true)"
|
|
6027
6030
|
else
|
|
6028
6031
|
changed_files=""
|
|
6029
6032
|
fi
|
|
@@ -6353,10 +6356,10 @@ build_pr_improvements_summary() {
|
|
|
6353
6356
|
done < "$changed_files_file"
|
|
6354
6357
|
fi
|
|
6355
6358
|
|
|
6356
|
-
if [ -s ${KASEKI_RESULTS_DIR}/result-summary.md ]; then
|
|
6359
|
+
if [ -s "${KASEKI_RESULTS_DIR}"/result-summary.md ]; then
|
|
6357
6360
|
summary_source="${KASEKI_RESULTS_DIR}/result-summary.md"
|
|
6358
6361
|
else
|
|
6359
|
-
for artifact in ${KASEKI_RESULTS_DIR}/analysis.md ${KASEKI_RESULTS_DIR}/pi-summary.json; do
|
|
6362
|
+
for artifact in "${KASEKI_RESULTS_DIR}"/analysis.md ${KASEKI_RESULTS_DIR}/pi-summary.json; do
|
|
6360
6363
|
if [ -s "$artifact" ]; then
|
|
6361
6364
|
summary_source="$artifact"
|
|
6362
6365
|
break
|
|
@@ -6542,7 +6545,7 @@ $(build_pr_improvements_summary)
|
|
|
6542
6545
|
## Agent review
|
|
6543
6546
|
$(build_pr_agent_review "$all_validation_statuses_pass")
|
|
6544
6547
|
|
|
6545
|
-
$(if [ -s ${KASEKI_RESULTS_DIR}/run-evaluation.json ]; then printf '## Agent evaluation\n%s\n\n' "$(build_pr_agent_evaluation)"; fi)
|
|
6548
|
+
$(if [ -s "${KASEKI_RESULTS_DIR}"/run-evaluation.json ]; then printf '## Agent evaluation\n%s\n\n' "$(build_pr_agent_evaluation)"; fi)
|
|
6546
6549
|
## Validation
|
|
6547
6550
|
### Validation statuses
|
|
6548
6551
|
- Pre-agent validation: $pre_validation_status
|
|
@@ -6591,11 +6594,11 @@ run_github_operations() {
|
|
|
6591
6594
|
owner="$GITHUB_REPO_OWNER"
|
|
6592
6595
|
repo="$GITHUB_REPO_NAME"
|
|
6593
6596
|
else
|
|
6594
|
-
printf -- 'Cannot parse GitHub repo URL: %s\n' "$REPO_URL" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6597
|
+
printf -- 'Cannot parse GitHub repo URL: %s\n' "$REPO_URL" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6595
6598
|
return 7
|
|
6596
6599
|
fi
|
|
6597
6600
|
|
|
6598
|
-
printf -- 'GitHub operations: owner=%s, repo=%s\n' "$owner" "$repo" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6601
|
+
printf -- 'GitHub operations: owner=%s, repo=%s\n' "$owner" "$repo" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6599
6602
|
GITHUB_OPERATION_PHASE="setup"
|
|
6600
6603
|
|
|
6601
6604
|
# Set git user for commits
|
|
@@ -6604,7 +6607,7 @@ run_github_operations() {
|
|
|
6604
6607
|
|
|
6605
6608
|
# Generate GitHub App installation token
|
|
6606
6609
|
GITHUB_OPERATION_PHASE="token_generation"
|
|
6607
|
-
printf 'Generating GitHub App installation token...\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6610
|
+
printf 'Generating GitHub App installation token...\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6608
6611
|
local github_app_token_helper="${KASEKI_GITHUB_APP_TOKEN_HELPER:-/usr/local/bin/github-app-token}"
|
|
6609
6612
|
local token_stdout_tmp token_stderr_tmp token_exit_code token_stderr token_parse_result token_error token_http_status
|
|
6610
6613
|
token_stdout_tmp="$(mktemp /tmp/github-app-token-stdout.XXXXXX)" || { printf 'Failed to create token stdout temp file\n' >&2; return 7; }
|
|
@@ -6625,7 +6628,7 @@ run_github_operations() {
|
|
|
6625
6628
|
if [ "$token_parse_result" != "$token_error" ]; then
|
|
6626
6629
|
token_http_status="${token_parse_result#*$'\t'}"
|
|
6627
6630
|
fi
|
|
6628
|
-
printf 'Failed to generate token: %s\n' "$token_error" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6631
|
+
printf 'Failed to generate token: %s\n' "$token_error" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6629
6632
|
GITHUB_API_ERROR_TYPE="github_app_token_error"
|
|
6630
6633
|
GITHUB_API_ERROR_MESSAGE="$token_error"
|
|
6631
6634
|
GITHUB_API_HTTP_STATUS="$token_http_status"
|
|
@@ -6635,83 +6638,83 @@ run_github_operations() {
|
|
|
6635
6638
|
fi
|
|
6636
6639
|
|
|
6637
6640
|
# Use helper to extract token from JSON response
|
|
6638
|
-
if ! run_node_subprocess token "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); process.stdout.write(d.token || '')" "$token_data" ${KASEKI_RESULTS_DIR}/git-push.log; then
|
|
6639
|
-
printf -- 'Failed to extract token from response: %s\n' "$token_data" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6641
|
+
if ! run_node_subprocess token "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); process.stdout.write(d.token || '')" "$token_data" "${KASEKI_RESULTS_DIR}"/git-push.log; then
|
|
6642
|
+
printf -- 'Failed to extract token from response: %s\n' "$token_data" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6640
6643
|
GITHUB_PUSH_EXIT=7
|
|
6641
6644
|
return 7
|
|
6642
6645
|
fi
|
|
6643
6646
|
|
|
6644
6647
|
if [ -z "$token" ]; then
|
|
6645
|
-
printf -- 'Failed to extract token from response (empty result)\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6648
|
+
printf -- 'Failed to extract token from response (empty result)\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6646
6649
|
GITHUB_PUSH_EXIT=7
|
|
6647
6650
|
return 7
|
|
6648
6651
|
fi
|
|
6649
6652
|
|
|
6650
|
-
printf 'Token generated successfully\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6653
|
+
printf 'Token generated successfully\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6651
6654
|
|
|
6652
6655
|
# Create and push feature branch
|
|
6653
6656
|
GITHUB_OPERATION_PHASE="branch_creation"
|
|
6654
6657
|
feature_branch="kaseki/$INSTANCE_NAME"
|
|
6655
|
-
printf -- 'Creating feature branch: %s\n' "$feature_branch" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6658
|
+
printf -- 'Creating feature branch: %s\n' "$feature_branch" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6656
6659
|
git checkout -b "$feature_branch" || {
|
|
6657
|
-
printf 'Failed to create branch\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6660
|
+
printf 'Failed to create branch\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6658
6661
|
GITHUB_PUSH_EXIT=7
|
|
6659
6662
|
return 7
|
|
6660
6663
|
}
|
|
6661
6664
|
|
|
6662
6665
|
# Commit changes (git should already have changes from pi agent)
|
|
6663
6666
|
GITHUB_OPERATION_PHASE="commit"
|
|
6664
|
-
printf 'Committing changes...\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6665
|
-
if [ ! -s ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
6666
|
-
printf 'No changed files to stage\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6667
|
+
printf 'Committing changes...\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6668
|
+
if [ ! -s "${KASEKI_RESULTS_DIR}"/changed-files.txt ]; then
|
|
6669
|
+
printf 'No changed files to stage\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6667
6670
|
GITHUB_PUSH_EXIT=7
|
|
6668
6671
|
return 7
|
|
6669
6672
|
fi
|
|
6670
6673
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
6671
6674
|
[ -z "$changed_file" ] && continue
|
|
6672
6675
|
git add -- "$changed_file" || {
|
|
6673
|
-
printf -- 'Failed to stage changed file: %s\n' "$changed_file" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6676
|
+
printf -- 'Failed to stage changed file: %s\n' "$changed_file" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6674
6677
|
GITHUB_PUSH_EXIT=7
|
|
6675
6678
|
return 7
|
|
6676
6679
|
}
|
|
6677
|
-
done < ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
6680
|
+
done < "${KASEKI_RESULTS_DIR}"/changed-files.txt
|
|
6678
6681
|
if ! git commit -m "Kaseki: $INSTANCE_NAME"; then
|
|
6679
|
-
printf 'No changes to commit or commit failed\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6682
|
+
printf 'No changes to commit or commit failed\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6680
6683
|
GITHUB_PUSH_EXIT=7
|
|
6681
6684
|
return 7
|
|
6682
6685
|
fi
|
|
6683
6686
|
|
|
6684
6687
|
# Push branch
|
|
6685
6688
|
GITHUB_OPERATION_PHASE="push"
|
|
6686
|
-
printf 'Pushing branch to GitHub...\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6689
|
+
printf 'Pushing branch to GitHub...\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6687
6690
|
local askpass_file
|
|
6688
|
-
if ! create_github_askpass_helper ${KASEKI_RESULTS_DIR}/git-push.log 'GitHub credential helper'; then
|
|
6691
|
+
if ! create_github_askpass_helper "${KASEKI_RESULTS_DIR}"/git-push.log 'GitHub credential helper'; then
|
|
6689
6692
|
return 8
|
|
6690
6693
|
fi
|
|
6691
6694
|
askpass_file="$GITHUB_ASKPASS_FILE"
|
|
6692
6695
|
|
|
6693
6696
|
KASEKI_GITHUB_TOKEN="$token" GIT_ASKPASS="$askpass_file" GIT_TERMINAL_PROMPT=0 \
|
|
6694
|
-
git push "https://github.com/$owner/$repo.git" "$feature_branch" --force-with-lease 2>&1 | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6697
|
+
git push "https://github.com/$owner/$repo.git" "$feature_branch" --force-with-lease 2>&1 | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6695
6698
|
git_push_exit="${PIPESTATUS[0]:-1}"
|
|
6696
6699
|
if [ "$git_push_exit" -eq 0 ]; then
|
|
6697
|
-
printf 'Branch pushed successfully\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6700
|
+
printf 'Branch pushed successfully\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6698
6701
|
else
|
|
6699
6702
|
rm -f "$askpass_file"
|
|
6700
|
-
printf 'Failed to push branch (exit %s)\n' "$git_push_exit" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6703
|
+
printf 'Failed to push branch (exit %s)\n' "$git_push_exit" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6701
6704
|
GITHUB_PUSH_EXIT="$git_push_exit"
|
|
6702
6705
|
return "$git_push_exit"
|
|
6703
6706
|
fi
|
|
6704
6707
|
rm -f "$askpass_file"
|
|
6705
6708
|
|
|
6706
6709
|
if [ "$KASEKI_PUBLISH_MODE" = "branch" ]; then
|
|
6707
|
-
printf 'Publish mode branch: skipping pull request creation.\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6710
|
+
printf 'Publish mode branch: skipping pull request creation.\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6708
6711
|
GITHUB_PR_EXIT=0
|
|
6709
6712
|
GITHUB_OPERATION_PHASE="completed"
|
|
6710
6713
|
unset token
|
|
6711
6714
|
return 0
|
|
6712
6715
|
fi
|
|
6713
6716
|
if ! is_pr_creation_mode; then
|
|
6714
|
-
printf 'Publish mode %s: skipping pull request creation.\n' "$KASEKI_PUBLISH_MODE" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6717
|
+
printf 'Publish mode %s: skipping pull request creation.\n' "$KASEKI_PUBLISH_MODE" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6715
6718
|
GITHUB_PR_EXIT=0
|
|
6716
6719
|
GITHUB_OPERATION_PHASE="completed"
|
|
6717
6720
|
unset token
|
|
@@ -6721,7 +6724,7 @@ run_github_operations() {
|
|
|
6721
6724
|
# Create pull request. Both pr and draft_pr push a branch and create a PR;
|
|
6722
6725
|
# only draft_pr marks the GitHub Pulls API request as draft.
|
|
6723
6726
|
GITHUB_OPERATION_PHASE="pr_creation"
|
|
6724
|
-
printf 'Creating pull request...\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6727
|
+
printf 'Creating pull request...\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6725
6728
|
emit_progress "github operations" "pr_creation_starting"
|
|
6726
6729
|
local pr_title pr_body pr_response pr_url pr_number pr_http_status pr_draft_json
|
|
6727
6730
|
pr_title="$(derive_pr_title)"
|
|
@@ -6745,7 +6748,7 @@ run_github_operations() {
|
|
|
6745
6748
|
- Generated at (UTC): $fallback_timestamp
|
|
6746
6749
|
EOF
|
|
6747
6750
|
)
|
|
6748
|
-
printf 'WARN: build_pr_body returned empty content after sanitization; using fallback PR body.\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6751
|
+
printf 'WARN: build_pr_body returned empty content after sanitization; using fallback PR body.\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6749
6752
|
fi
|
|
6750
6753
|
if is_pr_draft_mode; then
|
|
6751
6754
|
pr_draft_json=true
|
|
@@ -6759,7 +6762,7 @@ EOF
|
|
|
6759
6762
|
|
|
6760
6763
|
while [ $retry_count -le "$max_retries" ]; do
|
|
6761
6764
|
if [ $retry_count -gt 0 ]; then
|
|
6762
|
-
printf 'Retrying PR creation (attempt %d of %d) after %ds delay...\n' $((retry_count + 1)) "$max_retries" "$backoff_delay" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6765
|
+
printf 'Retrying PR creation (attempt %d of %d) after %ds delay...\n' $((retry_count + 1)) "$max_retries" "$backoff_delay" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6763
6766
|
emit_progress "github operations" "pr_creation_attempt $((retry_count + 1))/$max_retries"
|
|
6764
6767
|
sleep "$backoff_delay"
|
|
6765
6768
|
# Exponential backoff: 2s, 4s, 8s
|
|
@@ -6769,31 +6772,31 @@ EOF
|
|
|
6769
6772
|
|
|
6770
6773
|
# Capture both response and HTTP status code
|
|
6771
6774
|
local pr_response_file temp_status_file
|
|
6772
|
-
pr_response_file="$(mktemp /tmp/kaseki-pr-response.XXXXXX)" || { printf 'Failed to create temp file for PR response\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2; GITHUB_PR_EXIT=8; return 8; }
|
|
6773
|
-
temp_status_file="$(mktemp /tmp/kaseki-pr-status.XXXXXX)" || { printf 'Failed to create temp file for PR status\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2; GITHUB_PR_EXIT=8; return 8; }
|
|
6775
|
+
pr_response_file="$(mktemp /tmp/kaseki-pr-response.XXXXXX)" || { printf 'Failed to create temp file for PR response\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2; GITHUB_PR_EXIT=8; return 8; }
|
|
6776
|
+
temp_status_file="$(mktemp /tmp/kaseki-pr-status.XXXXXX)" || { printf 'Failed to create temp file for PR status\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2; GITHUB_PR_EXIT=8; return 8; }
|
|
6774
6777
|
|
|
6775
6778
|
if [ $retry_count -eq 0 ] && [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6776
|
-
printf 'Debug: Creating PR with head=%s, base=%s, draft=%s\n' "$feature_branch" "$GIT_REF" "$pr_draft_json" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6779
|
+
printf 'Debug: Creating PR with head=%s, base=%s, draft=%s\n' "$feature_branch" "$GIT_REF" "$pr_draft_json" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6777
6780
|
fi
|
|
6778
6781
|
|
|
6779
6782
|
# Encode PR title and body as JSON strings
|
|
6780
6783
|
local pr_title_json pr_body_json
|
|
6781
6784
|
pr_title_json='""'
|
|
6782
6785
|
pr_body_json='""'
|
|
6783
|
-
if ! run_node_subprocess pr_title_json "console.log(JSON.stringify(require('fs').readFileSync(0, 'utf8')))" "$pr_title" ${KASEKI_RESULTS_DIR}/git-push.log; then
|
|
6784
|
-
printf 'ERROR: Failed to JSON encode PR title\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6786
|
+
if ! run_node_subprocess pr_title_json "console.log(JSON.stringify(require('fs').readFileSync(0, 'utf8')))" "$pr_title" "${KASEKI_RESULTS_DIR}"/git-push.log; then
|
|
6787
|
+
printf 'ERROR: Failed to JSON encode PR title\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6785
6788
|
GITHUB_PR_EXIT=8
|
|
6786
6789
|
return 8
|
|
6787
6790
|
fi
|
|
6788
|
-
if ! run_node_subprocess pr_body_json "console.log(JSON.stringify(require('fs').readFileSync(0, 'utf8')))" "$pr_body" ${KASEKI_RESULTS_DIR}/git-push.log; then
|
|
6789
|
-
printf 'ERROR: Failed to JSON encode PR body\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6791
|
+
if ! run_node_subprocess pr_body_json "console.log(JSON.stringify(require('fs').readFileSync(0, 'utf8')))" "$pr_body" "${KASEKI_RESULTS_DIR}"/git-push.log; then
|
|
6792
|
+
printf 'ERROR: Failed to JSON encode PR body\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6790
6793
|
GITHUB_PR_EXIT=8
|
|
6791
6794
|
return 8
|
|
6792
6795
|
fi
|
|
6793
6796
|
|
|
6794
6797
|
# Validate both variables are non-empty before using in curl
|
|
6795
6798
|
if [ -z "$pr_title_json" ] || [ -z "$pr_body_json" ]; then
|
|
6796
|
-
printf 'ERROR: JSON encoding produced empty values (title=%s, body=%s)\n' "$pr_title_json" "$pr_body_json" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6799
|
+
printf 'ERROR: JSON encoding produced empty values (title=%s, body=%s)\n' "$pr_title_json" "$pr_body_json" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6797
6800
|
GITHUB_PR_EXIT=8
|
|
6798
6801
|
return 8
|
|
6799
6802
|
fi
|
|
@@ -6818,7 +6821,7 @@ EOF
|
|
|
6818
6821
|
|
|
6819
6822
|
if [ $curl_exit -ne 0 ]; then
|
|
6820
6823
|
# curl command itself failed (network error, timeout, etc.)
|
|
6821
|
-
printf 'GitHub PR API curl command failed with exit code %d (attempt %d)\n' "$curl_exit" $((retry_count + 1)) | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6824
|
+
printf 'GitHub PR API curl command failed with exit code %d (attempt %d)\n' "$curl_exit" $((retry_count + 1)) | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6822
6825
|
GITHUB_API_HTTP_STATUS="0"
|
|
6823
6826
|
if is_github_pr_error_retryable "0" "curl_error" && [ "$retry_count" -lt "$((max_retries - 1))" ]; then
|
|
6824
6827
|
retry_count=$((retry_count + 1))
|
|
@@ -6836,43 +6839,43 @@ EOF
|
|
|
6836
6839
|
fi
|
|
6837
6840
|
|
|
6838
6841
|
if [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6839
|
-
printf 'Debug: PR API response HTTP status: %s (attempt %d)\n' "$pr_http_status" $((retry_count + 1)) | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6842
|
+
printf 'Debug: PR API response HTTP status: %s (attempt %d)\n' "$pr_http_status" $((retry_count + 1)) | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6840
6843
|
fi
|
|
6841
6844
|
|
|
6842
6845
|
# Validate the API response
|
|
6843
|
-
if validate_github_api_response "$pr_http_status" "$pr_response" ${KASEKI_RESULTS_DIR}/git-push.log; then
|
|
6846
|
+
if validate_github_api_response "$pr_http_status" "$pr_response" "${KASEKI_RESULTS_DIR}"/git-push.log; then
|
|
6844
6847
|
# API returned success (201); now extract the URL and issue number using helper
|
|
6845
|
-
if ! run_node_subprocess pr_url "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); process.stdout.write(d.html_url || '')" "$pr_response" ${KASEKI_RESULTS_DIR}/git-push.log; then
|
|
6846
|
-
printf 'ERROR: Failed to extract PR URL from API response\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6848
|
+
if ! run_node_subprocess pr_url "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); process.stdout.write(d.html_url || '')" "$pr_response" "${KASEKI_RESULTS_DIR}"/git-push.log; then
|
|
6849
|
+
printf 'ERROR: Failed to extract PR URL from API response\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6847
6850
|
emit_error_event "github_pr_response_malformed" "Failed to parse PR API response to extract html_url" "exit"
|
|
6848
6851
|
GITHUB_PR_EXIT=9
|
|
6849
6852
|
pr_url=""
|
|
6850
6853
|
fi
|
|
6851
|
-
if ! run_node_subprocess pr_number "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); if (Number.isInteger(d.number)) process.stdout.write(String(d.number));" "$pr_response" ${KASEKI_RESULTS_DIR}/git-push.log; then
|
|
6852
|
-
printf 'Warning: failed to extract PR number from API response; leaving PR unlabeled\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6854
|
+
if ! run_node_subprocess pr_number "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); if (Number.isInteger(d.number)) process.stdout.write(String(d.number));" "$pr_response" "${KASEKI_RESULTS_DIR}"/git-push.log; then
|
|
6855
|
+
printf 'Warning: failed to extract PR number from API response; leaving PR unlabeled\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6853
6856
|
pr_number=""
|
|
6854
6857
|
fi
|
|
6855
6858
|
|
|
6856
6859
|
if [ -n "$pr_url" ]; then
|
|
6857
6860
|
GITHUB_PR_URL="$pr_url"
|
|
6858
6861
|
GITHUB_PR_EXIT=0
|
|
6859
|
-
printf 'Pull request created: %s\n' "$pr_url" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6862
|
+
printf 'Pull request created: %s\n' "$pr_url" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6860
6863
|
if [ -n "$pr_number" ]; then
|
|
6861
|
-
apply_github_pr_labels "$owner" "$repo" "$pr_number" "$token" ${KASEKI_RESULTS_DIR}/git-push.log || true
|
|
6864
|
+
apply_github_pr_labels "$owner" "$repo" "$pr_number" "$token" "${KASEKI_RESULTS_DIR}"/git-push.log || true
|
|
6862
6865
|
# Request repository owner as reviewer for personal repos
|
|
6863
|
-
request_owner_review "$pr_response" "$token" ${KASEKI_RESULTS_DIR}/git-push.log || true
|
|
6866
|
+
request_owner_review "$pr_response" "$token" "${KASEKI_RESULTS_DIR}"/git-push.log || true
|
|
6864
6867
|
else
|
|
6865
|
-
printf 'Warning: PR API response missing number field; leaving PR unlabeled\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6868
|
+
printf 'Warning: PR API response missing number field; leaving PR unlabeled\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6866
6869
|
fi
|
|
6867
6870
|
pr_created=1
|
|
6868
6871
|
rm -f "$pr_response_file"
|
|
6869
6872
|
break
|
|
6870
6873
|
else
|
|
6871
6874
|
# HTTP 201 but no html_url in response - malformed response
|
|
6872
|
-
printf 'Pull request API returned success (201) but response missing html_url field\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6875
|
+
printf 'Pull request API returned success (201) but response missing html_url field\n' | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6873
6876
|
emit_error_event "github_pr_response_malformed" "GitHub PR API returned 201 but response missing html_url field" "exit"
|
|
6874
6877
|
if [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6875
|
-
printf 'Debug: Full API response:\n%s\n' "$pr_response" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6878
|
+
printf 'Debug: Full API response:\n%s\n' "$pr_response" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6876
6879
|
fi
|
|
6877
6880
|
GITHUB_PR_EXIT=9
|
|
6878
6881
|
pr_created=0
|
|
@@ -6882,17 +6885,17 @@ EOF
|
|
|
6882
6885
|
else
|
|
6883
6886
|
# API returned an error
|
|
6884
6887
|
if is_github_pr_error_retryable "$pr_http_status" "$GITHUB_API_ERROR_TYPE" && [ "$retry_count" -lt "$((max_retries - 1))" ]; then
|
|
6885
|
-
printf 'GitHub API returned retryable error (attempt %d): %s (HTTP %s)\n' $((retry_count + 1)) "$GITHUB_API_ERROR_TYPE" "$pr_http_status" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6888
|
+
printf 'GitHub API returned retryable error (attempt %d): %s (HTTP %s)\n' $((retry_count + 1)) "$GITHUB_API_ERROR_TYPE" "$pr_http_status" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6886
6889
|
retry_count=$((retry_count + 1))
|
|
6887
6890
|
rm -f "$pr_response_file"
|
|
6888
6891
|
continue
|
|
6889
6892
|
else
|
|
6890
6893
|
# Permanent error, give up
|
|
6891
|
-
printf 'Failed to create PR. API error: %s\n' "$GITHUB_API_ERROR_MESSAGE" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6894
|
+
printf 'Failed to create PR. API error: %s\n' "$GITHUB_API_ERROR_MESSAGE" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
6892
6895
|
emit_error_event "github_pr_api_failed" "GitHub API error ($GITHUB_API_ERROR_TYPE): $GITHUB_API_ERROR_MESSAGE (HTTP $GITHUB_API_HTTP_STATUS)" "exit"
|
|
6893
6896
|
if [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6894
|
-
printf 'Debug: API error type: %s, HTTP status: %s\n' "$GITHUB_API_ERROR_TYPE" "$GITHUB_API_HTTP_STATUS" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6895
|
-
printf 'Debug: Full response:\n%s\n' "$pr_response" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6897
|
+
printf 'Debug: API error type: %s, HTTP status: %s\n' "$GITHUB_API_ERROR_TYPE" "$GITHUB_API_HTTP_STATUS" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6898
|
+
printf 'Debug: Full response:\n%s\n' "$pr_response" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
6896
6899
|
fi
|
|
6897
6900
|
GITHUB_PR_EXIT=9
|
|
6898
6901
|
pr_created=0
|
|
@@ -6925,7 +6928,7 @@ if [ "$GITHUB_APP_ENABLED" = "1" ]; then
|
|
|
6925
6928
|
printf 'ERROR: GitHub operations preflight health check failed\n' >&2
|
|
6926
6929
|
printf 'GitHub App is enabled but configuration or dependencies are missing.\n' >&2
|
|
6927
6930
|
printf 'Proceeding with kaseki run, but GitHub operations will be skipped or fail.\n' >&2
|
|
6928
|
-
emit_error_event "github_preflight_failed" "GitHub operations health check failed; check ${KASEKI_RESULTS_DIR}/github-health-check.log for details" "continue"
|
|
6931
|
+
emit_error_event "github_preflight_failed" "GitHub operations health check failed; check "${KASEKI_RESULTS_DIR}"/github-health-check.log for details" "continue"
|
|
6929
6932
|
fi
|
|
6930
6933
|
fi
|
|
6931
6934
|
|
|
@@ -6949,7 +6952,7 @@ unset OPENROUTER_API_KEY secret_content
|
|
|
6949
6952
|
if [ -z "$openrouter_api_key" ]; then
|
|
6950
6953
|
set_current_stage "agent setup"
|
|
6951
6954
|
openrouter_api_key_file="${OPENROUTER_API_KEY_FILE:-/agents/secrets/openrouter_api_key}"
|
|
6952
|
-
printf 'Missing OpenRouter API key. Set OPENROUTER_API_KEY or provide %s.\n' "$openrouter_api_key_file" | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log >&2
|
|
6955
|
+
printf 'Missing OpenRouter API key. Set OPENROUTER_API_KEY or provide %s.\n' "$openrouter_api_key_file" | tee -a "${KASEKI_RESULTS_DIR}"/pi-stderr.log >&2
|
|
6953
6956
|
: > "$RAW_EVENTS"
|
|
6954
6957
|
PI_EXIT=2
|
|
6955
6958
|
STATUS=2
|
|
@@ -6960,7 +6963,7 @@ fi
|
|
|
6960
6963
|
if ! run_clone_repository; then
|
|
6961
6964
|
exit 0
|
|
6962
6965
|
fi
|
|
6963
|
-
cd ${KASEKI_WORKSPACE_DIR}/repo || { STATUS=1; FAILED_COMMAND="enter repository"; exit "$STATUS"; }
|
|
6966
|
+
cd "${KASEKI_WORKSPACE_DIR}"/repo || { STATUS=1; FAILED_COMMAND="enter repository"; exit "$STATUS"; }
|
|
6964
6967
|
|
|
6965
6968
|
prepare_dependencies() {
|
|
6966
6969
|
if [ ! -f package.json ]; then
|
|
@@ -7190,7 +7193,7 @@ if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ] && [ "$KASEKI_PRE_AGENT_VALID
|
|
|
7190
7193
|
emit_progress "baseline validation cache" "failed to save (non-blocking)"
|
|
7191
7194
|
fi
|
|
7192
7195
|
# Cleanup baseline workspace to save space
|
|
7193
|
-
rm -rf ${KASEKI_WORKSPACE_BASELINE_DIR} 2>/dev/null || true
|
|
7196
|
+
rm -rf "${KASEKI_WORKSPACE_BASELINE_DIR}" 2>/dev/null || true
|
|
7194
7197
|
else
|
|
7195
7198
|
BASELINE_CACHE_STATUS="checkout_failed"
|
|
7196
7199
|
emit_error_event "baseline_checkout_failed" "Failed to setup baseline for test failure comparison; continuing without baseline" "continue"
|
|
@@ -7207,13 +7210,13 @@ if [ "$KASEKI_PRE_AGENT_VALIDATION" = "0" ]; then
|
|
|
7207
7210
|
printf '\n==> pre-agent validation\n'
|
|
7208
7211
|
set_current_stage "pre-agent validation"
|
|
7209
7212
|
emit_progress "pre-agent validation" "skipped by KASEKI_PRE_AGENT_VALIDATION=0"
|
|
7210
|
-
printf 'Pre-agent validation skipped because KASEKI_PRE_AGENT_VALIDATION=0.\n' | tee -a ${KASEKI_RESULTS_DIR}/pre-validation.log
|
|
7213
|
+
printf 'Pre-agent validation skipped because KASEKI_PRE_AGENT_VALIDATION=0.\n' | tee -a "${KASEKI_RESULTS_DIR}"/pre-validation.log
|
|
7211
7214
|
record_stage_timing "pre-agent validation" 0 0 "skipped_by_config"
|
|
7212
7215
|
else
|
|
7213
7216
|
run_validation_commands \
|
|
7214
7217
|
"pre-agent validation" \
|
|
7215
7218
|
"$KASEKI_PRE_AGENT_VALIDATION_COMMANDS" \
|
|
7216
|
-
${KASEKI_RESULTS_DIR}/pre-validation.log \
|
|
7219
|
+
"${KASEKI_RESULTS_DIR}"/pre-validation.log \
|
|
7217
7220
|
"$PRE_VALIDATION_RAW_LOG" \
|
|
7218
7221
|
"$PRE_VALIDATION_TIMINGS_FILE" \
|
|
7219
7222
|
"$PRE_VALIDATION_ENV_LOG" \
|
|
@@ -7242,7 +7245,7 @@ set_current_stage "typescript precheck"
|
|
|
7242
7245
|
if ! run_typescript_precheck; then
|
|
7243
7246
|
if [ "$KASEKI_SCOUTING" = "1" ]; then
|
|
7244
7247
|
# If scouting is enabled (experimental path), continue anyway with warning
|
|
7245
|
-
printf 'WARNING: TypeScript pre-check failed, but continuing due to scouting mode being enabled.\n' | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
7248
|
+
printf 'WARNING: TypeScript pre-check failed, but continuing due to scouting mode being enabled.\n' | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
7246
7249
|
else
|
|
7247
7250
|
# Without scouting, TypeScript failures are fatal
|
|
7248
7251
|
STATUS="$TS_PRE_CHECK_EXIT"
|
|
@@ -7258,13 +7261,13 @@ printf 'Pi version: %s\n' "$PI_VERSION"
|
|
|
7258
7261
|
# === Phase 1: Early Filesystem Diagnostics (Before Scouting) ===
|
|
7259
7262
|
# Detects read-only filesystem constraints that would cause silent scouting failures
|
|
7260
7263
|
check_filesystem_capabilities() {
|
|
7261
|
-
local results_dir="$
|
|
7264
|
+
local results_dir="$KASEKI_RESULTS_DIR"
|
|
7262
7265
|
local filesystem_writable=true
|
|
7263
7266
|
local readonly_reason=""
|
|
7264
7267
|
|
|
7265
7268
|
emit_progress "filesystem capabilities check" "verifying write capabilities for artifacts"
|
|
7266
7269
|
|
|
7267
|
-
# Test ${KASEKI_RESULTS_DIR}/ writability
|
|
7270
|
+
# Test "${KASEKI_RESULTS_DIR}"/ writability
|
|
7268
7271
|
if [ ! -w "$results_dir" ]; then
|
|
7269
7272
|
filesystem_writable=false
|
|
7270
7273
|
readonly_reason="${KASEKI_RESULTS_DIR} is READ-ONLY (Docker mounted with :ro or container --read-only flag)"
|
|
@@ -7277,13 +7280,13 @@ check_filesystem_capabilities() {
|
|
|
7277
7280
|
printf ' - Container UID: %d\n' "$(id -u)"
|
|
7278
7281
|
printf ' - Expected reason: Docker mounted with :ro flag or container --read-only\n'
|
|
7279
7282
|
printf '\nImpact:\n'
|
|
7280
|
-
printf ' - Scouting Pi agent will exit 0 but ${KASEKI_RESULTS_DIR}/scouting-candidate.json will be MISSING\n'
|
|
7283
|
+
printf ' - Scouting Pi agent will exit 0 but "${KASEKI_RESULTS_DIR}"/scouting-candidate.json will be MISSING\n'
|
|
7281
7284
|
printf ' - Validation logs and artifacts cannot be written\n'
|
|
7282
7285
|
printf ' - This causes exit code 86 (scouting validation failure)\n'
|
|
7283
7286
|
printf '\nFix: Remount ${KASEKI_RESULTS_DIR} as read-write\n'
|
|
7284
7287
|
printf ' docker run -v /path/to${KASEKI_RESULTS_DIR}:${KASEKI_RESULTS_DIR}:rw ...\n'
|
|
7285
7288
|
printf 'Or remove --read-only flag from Docker run command\n'
|
|
7286
|
-
} | tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
7289
|
+
} | tee -a "${KASEKI_RESULTS_DIR}"/scouting-stderr.log
|
|
7287
7290
|
else
|
|
7288
7291
|
# Test actual write capability
|
|
7289
7292
|
local test_file="$results_dir/.kaseki-fs-test-$$"
|
|
@@ -7298,14 +7301,14 @@ check_filesystem_capabilities() {
|
|
|
7298
7301
|
fi
|
|
7299
7302
|
|
|
7300
7303
|
# Record in metadata for post-mortem analysis
|
|
7301
|
-
printf '%s\n' "$filesystem_writable" > ${KASEKI_RESULTS_DIR}/filesystem-writable-at-start.txt
|
|
7302
|
-
[ -n "$readonly_reason" ] && printf '%s\n' "$readonly_reason" > ${KASEKI_RESULTS_DIR}/filesystem-readonly-reason.txt
|
|
7304
|
+
printf '%s\n' "$filesystem_writable" > "${KASEKI_RESULTS_DIR}"/filesystem-writable-at-start.txt
|
|
7305
|
+
[ -n "$readonly_reason" ] && printf '%s\n' "$readonly_reason" > "${KASEKI_RESULTS_DIR}"/filesystem-readonly-reason.txt
|
|
7303
7306
|
|
|
7304
7307
|
if [ "$filesystem_writable" = "false" ]; then
|
|
7305
7308
|
if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ]; then
|
|
7306
7309
|
emit_progress "baseline validation preparation" "DISABLED due to read-only filesystem detected"
|
|
7307
7310
|
KASEKI_BASELINE_VALIDATION_ENABLED="0"
|
|
7308
|
-
printf '[filesystem-diagnostic] Baseline validation auto-disabled due to read-only filesystem\n' | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
7311
|
+
printf '[filesystem-diagnostic] Baseline validation auto-disabled due to read-only filesystem\n' | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
7309
7312
|
fi
|
|
7310
7313
|
return 1
|
|
7311
7314
|
fi
|
|
@@ -7355,7 +7358,7 @@ if [ "$KASEKI_SCOUTING" = "1" ] && [ -f "$SCOUTING_ARTIFACT" ]; then
|
|
|
7355
7358
|
export KASEKI_VALIDATION_ALLOWLIST="$merged_validation_allowlist"
|
|
7356
7359
|
|
|
7357
7360
|
# Log merge decisions with structured JSON construction so pattern text is escaped safely.
|
|
7358
|
-
append_jsonl_object ${KASEKI_RESULTS_DIR}/metadata.jsonl \
|
|
7361
|
+
append_jsonl_object "${KASEKI_RESULTS_DIR}"/metadata.jsonl \
|
|
7359
7362
|
"timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
7360
7363
|
"event=allowlist_merge" \
|
|
7361
7364
|
"scouting_agent_patterns=$scouting_agent_patterns" \
|
|
@@ -7368,14 +7371,14 @@ if [ "$KASEKI_SCOUTING" = "1" ] && [ -f "$SCOUTING_ARTIFACT" ]; then
|
|
|
7368
7371
|
allowlist_merge_status="merged"
|
|
7369
7372
|
|
|
7370
7373
|
# Run coverage validation with dry-run
|
|
7371
|
-
if [ -s ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
7372
|
-
run_scouting_allowlist_coverage "$SCOUTING_ARTIFACT" 2>&1 | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
7374
|
+
if [ -s "${KASEKI_RESULTS_DIR}"/changed-files.txt ]; then
|
|
7375
|
+
run_scouting_allowlist_coverage "$SCOUTING_ARTIFACT" 2>&1 | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
7373
7376
|
fi
|
|
7374
7377
|
|
|
7375
7378
|
emit_progress "derive allowlist from scouting" "finished (status=$allowlist_merge_status)"
|
|
7376
7379
|
else
|
|
7377
7380
|
# Pattern validation failed - fail fast
|
|
7378
|
-
printf 'ERROR: Derived allowlist patterns failed validation. Cannot proceed.\n' | tee -a ${KASEKI_RESULTS_DIR}/quality.log >&2
|
|
7381
|
+
printf 'ERROR: Derived allowlist patterns failed validation. Cannot proceed.\n' | tee -a "${KASEKI_RESULTS_DIR}"/quality.log >&2
|
|
7379
7382
|
STATUS=86
|
|
7380
7383
|
FAILED_COMMAND="allowlist pattern validation"
|
|
7381
7384
|
emit_error_event "scouting_allowlist_invalid" "Derived allowlist patterns failed validation" "exit"
|
|
@@ -7383,7 +7386,7 @@ if [ "$KASEKI_SCOUTING" = "1" ] && [ -f "$SCOUTING_ARTIFACT" ]; then
|
|
|
7383
7386
|
fi
|
|
7384
7387
|
else
|
|
7385
7388
|
# Derivation failed - log and fail fast
|
|
7386
|
-
printf 'ERROR: Failed to derive allowlist from scouting artifact: %s\n' "$scouting_output" | tee -a ${KASEKI_RESULTS_DIR}/quality.log >&2
|
|
7389
|
+
printf 'ERROR: Failed to derive allowlist from scouting artifact: %s\n' "$scouting_output" | tee -a "${KASEKI_RESULTS_DIR}"/quality.log >&2
|
|
7387
7390
|
STATUS=86
|
|
7388
7391
|
FAILED_COMMAND="allowlist derivation from scouting"
|
|
7389
7392
|
emit_error_event "scouting_allowlist_derivation_failed" "Failed to derive allowlist from scouting artifact" "exit"
|
|
@@ -7421,7 +7424,7 @@ if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
|
7421
7424
|
printf ' Model: %s\n' "$KASEKI_MODEL"
|
|
7422
7425
|
printf ' Timeout: %s seconds\n' "$KASEKI_AGENT_TIMEOUT_SECONDS"
|
|
7423
7426
|
printf ' Task: %s\n' "$TASK_PROMPT"
|
|
7424
|
-
} | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log
|
|
7427
|
+
} | tee -a "${KASEKI_RESULTS_DIR}"/pi-stderr.log
|
|
7425
7428
|
emit_progress "pi coding agent" "skipped (dry-run)"
|
|
7426
7429
|
record_stage_timing "pi coding agent" "0" "$PI_DURATION_SECONDS" "dry_run=true"
|
|
7427
7430
|
else
|
|
@@ -7433,9 +7436,9 @@ else
|
|
|
7433
7436
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
7434
7437
|
timeout --signal=SIGTERM "$KASEKI_AGENT_TIMEOUT_SECONDS" \
|
|
7435
7438
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_MODEL" "$agent_prompt" \
|
|
7436
|
-
2> >(tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log >&2) \
|
|
7439
|
+
2> >(tee -a "${KASEKI_RESULTS_DIR}"/pi-stderr.log >&2) \
|
|
7437
7440
|
| tee "$RAW_EVENTS" \
|
|
7438
|
-
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
7441
|
+
| kaseki-pi-progress-stream "${KASEKI_RESULTS_DIR}"/progress.jsonl "${KASEKI_RESULTS_DIR}"/progress.log
|
|
7439
7442
|
PI_EXIT="${PIPESTATUS[0]}"
|
|
7440
7443
|
unset agent_prompt
|
|
7441
7444
|
PI_DURATION_SECONDS=$(($(date +%s) - PI_START_EPOCH))
|
|
@@ -7444,7 +7447,7 @@ else
|
|
|
7444
7447
|
record_stage_timing "pi coding agent" "$PI_EXIT" "$PI_DURATION_SECONDS" "timeout_seconds=$KASEKI_AGENT_TIMEOUT_SECONDS"
|
|
7445
7448
|
|
|
7446
7449
|
if [ "$KASEKI_DEBUG_RAW_EVENTS" = "1" ]; then
|
|
7447
|
-
cp "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.raw.jsonl
|
|
7450
|
+
cp "$RAW_EVENTS" "${KASEKI_RESULTS_DIR}"/pi-events.raw.jsonl
|
|
7448
7451
|
fi
|
|
7449
7452
|
|
|
7450
7453
|
PI_EXTRACTION_DEPS_OK=1
|
|
@@ -7455,7 +7458,7 @@ else
|
|
|
7455
7458
|
missing_executables+=("$required_exec")
|
|
7456
7459
|
fi
|
|
7457
7460
|
done
|
|
7458
|
-
for helper_file in ${KASEKI_APP_LIB_DIR}/event-aggregator.js ${KASEKI_APP_LIB_DIR}/timestamp-tracker.js ${KASEKI_APP_LIB_DIR}/progress-stream-utils.js; do
|
|
7461
|
+
for helper_file in "${KASEKI_APP_LIB_DIR}"/event-aggregator.js ${KASEKI_APP_LIB_DIR}/timestamp-tracker.js ${KASEKI_APP_LIB_DIR}/progress-stream-utils.js; do
|
|
7459
7462
|
if [ ! -f "$helper_file" ]; then
|
|
7460
7463
|
missing_helpers+=("$helper_file")
|
|
7461
7464
|
fi
|
|
@@ -7468,34 +7471,34 @@ else
|
|
|
7468
7471
|
[ -z "$missing_helpers_joined" ] && missing_helpers_joined="none"
|
|
7469
7472
|
extraction_error=$(node -e "console.log(JSON.stringify({error:'pi_extraction_dependency_missing',missing_executables:process.argv[1],missing_helpers:process.argv[2],action:'Ensure required Pi binaries are on PATH and helper files exist in the image before running extraction'}))" "$missing_execs_joined" "$missing_helpers_joined")
|
|
7470
7473
|
printf '%s
|
|
7471
|
-
' "$extraction_error" | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log ${KASEKI_RESULTS_DIR}/quality.log >&2
|
|
7474
|
+
' "$extraction_error" | tee -a "${KASEKI_RESULTS_DIR}"/pi-stderr.log "${KASEKI_RESULTS_DIR}"/quality.log >&2
|
|
7472
7475
|
emit_error_event "pi_extraction_dependency_missing" "missing executables: $missing_execs_joined; missing helpers: $missing_helpers_joined; ensure Pi binaries are in PATH and /app/lib helpers are present" "abort_extraction"
|
|
7473
7476
|
if [ "$STATUS" -eq 0 ]; then
|
|
7474
7477
|
STATUS=87
|
|
7475
7478
|
FAILED_COMMAND="pi artifact extraction dependency validation"
|
|
7476
7479
|
fi
|
|
7477
|
-
cp "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.raw.jsonl 2>/dev/null || true
|
|
7480
|
+
cp "$RAW_EVENTS" "${KASEKI_RESULTS_DIR}"/pi-events.raw.jsonl 2>/dev/null || true
|
|
7478
7481
|
fi
|
|
7479
7482
|
|
|
7480
7483
|
FILTER_EXIT=0
|
|
7481
7484
|
if [ "$PI_EXTRACTION_DEPS_OK" -eq 1 ]; then
|
|
7482
7485
|
set +e
|
|
7483
|
-
kaseki-pi-event-filter "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.jsonl ${KASEKI_RESULTS_DIR}/pi-summary.json
|
|
7486
|
+
kaseki-pi-event-filter "$RAW_EVENTS" "${KASEKI_RESULTS_DIR}"/pi-events.jsonl "${KASEKI_RESULTS_DIR}"/pi-summary.json
|
|
7484
7487
|
FILTER_EXIT=$?
|
|
7485
7488
|
set +e
|
|
7486
7489
|
fi
|
|
7487
7490
|
if [ "$FILTER_EXIT" -ne 0 ]; then
|
|
7488
|
-
printf 'pi-event-filter failed with exit %s; raw events preserved as fallback artifact\n' "$FILTER_EXIT" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
7489
|
-
printf 'ERROR: kaseki-pi-event-filter failed with exit %s while exporting Pi events\n' "$FILTER_EXIT" | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log >&2
|
|
7491
|
+
printf 'pi-event-filter failed with exit %s; raw events preserved as fallback artifact\n' "$FILTER_EXIT" | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
7492
|
+
printf 'ERROR: kaseki-pi-event-filter failed with exit %s while exporting Pi events\n' "$FILTER_EXIT" | tee -a "${KASEKI_RESULTS_DIR}"/pi-stderr.log >&2
|
|
7490
7493
|
emit_error_event "pi_event_filter_failed" "kaseki-pi-event-filter exited with code $FILTER_EXIT" "continue"
|
|
7491
7494
|
if [ "$STATUS" -eq 0 ]; then
|
|
7492
7495
|
STATUS="$FILTER_EXIT"
|
|
7493
7496
|
FAILED_COMMAND="kaseki-pi-event-filter"
|
|
7494
7497
|
fi
|
|
7495
|
-
cp "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.raw.jsonl 2>/dev/null || true
|
|
7498
|
+
cp "$RAW_EVENTS" "${KASEKI_RESULTS_DIR}"/pi-events.raw.jsonl 2>/dev/null || true
|
|
7496
7499
|
fi
|
|
7497
|
-
if [ -s "$RAW_EVENTS" ] && { [ ! -s ${KASEKI_RESULTS_DIR}/pi-events.jsonl ] || [ ! -s ${KASEKI_RESULTS_DIR}/pi-summary.json ]; }; then
|
|
7498
|
-
printf 'ERROR: pi event export incomplete; raw events are non-empty but event artifacts are missing/empty\n' | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log >&2
|
|
7500
|
+
if [ -s "$RAW_EVENTS" ] && { [ ! -s "${KASEKI_RESULTS_DIR}"/pi-events.jsonl ] || [ ! -s "${KASEKI_RESULTS_DIR}"/pi-summary.json ]; }; then
|
|
7501
|
+
printf 'ERROR: pi event export incomplete; raw events are non-empty but event artifacts are missing/empty\n' | tee -a "${KASEKI_RESULTS_DIR}"/pi-stderr.log >&2
|
|
7499
7502
|
emit_error_event "pi_event_export_incomplete" "RAW_EVENTS has data but exported artifacts are empty or missing" "continue"
|
|
7500
7503
|
if [ "$STATUS" -eq 0 ]; then
|
|
7501
7504
|
STATUS=86
|
|
@@ -7504,16 +7507,16 @@ else
|
|
|
7504
7507
|
fi
|
|
7505
7508
|
|
|
7506
7509
|
# Process hashline_edit events (non-fatal phase; failures don't block pipeline)
|
|
7507
|
-
if [ "$KASEKI_HASHLINE_EDITS" != "0" ] && [ -s ${KASEKI_RESULTS_DIR}/pi-events.jsonl ]; then
|
|
7510
|
+
if [ "$KASEKI_HASHLINE_EDITS" != "0" ] && [ -s "${KASEKI_RESULTS_DIR}"/pi-events.jsonl ]; then
|
|
7508
7511
|
emit_progress "hashline validation" "started"
|
|
7509
7512
|
HASHLINE_EXIT=0
|
|
7510
7513
|
set +e
|
|
7511
|
-
npx tsx ${KASEKI_APP_LIB_DIR}/hashline-event-handler-cli.js ${KASEKI_RESULTS_DIR}/pi-events.jsonl /workspace ${KASEKI_RESULTS_DIR}/hashline-events.jsonl ${KASEKI_RESULTS_DIR}/hashline-summary.json 2>> ${KASEKI_RESULTS_DIR}/hashline-validation.log
|
|
7514
|
+
npx tsx "${KASEKI_APP_LIB_DIR}"/hashline-event-handler-cli.js "${KASEKI_RESULTS_DIR}"/pi-events.jsonl /workspace ${KASEKI_RESULTS_DIR}/hashline-events.jsonl ${KASEKI_RESULTS_DIR}/hashline-summary.json 2>> "${KASEKI_RESULTS_DIR}"/hashline-validation.log
|
|
7512
7515
|
HASHLINE_EXIT=$?
|
|
7513
7516
|
set +e
|
|
7514
7517
|
|
|
7515
7518
|
if [ "$HASHLINE_EXIT" -ne 0 ]; then
|
|
7516
|
-
printf 'Warning: hashline validation exited with code %s (non-fatal; continuing pipeline)\n' "$HASHLINE_EXIT" | tee -a ${KASEKI_RESULTS_DIR}/hashline-validation.log
|
|
7519
|
+
printf 'Warning: hashline validation exited with code %s (non-fatal; continuing pipeline)\n' "$HASHLINE_EXIT" | tee -a "${KASEKI_RESULTS_DIR}"/hashline-validation.log
|
|
7517
7520
|
emit_event "warning" "warning_type=hashline_validation_failed" "detail=hashline_edit processing exited with code $HASHLINE_EXIT"
|
|
7518
7521
|
else
|
|
7519
7522
|
emit_progress "hashline validation" "completed"
|
|
@@ -7570,7 +7573,7 @@ fi
|
|
|
7570
7573
|
|
|
7571
7574
|
if [ "$KASEKI_DRY_RUN" != "1" ]; then
|
|
7572
7575
|
if [ "$PI_EXIT" -eq 124 ]; then
|
|
7573
|
-
printf 'pi timeout after %ss (exit 124)\n' "$KASEKI_AGENT_TIMEOUT_SECONDS" | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log >&2
|
|
7576
|
+
printf 'pi timeout after %ss (exit 124)\n' "$KASEKI_AGENT_TIMEOUT_SECONDS" | tee -a "${KASEKI_RESULTS_DIR}"/pi-stderr.log >&2
|
|
7574
7577
|
if [ "$STATUS" -eq 0 ]; then
|
|
7575
7578
|
STATUS=124
|
|
7576
7579
|
FAILED_COMMAND="pi coding agent timeout"
|
|
@@ -7609,11 +7612,11 @@ printf '\n==> quality checks\n'
|
|
|
7609
7612
|
set_current_stage "quality checks"
|
|
7610
7613
|
emit_progress "quality checks" "started"
|
|
7611
7614
|
stage_start="$(date +%s)"
|
|
7612
|
-
diff_size="$(wc -c < ${KASEKI_RESULTS_DIR}/git.diff | tr -d ' ')"
|
|
7615
|
+
diff_size="$(wc -c < "${KASEKI_RESULTS_DIR}"/git.diff | tr -d ' ')"
|
|
7613
7616
|
if [ "$diff_size" -gt "$KASEKI_MAX_DIFF_BYTES" ]; then
|
|
7614
7617
|
QUALITY_EXIT=4
|
|
7615
7618
|
QUALITY_FAILURE_REASON="max_diff_bytes: $diff_size bytes exceeds limit of $KASEKI_MAX_DIFF_BYTES bytes"
|
|
7616
|
-
printf 'git.diff is too large: %s bytes > %s bytes\n' "$diff_size" "$KASEKI_MAX_DIFF_BYTES" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
7619
|
+
printf 'git.diff is too large: %s bytes > %s bytes\n' "$diff_size" "$KASEKI_MAX_DIFF_BYTES" | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
7617
7620
|
emit_event "quality_gate_rule_evaluated" "rule=max_diff_bytes" "passed=false" "actual=$diff_size" "limit=$KASEKI_MAX_DIFF_BYTES"
|
|
7618
7621
|
else
|
|
7619
7622
|
emit_event "quality_gate_rule_evaluated" "rule=max_diff_bytes" "passed=true" "actual=$diff_size" "limit=$KASEKI_MAX_DIFF_BYTES"
|
|
@@ -7628,17 +7631,17 @@ if [ -n "$allowlist_regex" ]; then
|
|
|
7628
7631
|
if ! printf '%s\n' "$changed_file" | grep -Eq "^(${allowlist_regex})$"; then
|
|
7629
7632
|
QUALITY_EXIT=5
|
|
7630
7633
|
QUALITY_FAILURE_REASON="allowlist_check: file '$changed_file' not in allowlist"
|
|
7631
|
-
printf 'changed file outside allowlist: %s\n' "$changed_file" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
7634
|
+
printf 'changed file outside allowlist: %s\n' "$changed_file" | tee -a "${KASEKI_RESULTS_DIR}"/quality.log
|
|
7632
7635
|
emit_event "quality_gate_rule_evaluated" "rule=allowlist_check" "passed=false" "file=$changed_file"
|
|
7633
7636
|
else
|
|
7634
7637
|
emit_event "quality_gate_rule_evaluated" "rule=allowlist_check" "passed=true" "file=$changed_file"
|
|
7635
7638
|
fi
|
|
7636
|
-
done < ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
7639
|
+
done < "${KASEKI_RESULTS_DIR}"/changed-files.txt
|
|
7637
7640
|
fi
|
|
7638
7641
|
|
|
7639
7642
|
if [ -f package.json ] && node -e "const p=require('./package.json'); process.exit(p.scripts && p.scripts['format:check'] ? 0 : 1)" 2>/dev/null; then
|
|
7640
7643
|
format_command="npm run format:check"
|
|
7641
|
-
printf '%s\n' "$format_command" >> ${KASEKI_RESULTS_DIR}/format-check-command.txt
|
|
7644
|
+
printf '%s\n' "$format_command" >> "${KASEKI_RESULTS_DIR}"/format-check-command.txt
|
|
7642
7645
|
fi
|
|
7643
7646
|
record_stage_timing "quality checks" "$QUALITY_EXIT" "$(($(date +%s) - stage_start))" "diff_size_bytes=$diff_size"
|
|
7644
7647
|
|
|
@@ -7647,7 +7650,7 @@ run_expectation_mismatch_detector
|
|
|
7647
7650
|
|
|
7648
7651
|
pre_validation_goal_check_diff_hash=""
|
|
7649
7652
|
if [ "$STATUS" -eq 0 ] && [ "$PI_EXIT" -eq 0 ] && [ "$QUALITY_EXIT" -eq 0 ]; then
|
|
7650
|
-
pre_validation_goal_check_diff_hash="$(sha256sum ${KASEKI_RESULTS_DIR}/git.diff 2>/dev/null | awk '{print $1}')"
|
|
7653
|
+
pre_validation_goal_check_diff_hash="$(sha256sum "${KASEKI_RESULTS_DIR}"/git.diff 2>/dev/null | awk '{print $1}')"
|
|
7651
7654
|
run_goal_check "$coding_attempt"
|
|
7652
7655
|
collect_goal_check_feedback "$INSTANCE_NAME"
|
|
7653
7656
|
snapshot_attempt_artifacts "$coding_attempt"
|
|
@@ -7679,18 +7682,18 @@ log_validation_environment() {
|
|
|
7679
7682
|
printf '[validation environment] PATH=%s\n' "$PATH"
|
|
7680
7683
|
printf '[validation environment] NODE_OPTIONS=%s\n' "${NODE_OPTIONS:-<not set>}"
|
|
7681
7684
|
printf '[validation environment] NODE_PATH=%s\n' "${NODE_PATH:-<not set>}"
|
|
7682
|
-
printf '[validation environment] disk_space_available=%s\n' "$(df -h ${KASEKI_RESULTS_DIR} 2>/dev/null | tail -1 | awk '{print $4}' || echo '<df failed>')"
|
|
7683
|
-
printf '[validation environment] disk_space_used=%s\n' "$(du -sh ${KASEKI_RESULTS_DIR} 2>/dev/null | cut -f1 || echo '<du failed>')"
|
|
7684
|
-
} | tee -a ${KASEKI_RESULTS_DIR}/validation.log "$VALIDATION_ENV_LOG"
|
|
7685
|
+
printf '[validation environment] disk_space_available=%s\n' "$(df -h "${KASEKI_RESULTS_DIR}" 2>/dev/null | tail -1 | awk '{print $4}' || echo '<df failed>')"
|
|
7686
|
+
printf '[validation environment] disk_space_used=%s\n' "$(du -sh "${KASEKI_RESULTS_DIR}" 2>/dev/null | cut -f1 || echo '<du failed>')"
|
|
7687
|
+
} | tee -a "${KASEKI_RESULTS_DIR}"/validation.log "$VALIDATION_ENV_LOG"
|
|
7685
7688
|
}
|
|
7686
7689
|
log_validation_environment
|
|
7687
|
-
collect_changed_file_state ${KASEKI_RESULTS_DIR}/validation-before-state.txt
|
|
7690
|
+
collect_changed_file_state "${KASEKI_RESULTS_DIR}"/validation-before-state.txt
|
|
7688
7691
|
|
|
7689
7692
|
if [ "$KASEKI_DRY_RUN" = "1" ] || [ -z "$KASEKI_VALIDATION_COMMANDS" ] || [ "$KASEKI_VALIDATION_COMMANDS" = "none" ]; then
|
|
7690
7693
|
run_validation_commands \
|
|
7691
7694
|
"validation" \
|
|
7692
7695
|
"$KASEKI_VALIDATION_COMMANDS" \
|
|
7693
|
-
${KASEKI_RESULTS_DIR}/validation.log \
|
|
7696
|
+
"${KASEKI_RESULTS_DIR}"/validation.log \
|
|
7694
7697
|
"$VALIDATION_RAW_LOG" \
|
|
7695
7698
|
"$VALIDATION_TIMINGS_FILE" \
|
|
7696
7699
|
"$VALIDATION_ENV_LOG" \
|
|
@@ -7699,7 +7702,7 @@ elif [ "$QUALITY_EXIT" -ne 0 ]; then
|
|
|
7699
7702
|
printf '\n==> validation\n'
|
|
7700
7703
|
set_current_stage "validation"
|
|
7701
7704
|
emit_progress "validation" "started"
|
|
7702
|
-
printf 'Validation skipped because quality gates failed with exit %s.\n' "$QUALITY_EXIT" | tee -a ${KASEKI_RESULTS_DIR}/validation.log
|
|
7705
|
+
printf 'Validation skipped because quality gates failed with exit %s.\n' "$QUALITY_EXIT" | tee -a "${KASEKI_RESULTS_DIR}"/validation.log
|
|
7703
7706
|
VALIDATION_EXIT="$QUALITY_EXIT"
|
|
7704
7707
|
if [ -z "$VALIDATION_FAILURE_REASON" ]; then
|
|
7705
7708
|
VALIDATION_FAILURE_REASON="quality_gate_failed: $QUALITY_FAILURE_REASON"
|
|
@@ -7710,14 +7713,14 @@ elif [ "$PI_EXIT" -ne 0 ] && [ "$KASEKI_VALIDATE_AFTER_AGENT_FAILURE" != "1" ];
|
|
|
7710
7713
|
printf '\n==> validation\n'
|
|
7711
7714
|
set_current_stage "validation"
|
|
7712
7715
|
emit_progress "validation" "started"
|
|
7713
|
-
printf 'Validation skipped because pi coding agent failed with exit %s. Set KASEKI_VALIDATE_AFTER_AGENT_FAILURE=1 to run validation anyway.\n' "$PI_EXIT" | tee -a ${KASEKI_RESULTS_DIR}/validation.log
|
|
7716
|
+
printf 'Validation skipped because pi coding agent failed with exit %s. Set KASEKI_VALIDATE_AFTER_AGENT_FAILURE=1 to run validation anyway.\n' "$PI_EXIT" | tee -a "${KASEKI_RESULTS_DIR}"/validation.log
|
|
7714
7717
|
record_stage_timing "validation" "$PI_EXIT" 0 "skipped_after_agent_failure"
|
|
7715
7718
|
emit_progress "validation" "finished with exit $VALIDATION_EXIT"
|
|
7716
7719
|
else
|
|
7717
7720
|
run_validation_commands \
|
|
7718
7721
|
"validation" \
|
|
7719
7722
|
"$KASEKI_VALIDATION_COMMANDS" \
|
|
7720
|
-
${KASEKI_RESULTS_DIR}/validation.log \
|
|
7723
|
+
"${KASEKI_RESULTS_DIR}"/validation.log \
|
|
7721
7724
|
"$VALIDATION_RAW_LOG" \
|
|
7722
7725
|
"$VALIDATION_TIMINGS_FILE" \
|
|
7723
7726
|
"$VALIDATION_ENV_LOG" \
|
|
@@ -7731,18 +7734,18 @@ fi
|
|
|
7731
7734
|
|
|
7732
7735
|
# Check validation-phase allowlist (if configured)
|
|
7733
7736
|
if [ "$VALIDATION_EXIT" -eq 0 ]; then
|
|
7734
|
-
collect_changed_file_state ${KASEKI_RESULTS_DIR}/validation-after-state.txt
|
|
7737
|
+
collect_changed_file_state "${KASEKI_RESULTS_DIR}"/validation-after-state.txt
|
|
7735
7738
|
collect_git_artifacts
|
|
7736
7739
|
if ! check_validation_allowlist; then
|
|
7737
7740
|
: # Exit code already set in check_validation_allowlist
|
|
7738
7741
|
fi
|
|
7739
7742
|
fi
|
|
7740
7743
|
|
|
7741
|
-
post_validation_goal_check_diff_hash="$(sha256sum ${KASEKI_RESULTS_DIR}/git.diff 2>/dev/null | awk '{print $1}')"
|
|
7744
|
+
post_validation_goal_check_diff_hash="$(sha256sum "${KASEKI_RESULTS_DIR}"/git.diff 2>/dev/null | awk '{print $1}')"
|
|
7742
7745
|
if [ "$STATUS" -eq 0 ] && [ "$PI_EXIT" -eq 0 ] && [ "$QUALITY_EXIT" -eq 0 ] && [ "$VALIDATION_EXIT" -eq 0 ] && \
|
|
7743
7746
|
[ -n "$pre_validation_goal_check_diff_hash" ] && [ -n "$post_validation_goal_check_diff_hash" ] && \
|
|
7744
7747
|
[ "$post_validation_goal_check_diff_hash" != "$pre_validation_goal_check_diff_hash" ]; then
|
|
7745
|
-
printf 'Validation commands changed the final git diff; re-running goal check against post-validation artifacts.\n' | tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log
|
|
7748
|
+
printf 'Validation commands changed the final git diff; re-running goal check against post-validation artifacts.\n' | tee -a "${KASEKI_RESULTS_DIR}"/goal-check-stderr.log
|
|
7746
7749
|
emit_progress "goal check" "re-running after validation changed the final diff (attempt $coding_attempt)"
|
|
7747
7750
|
run_goal_check "$coding_attempt"
|
|
7748
7751
|
collect_goal_check_feedback "$INSTANCE_NAME"
|
|
@@ -7776,14 +7779,14 @@ printf '\n==> secret scan\n'
|
|
|
7776
7779
|
set_current_stage "secret scan"
|
|
7777
7780
|
emit_progress "secret scan" "started"
|
|
7778
7781
|
stage_start="$(date +%s)"
|
|
7779
|
-
: > ${KASEKI_RESULTS_DIR}/secret-scan.log
|
|
7782
|
+
: > "${KASEKI_RESULTS_DIR}"/secret-scan.log
|
|
7780
7783
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
7781
|
-
printf '🔄 DRY-RUN MODE: Skipping secret scan (no artifacts to scan)\n' | tee -a ${KASEKI_RESULTS_DIR}/secret-scan.log
|
|
7784
|
+
printf '🔄 DRY-RUN MODE: Skipping secret scan (no artifacts to scan)\n' | tee -a "${KASEKI_RESULTS_DIR}"/secret-scan.log
|
|
7782
7785
|
SECRET_SCAN_EXIT=0
|
|
7783
7786
|
record_stage_timing "secret scan" "0" "$(($(date +%s) - stage_start))" "dry_run=true"
|
|
7784
7787
|
else
|
|
7785
7788
|
# Run the initial scan
|
|
7786
|
-
if grep -R -n -E 'sk-or-[A-Za-z0-9_-]{20,}' ${KASEKI_RESULTS_DIR} ${KASEKI_WORKSPACE_DIR}/repo/.git ${KASEKI_WORKSPACE_DIR}/repo/src ${KASEKI_WORKSPACE_DIR}/repo/tests 2>/dev/null | grep -v '/secret-scan.log:' > ${KASEKI_RESULTS_DIR}/secret-scan.log; then
|
|
7789
|
+
if grep -R -n -E 'sk-or-[A-Za-z0-9_-]{20,}' "${KASEKI_RESULTS_DIR}" "${KASEKI_WORKSPACE_DIR}"/repo/.git "${KASEKI_WORKSPACE_DIR}"/repo/src "${KASEKI_WORKSPACE_DIR}"/repo/tests 2>/dev/null | grep -v '/secret-scan.log:' > "${KASEKI_RESULTS_DIR}"/secret-scan.log; then
|
|
7787
7790
|
# Matches found - check against allowlist
|
|
7788
7791
|
if check_secret_scan_allowlist; then
|
|
7789
7792
|
# All matches are allowlisted
|
|
@@ -7801,7 +7804,6 @@ fi
|
|
|
7801
7804
|
emit_progress "secret scan" "finished with exit $SECRET_SCAN_EXIT"
|
|
7802
7805
|
|
|
7803
7806
|
run_run_evaluation
|
|
7804
|
-
collect_run_evaluation_feedback "$INSTANCE_NAME"
|
|
7805
7807
|
|
|
7806
7808
|
build_github_skip_reasons() {
|
|
7807
7809
|
GITHUB_SKIP_REASONS=()
|
|
@@ -7836,7 +7838,7 @@ printf '\n==> github operations\n'
|
|
|
7836
7838
|
set_current_stage "github operations"
|
|
7837
7839
|
emit_progress "github operations" "started"
|
|
7838
7840
|
stage_start="$(date +%s)"
|
|
7839
|
-
: > ${KASEKI_RESULTS_DIR}/git-push.log
|
|
7841
|
+
: > "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
7840
7842
|
build_github_skip_reasons
|
|
7841
7843
|
if [ "${#GITHUB_SKIP_REASONS[@]}" -eq 0 ]; then
|
|
7842
7844
|
github_app_id_file="$(resolve_github_secret_file "GITHUB_APP_ID_FILE" "github_app_id")"
|
|
@@ -7855,7 +7857,7 @@ if [ "${#GITHUB_SKIP_REASONS[@]}" -eq 0 ]; then
|
|
|
7855
7857
|
else
|
|
7856
7858
|
GITHUB_SKIP_REASONS+=("github_app_secrets_missing")
|
|
7857
7859
|
GITHUB_OPERATION_PHASE="secrets"
|
|
7858
|
-
printf -- 'GitHub operations: skipped (reasons: %s)\n' "$(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
7860
|
+
printf -- 'GitHub operations: skipped (reasons: %s)\n' "$(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log >&2
|
|
7859
7861
|
emit_progress "github operations" "skipped: $(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")"
|
|
7860
7862
|
GITHUB_PUSH_EXIT=7
|
|
7861
7863
|
fi
|
|
@@ -7867,7 +7869,7 @@ else
|
|
|
7867
7869
|
"$([ "$QUALITY_EXIT" -eq 0 ] && printf 'passed' || printf 'failed')" \
|
|
7868
7870
|
"$([ "$SECRET_SCAN_EXIT" -eq 0 ] && printf 'passed' || printf 'failed')" \
|
|
7869
7871
|
"$DIFF_NONEMPTY" \
|
|
7870
|
-
"$GITHUB_APP_ENABLED" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
7872
|
+
"$GITHUB_APP_ENABLED" | tee -a "${KASEKI_RESULTS_DIR}"/git-push.log
|
|
7871
7873
|
emit_progress "github operations" "skipped: $(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")"
|
|
7872
7874
|
fi
|
|
7873
7875
|
if [ "$GITHUB_APP_ENABLED" = "1" ]; then
|