@cyanautomation/kaseki-agent 1.64.1 → 1.64.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/kaseki-agent.sh +587 -498
- package/package.json +1 -1
package/kaseki-agent.sh
CHANGED
|
@@ -3,6 +3,61 @@
|
|
|
3
3
|
# record status/timing artifacts before deciding whether to stop.
|
|
4
4
|
set -uo pipefail
|
|
5
5
|
|
|
6
|
+
# Early exit for helper resolution check - must happen before variable initialization
|
|
7
|
+
if [ "${KASEKI_AGENT_HELPER_RESOLUTION_CHECK:-0}" = "1" ]; then
|
|
8
|
+
# Define helper resolution function locally
|
|
9
|
+
resolve_allowlist_helper() {
|
|
10
|
+
local script_dir="$1"
|
|
11
|
+
local script_relative_helper="$script_dir/scripts/allowlist-helper.sh"
|
|
12
|
+
local fallback_helper="${KASEKI_ALLOWLIST_HELPER_FALLBACK:-/app/scripts/allowlist-helper.sh}"
|
|
13
|
+
|
|
14
|
+
if [ -r "$script_relative_helper" ]; then
|
|
15
|
+
printf '%s\n' "$script_relative_helper"
|
|
16
|
+
return 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
if [ -r "$fallback_helper" ]; then
|
|
20
|
+
printf '%s\n' "$fallback_helper"
|
|
21
|
+
return 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
printf 'ERROR: Allowlist helper is not readable. Expected packaged helper at %s or fallback helper at %s. This worker image or mounted template is incomplete; rebuild the image or restore scripts/allowlist-helper.sh.\n' \
|
|
25
|
+
"$script_relative_helper" \
|
|
26
|
+
"$fallback_helper" >&2
|
|
27
|
+
return 66
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
31
|
+
ALLOWLIST_HELPER="$(resolve_allowlist_helper "$SCRIPT_DIR")"
|
|
32
|
+
allowlist_helper_status=$?
|
|
33
|
+
if [ "$allowlist_helper_status" -ne 0 ]; then
|
|
34
|
+
exit "$allowlist_helper_status"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Source the helper
|
|
38
|
+
# shellcheck source=/dev/null
|
|
39
|
+
. "$ALLOWLIST_HELPER" || {
|
|
40
|
+
printf 'ERROR: Failed to source %s (exit code: %d)\n' "$ALLOWLIST_HELPER" $? >&2
|
|
41
|
+
exit 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Verify the helper was sourced successfully
|
|
45
|
+
if ! declare -f build_allowlist_regex >/dev/null 2>&1; then
|
|
46
|
+
printf 'ERROR: build_allowlist_regex function not found after sourcing %s\n' "$ALLOWLIST_HELPER" >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Call the function to verify it works
|
|
51
|
+
build_allowlist_regex "${KASEKI_CHANGED_FILES_ALLOWLIST:-}" >/dev/null 2>&1 || {
|
|
52
|
+
printf 'ERROR: build_allowlist_regex exited with status %d\n' $? >&2
|
|
53
|
+
exit 1
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Output and exit
|
|
57
|
+
printf 'allowlist_helper=%s\n' "$ALLOWLIST_HELPER"
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
6
61
|
INSTANCE_NAME="${KASEKI_INSTANCE:-kaseki-unknown}"
|
|
7
62
|
REPO_URL="${REPO_URL:-https://github.com/CyanAutomation/crudmapper}"
|
|
8
63
|
GIT_REF="${GIT_REF:-main}"
|
|
@@ -19,12 +74,21 @@ KASEKI_AUTO_LINT_CLEANUP_COMMANDS="${KASEKI_AUTO_LINT_CLEANUP_COMMANDS-npm run l
|
|
|
19
74
|
KASEKI_SKIP_MISSING_NPM_SCRIPTS="${KASEKI_SKIP_MISSING_NPM_SCRIPTS:-1}"
|
|
20
75
|
KASEKI_DEBUG_RAW_EVENTS="${KASEKI_DEBUG_RAW_EVENTS:-0}"
|
|
21
76
|
KASEKI_STREAM_PROGRESS="${KASEKI_STREAM_PROGRESS:-1}"
|
|
22
|
-
KASEKI_RESULTS_DIR="${KASEKI_RESULTS_DIR
|
|
77
|
+
KASEKI_RESULTS_DIR="${KASEKI_RESULTS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
78
|
+
export KASEKI_RESULTS_DIR
|
|
79
|
+
KASEKI_WORKSPACE_DIR="${KASEKI_WORKSPACE_DIR:-/workspace}"
|
|
80
|
+
export KASEKI_WORKSPACE_DIR
|
|
81
|
+
KASEKI_WORKSPACE_BASELINE_DIR="${KASEKI_WORKSPACE_BASELINE_DIR:-${KASEKI_WORKSPACE_BASELINE_DIR}}"
|
|
82
|
+
export KASEKI_WORKSPACE_BASELINE_DIR
|
|
83
|
+
KASEKI_APP_LIB_DIR="${KASEKI_APP_LIB_DIR:-/app/lib}"
|
|
84
|
+
export KASEKI_APP_LIB_DIR
|
|
85
|
+
KASEKI_CACHE_DIR="${KASEKI_CACHE_DIR:-/cache}"
|
|
86
|
+
export KASEKI_CACHE_DIR
|
|
23
87
|
KASEKI_VALIDATE_AFTER_AGENT_FAILURE="${KASEKI_VALIDATE_AFTER_AGENT_FAILURE:-0}"
|
|
24
88
|
KASEKI_PRE_AGENT_VALIDATION="${KASEKI_PRE_AGENT_VALIDATION:-1}"
|
|
25
89
|
KASEKI_PRE_AGENT_VALIDATION_COMMANDS="${KASEKI_PRE_AGENT_VALIDATION_COMMANDS-$KASEKI_VALIDATION_COMMANDS}"
|
|
26
90
|
KASEKI_BASELINE_VALIDATION_ENABLED="${KASEKI_BASELINE_VALIDATION_ENABLED:-1}"
|
|
27
|
-
KASEKI_BASELINE_CACHE_ROOT="${KASEKI_BASELINE_CACHE_ROOT
|
|
91
|
+
KASEKI_BASELINE_CACHE_ROOT="${KASEKI_BASELINE_CACHE_ROOT:-${KASEKI_CACHE_DIR}/kaseki-baseline}"
|
|
28
92
|
KASEKI_BASELINE_CACHE_MAX_AGE_HOURS="${KASEKI_BASELINE_CACHE_MAX_AGE_HOURS:-24}"
|
|
29
93
|
KASEKI_BASELINE_CACHE_DISABLED="${KASEKI_BASELINE_CACHE_DISABLED:-0}"
|
|
30
94
|
KASEKI_TS_PRE_CHECK="${KASEKI_TS_PRE_CHECK:-1}"
|
|
@@ -58,7 +122,7 @@ KASEKI_MAX_DIFF_BYTES="${KASEKI_MAX_DIFF_BYTES:-400000}"
|
|
|
58
122
|
KASEKI_REPO_MEMORY_MODE="${KASEKI_REPO_MEMORY_MODE:-off}"
|
|
59
123
|
KASEKI_REPO_MEMORY_TTL_DAYS="${KASEKI_REPO_MEMORY_TTL_DAYS:-30}"
|
|
60
124
|
KASEKI_REPO_MEMORY_MAX_BYTES="${KASEKI_REPO_MEMORY_MAX_BYTES:-8000}"
|
|
61
|
-
KASEKI_REPO_MEMORY_ROOT="${KASEKI_REPO_MEMORY_ROOT
|
|
125
|
+
KASEKI_REPO_MEMORY_ROOT="${KASEKI_REPO_MEMORY_ROOT:-${KASEKI_CACHE_DIR}/repo-memory}"
|
|
62
126
|
TASK_PROMPT="${TASK_PROMPT:-Make normalizeRole treat a non-string Name fallback safely when FriendlyName is empty or missing. It should fall back to \"Unnamed Role\" instead of preserving arbitrary truthy non-string values. Add or update exactly one compact table-driven Vitest case in tests/parser.validation.ts, with a neutral static test title and no per-case assertion messages or explanatory comments. Do not add broad repeated test blocks. Do not print, inspect, or expose environment variables, secrets, credentials, or API keys. Keep changes limited to the source and test files needed for this fix.}"
|
|
63
127
|
KASEKI_AGENT_GUARDRAILS="${KASEKI_AGENT_GUARDRAILS:-1}"
|
|
64
128
|
KASEKI_RESTORE_DISALLOWED_CHANGES="${KASEKI_RESTORE_DISALLOWED_CHANGES:-1}"
|
|
@@ -134,13 +198,13 @@ TS_PRE_CHECK_DURATION_SECONDS=0
|
|
|
134
198
|
TS_PRE_CHECK_TIMESTAMP=""
|
|
135
199
|
FILTER_STDERR_TAIL=""
|
|
136
200
|
FILTER_STDERR_FILE="/tmp/kaseki-filter-stderr.log"
|
|
137
|
-
VALIDATION_RAW_LOG="/
|
|
138
|
-
PRE_VALIDATION_RAW_LOG="/
|
|
139
|
-
AUTO_LINT_CLEANUP_LOG="/
|
|
140
|
-
AUTO_LINT_CLEANUP_TIMINGS_FILE="/
|
|
141
|
-
FILTER_DIAGNOSTICS_LOG="/
|
|
142
|
-
VALIDATION_ENV_LOG="/
|
|
143
|
-
PRE_VALIDATION_ENV_LOG="/
|
|
201
|
+
VALIDATION_RAW_LOG="${KASEKI_RESULTS_DIR}/validation-raw.log"
|
|
202
|
+
PRE_VALIDATION_RAW_LOG="${KASEKI_RESULTS_DIR}/pre-validation-raw.log"
|
|
203
|
+
AUTO_LINT_CLEANUP_LOG="${KASEKI_RESULTS_DIR}/auto-lint-cleanup.log"
|
|
204
|
+
AUTO_LINT_CLEANUP_TIMINGS_FILE="${KASEKI_RESULTS_DIR}/auto-lint-cleanup-timings.tsv"
|
|
205
|
+
FILTER_DIAGNOSTICS_LOG="${KASEKI_RESULTS_DIR}/filter-diagnostics.log"
|
|
206
|
+
VALIDATION_ENV_LOG="${KASEKI_RESULTS_DIR}/validation-env.log"
|
|
207
|
+
PRE_VALIDATION_ENV_LOG="${KASEKI_RESULTS_DIR}/pre-validation-env.log"
|
|
144
208
|
DIFF_NONEMPTY=false
|
|
145
209
|
QUALITY_EXIT=0
|
|
146
210
|
QUALITY_FAILURE_REASON=""
|
|
@@ -154,25 +218,25 @@ GITHUB_OPERATION_PHASE=""
|
|
|
154
218
|
ACTUAL_MODEL="unknown"
|
|
155
219
|
GITHUB_PR_URL=""
|
|
156
220
|
GITHUB_SKIP_REASONS=()
|
|
157
|
-
VALIDATION_TIMINGS_FILE="/
|
|
158
|
-
PRE_VALIDATION_TIMINGS_FILE="/
|
|
159
|
-
STAGE_TIMINGS_FILE="/
|
|
160
|
-
DEPENDENCY_CACHE_LOG="/
|
|
221
|
+
VALIDATION_TIMINGS_FILE="${KASEKI_RESULTS_DIR}/validation-timings.tsv"
|
|
222
|
+
PRE_VALIDATION_TIMINGS_FILE="${KASEKI_RESULTS_DIR}/pre-validation-timings.tsv"
|
|
223
|
+
STAGE_TIMINGS_FILE="${KASEKI_RESULTS_DIR}/stage-timings.tsv"
|
|
224
|
+
DEPENDENCY_CACHE_LOG="${KASEKI_RESULTS_DIR}/dependency-cache.log"
|
|
161
225
|
RAW_EVENTS="/tmp/pi-events.raw.jsonl"
|
|
162
226
|
SCOUTING_RAW_EVENTS="/tmp/pi-scouting-events.raw.jsonl"
|
|
163
227
|
GOAL_SETTING_RAW_EVENTS="/tmp/pi-goal-setting-events.raw.jsonl"
|
|
164
228
|
GOAL_CHECK_RAW_EVENTS="/tmp/pi-goal-check-events.raw.jsonl"
|
|
165
229
|
RUN_EVALUATION_RAW_EVENTS="/tmp/pi-run-evaluation-events.raw.jsonl"
|
|
166
|
-
SCOUTING_ARTIFACT="/
|
|
167
|
-
SCOUTING_CANDIDATE_ARTIFACT="/
|
|
168
|
-
GOAL_SETTING_ARTIFACT="/
|
|
169
|
-
GOAL_SETTING_CANDIDATE_ARTIFACT="/
|
|
170
|
-
GOAL_CHECK_CANDIDATE_ARTIFACT="/
|
|
171
|
-
RUN_EVALUATION_ARTIFACT="/
|
|
172
|
-
RUN_EVALUATION_CANDIDATE_ARTIFACT="/
|
|
173
|
-
TEST_IMPACT_WARNINGS_ARTIFACT="/
|
|
174
|
-
EXPECTATION_MISMATCH_WARNINGS_ARTIFACT="/
|
|
175
|
-
KASEKI_DEPENDENCY_CACHE_DIR="${KASEKI_DEPENDENCY_CACHE_DIR
|
|
230
|
+
SCOUTING_ARTIFACT="${KASEKI_RESULTS_DIR}/scouting.json"
|
|
231
|
+
SCOUTING_CANDIDATE_ARTIFACT="${KASEKI_RESULTS_DIR}/scouting-candidate.json"
|
|
232
|
+
GOAL_SETTING_ARTIFACT="${KASEKI_RESULTS_DIR}/goal-setting.json"
|
|
233
|
+
GOAL_SETTING_CANDIDATE_ARTIFACT="${KASEKI_RESULTS_DIR}/goal-setting-candidate.json"
|
|
234
|
+
GOAL_CHECK_CANDIDATE_ARTIFACT="${KASEKI_RESULTS_DIR}/goal-check-candidate.json"
|
|
235
|
+
RUN_EVALUATION_ARTIFACT="${KASEKI_RESULTS_DIR}/run-evaluation.json"
|
|
236
|
+
RUN_EVALUATION_CANDIDATE_ARTIFACT="${KASEKI_RESULTS_DIR}/run-evaluation-candidate.json"
|
|
237
|
+
TEST_IMPACT_WARNINGS_ARTIFACT="${KASEKI_RESULTS_DIR}/test-impact-warnings.log"
|
|
238
|
+
EXPECTATION_MISMATCH_WARNINGS_ARTIFACT="${KASEKI_RESULTS_DIR}/expectation-mismatch-warnings.jsonl"
|
|
239
|
+
KASEKI_DEPENDENCY_CACHE_DIR="${KASEKI_DEPENDENCY_CACHE_DIR:-${KASEKI_WORKSPACE_DIR}/.kaseki-cache}"
|
|
176
240
|
KASEKI_DEPENDENCY_RESTORE_MODE="${KASEKI_DEPENDENCY_RESTORE_MODE:-auto}"
|
|
177
241
|
KASEKI_DEPENDENCY_CACHE_MAX_BYTES="${KASEKI_DEPENDENCY_CACHE_MAX_BYTES:-5368709120}"
|
|
178
242
|
KASEKI_DEPENDENCY_CACHE_MAX_AGE_DAYS="${KASEKI_DEPENDENCY_CACHE_MAX_AGE_DAYS:-30}"
|
|
@@ -184,7 +248,7 @@ KASEKI_IMAGE_DEPENDENCY_CACHE_DIR="${KASEKI_IMAGE_DEPENDENCY_CACHE_DIR:-/opt/kas
|
|
|
184
248
|
KASEKI_LOG_DIR="${KASEKI_LOG_DIR:-/var/log/kaseki}"
|
|
185
249
|
KASEKI_STRICT_HOST_LOGGING="${KASEKI_STRICT_HOST_LOGGING:-0}"
|
|
186
250
|
KASEKI_GIT_CACHE_MODE="${KASEKI_GIT_CACHE_MODE:-mirror}"
|
|
187
|
-
KASEKI_GIT_CACHE_ROOT="${KASEKI_GIT_CACHE_ROOT
|
|
251
|
+
KASEKI_GIT_CACHE_ROOT="${KASEKI_GIT_CACHE_ROOT:-${KASEKI_CACHE_DIR}/git}"
|
|
188
252
|
KASEKI_GIT_CACHE_FETCH_TIMEOUT_SECONDS="${KASEKI_GIT_CACHE_FETCH_TIMEOUT_SECONDS:-120}"
|
|
189
253
|
GIT_CACHE_KEY=""
|
|
190
254
|
GIT_CACHE_MIRROR=""
|
|
@@ -201,12 +265,12 @@ REPO_MEMORY_COMMIT_SHA="unknown"
|
|
|
201
265
|
|
|
202
266
|
# Track last executed command for better error reporting
|
|
203
267
|
LAST_COMMAND=""
|
|
204
|
-
LAST_COMMAND_LOG="/
|
|
268
|
+
LAST_COMMAND_LOG="${KASEKI_RESULTS_DIR}/last-command.log"
|
|
205
269
|
|
|
206
270
|
# Signal handler for graceful termination
|
|
207
271
|
handle_termination() {
|
|
208
272
|
local signal="$1"
|
|
209
|
-
printf '\nReceived %s; terminating kaseki-agent...\n' "$signal" | tee -a /
|
|
273
|
+
printf '\nReceived %s; terminating kaseki-agent...\n' "$signal" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
210
274
|
# Exit with standard code for signal (128 + signal_number)
|
|
211
275
|
# SIGINT = 130, SIGTERM = 143
|
|
212
276
|
if [ "$signal" = "SIGINT" ]; then
|
|
@@ -243,8 +307,8 @@ setup_host_logging_mirror() {
|
|
|
243
307
|
if mkdir -p "$KASEKI_LOG_DIR" 2>/dev/null && [ -w "$KASEKI_LOG_DIR" ]; then
|
|
244
308
|
stamp="$(date -u +%Y%m%dT%H%M%SZ)"
|
|
245
309
|
host_log_file="$KASEKI_LOG_DIR/${base_name}-${stamp}.log"
|
|
246
|
-
exec > >(tee -a /
|
|
247
|
-
2> >(tee -a /
|
|
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)
|
|
248
312
|
printf 'Host log mirror: %s\n' "$host_log_file"
|
|
249
313
|
return 0
|
|
250
314
|
fi
|
|
@@ -252,11 +316,11 @@ setup_host_logging_mirror() {
|
|
|
252
316
|
printf 'Error: strict host logging enabled, but KASEKI_LOG_DIR is not writable: %s\n' "$KASEKI_LOG_DIR" >&2
|
|
253
317
|
exit 1
|
|
254
318
|
fi
|
|
255
|
-
exec > >(tee -a /
|
|
319
|
+
exec > >(tee -a ${KASEKI_RESULTS_DIR}/stdout.log) 2> >(tee -a ${KASEKI_RESULTS_DIR}/stderr.log >&2)
|
|
256
320
|
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
|
|
257
321
|
}
|
|
258
322
|
|
|
259
|
-
mkdir_paths=(
|
|
323
|
+
mkdir_paths=("${KASEKI_RESULTS_DIR}")
|
|
260
324
|
if [ -n "${HOME:-}" ]; then
|
|
261
325
|
mkdir_paths+=("${HOME}")
|
|
262
326
|
fi
|
|
@@ -273,41 +337,41 @@ if ! mkdir -p "${mkdir_paths[@]}"; then
|
|
|
273
337
|
printf 'Error: Failed to create required runtime directories.\n' >&2
|
|
274
338
|
exit 1
|
|
275
339
|
fi
|
|
276
|
-
: > /
|
|
277
|
-
: > /
|
|
278
|
-
: > /
|
|
279
|
-
: > /
|
|
280
|
-
: > /
|
|
281
|
-
: > /
|
|
282
|
-
: > /
|
|
283
|
-
: > /
|
|
284
|
-
: > /
|
|
285
|
-
: > /
|
|
286
|
-
: > /
|
|
287
|
-
: > /
|
|
288
|
-
: > /
|
|
289
|
-
: > /
|
|
290
|
-
: > /
|
|
291
|
-
: > /
|
|
292
|
-
: > /
|
|
293
|
-
: > /
|
|
294
|
-
: > /
|
|
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
|
|
295
359
|
: > "$TEST_IMPACT_WARNINGS_ARTIFACT"
|
|
296
360
|
: > "$EXPECTATION_MISMATCH_WARNINGS_ARTIFACT"
|
|
297
|
-
: > /
|
|
298
|
-
: > /
|
|
361
|
+
: > ${KASEKI_RESULTS_DIR}/validation.log
|
|
362
|
+
: > ${KASEKI_RESULTS_DIR}/pre-validation.log
|
|
299
363
|
: > "$PRE_VALIDATION_RAW_LOG"
|
|
300
364
|
: > "$PRE_VALIDATION_ENV_LOG"
|
|
301
365
|
: > "$AUTO_LINT_CLEANUP_LOG"
|
|
302
366
|
: > "$AUTO_LINT_CLEANUP_TIMINGS_FILE"
|
|
303
|
-
: > /
|
|
304
|
-
: > /
|
|
305
|
-
: > /
|
|
306
|
-
: > /
|
|
307
|
-
: > /
|
|
308
|
-
: > /
|
|
309
|
-
: > /
|
|
310
|
-
: > /
|
|
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
|
|
311
375
|
: > "$VALIDATION_TIMINGS_FILE"
|
|
312
376
|
: > "$PRE_VALIDATION_TIMINGS_FILE"
|
|
313
377
|
: >> "$STAGE_TIMINGS_FILE"
|
|
@@ -474,9 +538,9 @@ validate_scouting_artifact_with_node() {
|
|
|
474
538
|
"$candidate_artifact" \
|
|
475
539
|
"$final_artifact" \
|
|
476
540
|
"$validation_error_file" \
|
|
477
|
-
"/
|
|
541
|
+
"${KASEKI_RESULTS_DIR}/scouting-validation-errors.jsonl" \
|
|
478
542
|
>/dev/null \
|
|
479
|
-
2>> /
|
|
543
|
+
2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
480
544
|
}
|
|
481
545
|
|
|
482
546
|
# Validate scouting artifact and emit structured reason code
|
|
@@ -490,7 +554,7 @@ validate_scouting_artifact() {
|
|
|
490
554
|
|
|
491
555
|
: > "$validation_error_file"
|
|
492
556
|
if [ ! -f "$candidate_artifact" ]; then
|
|
493
|
-
if [ -f /
|
|
557
|
+
if [ -f ${KASEKI_RESULTS_DIR}/filesystem-readonly-reason.txt ]; then
|
|
494
558
|
reason_code="readonly_filesystem"
|
|
495
559
|
reason_details="1 critical scouting validation error: scouting-candidate.json missing due to read-only filesystem"
|
|
496
560
|
else
|
|
@@ -498,15 +562,15 @@ validate_scouting_artifact() {
|
|
|
498
562
|
reason_details="1 critical scouting validation error: scouting-candidate.json"
|
|
499
563
|
fi
|
|
500
564
|
# shellcheck disable=SC2016
|
|
501
|
-
node -e 'const fs=require("node:fs"); const candidate=process.argv[1]; const reason=process.argv[2]; const error={timestamp:new Date().toISOString(),reason_code:reason,field:"scouting-candidate.json",expected:"file at /
|
|
565
|
+
node -e 'const fs=require("node:fs"); const candidate=process.argv[1]; const reason=process.argv[2]; const error={timestamp:new Date().toISOString(),reason_code:reason,field:"scouting-candidate.json",expected:"file at " + process.env.KASEKI_RESULTS_DIR + "/scouting-candidate.json",actual:`missing: ${candidate}`,severity:"critical",suggestion:reason==="readonly_filesystem" ? "remount " + process.env.KASEKI_RESULTS_DIR + " as read-write (docker run -v /path:" + process.env.KASEKI_RESULTS_DIR + ":rw)" : "ensure the scouting Pi writes exactly one valid JSON object to " + process.env.KASEKI_RESULTS_DIR + "/scouting-candidate.json"}; fs.appendFileSync(process.env.KASEKI_RESULTS_DIR + "/scouting-validation-errors.jsonl", JSON.stringify(error)+"\n");' "$candidate_artifact" "$reason_code" 2>> "${KASEKI_RESULTS_DIR}/scouting-stderr.log" || true
|
|
502
566
|
elif ! validate_scouting_artifact_with_node "$candidate_artifact" "$final_artifact" "$validation_error_file"; then
|
|
503
567
|
reason_code="$(node -e 'try{const v=JSON.parse(require("node:fs").readFileSync(process.argv[1],"utf8")); process.stdout.write(String(v.reason_code||"schema_mismatch"));}catch{process.stdout.write("schema_mismatch");}' "$validation_error_file" 2>/dev/null || printf 'schema_mismatch')"
|
|
504
568
|
reason_details="$(node -e 'try{const v=JSON.parse(require("node:fs").readFileSync(process.argv[1],"utf8")); process.stdout.write(String(v.details||"scouting artifact validation failed"));}catch{process.stdout.write("scouting artifact validation failed");}' "$validation_error_file" 2>/dev/null || printf 'scouting artifact validation failed')"
|
|
505
569
|
fi
|
|
506
570
|
|
|
507
571
|
printf '%s\n' "$reason_code" > "$reason_file"
|
|
508
|
-
printf '%s\n' "$reason_details" > /
|
|
509
|
-
printf '[scouting-validation] reason=%s details=%s\n' "$reason_code" "$reason_details" | tee -a /
|
|
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
|
|
510
574
|
rm -f "$validation_error_file" 2>/dev/null || true
|
|
511
575
|
[ "$reason_code" = "valid" ]
|
|
512
576
|
}
|
|
@@ -521,12 +585,14 @@ validate_goal_check_artifact_with_node() {
|
|
|
521
585
|
# shellcheck disable=SC2016
|
|
522
586
|
node -e '
|
|
523
587
|
const fs = require("node:fs");
|
|
588
|
+
const path = require("node:path");
|
|
524
589
|
const input = process.argv[1];
|
|
525
590
|
const output = process.argv[2];
|
|
526
591
|
const attempt = Number(process.argv[3]);
|
|
527
592
|
const errorLog = process.argv[4];
|
|
528
|
-
const
|
|
529
|
-
const
|
|
593
|
+
const resultsDir = process.env.KASEKI_RESULTS_DIR || "/results";
|
|
594
|
+
const jsonlLog = path.join(resultsDir, "goal-check-validation-errors.jsonl");
|
|
595
|
+
const attemptsLog = path.join(resultsDir, "goal-check-attempts.jsonl");
|
|
530
596
|
|
|
531
597
|
function actualType(value) {
|
|
532
598
|
if (value === null) return "null";
|
|
@@ -535,11 +601,16 @@ function actualType(value) {
|
|
|
535
601
|
}
|
|
536
602
|
|
|
537
603
|
function appendValidationFailure(error) {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
604
|
+
try {
|
|
605
|
+
fs.mkdirSync(path.dirname(jsonlLog), { recursive: true });
|
|
606
|
+
fs.appendFileSync(jsonlLog, JSON.stringify({
|
|
607
|
+
timestamp: new Date().toISOString(),
|
|
608
|
+
attempt,
|
|
609
|
+
...error,
|
|
610
|
+
}) + "\n");
|
|
611
|
+
} catch (e) {
|
|
612
|
+
// Non-blocking log failure
|
|
613
|
+
}
|
|
543
614
|
}
|
|
544
615
|
|
|
545
616
|
function summarize(errors) {
|
|
@@ -572,7 +643,7 @@ try {
|
|
|
572
643
|
expected: "valid JSON object",
|
|
573
644
|
actual: error && error.message ? String(error.message) : String(error),
|
|
574
645
|
severity: "critical",
|
|
575
|
-
suggestion: "ensure exactly one valid JSON object is written to /
|
|
646
|
+
suggestion: "ensure exactly one valid JSON object is written to ${KASEKI_RESULTS_DIR}/goal-check-candidate.json",
|
|
576
647
|
}]);
|
|
577
648
|
}
|
|
578
649
|
|
|
@@ -625,8 +696,13 @@ if (errors.length) {
|
|
|
625
696
|
artifact.attempt = attempt;
|
|
626
697
|
artifact.timestamp = new Date().toISOString();
|
|
627
698
|
fs.writeFileSync(output, JSON.stringify(artifact, null, 2) + "\n");
|
|
628
|
-
|
|
629
|
-
|
|
699
|
+
try {
|
|
700
|
+
fs.mkdirSync(path.dirname(attemptsLog), { recursive: true });
|
|
701
|
+
fs.appendFileSync(attemptsLog, JSON.stringify(artifact) + "\n");
|
|
702
|
+
} catch (e) {
|
|
703
|
+
// Non-blocking log failure
|
|
704
|
+
}
|
|
705
|
+
' "$candidate_artifact" "$final_artifact" "$attempt" "$validation_error_file" 2>> "${KASEKI_RESULTS_DIR}/goal-check-stderr.log"
|
|
630
706
|
}
|
|
631
707
|
|
|
632
708
|
validate_goal_check_artifact() {
|
|
@@ -634,7 +710,7 @@ validate_goal_check_artifact() {
|
|
|
634
710
|
local final_artifact="$2"
|
|
635
711
|
local attempt="$3"
|
|
636
712
|
local reason_file="$4"
|
|
637
|
-
local summary_file="${5
|
|
713
|
+
local summary_file="${5:-${KASEKI_RESULTS_DIR}/goal-check-validation-summary.txt}"
|
|
638
714
|
local validation_error_file="/tmp/goal-check-validation-errors.json"
|
|
639
715
|
local reason_code="valid"
|
|
640
716
|
local reason_details="artifact validation passed"
|
|
@@ -644,7 +720,7 @@ validate_goal_check_artifact() {
|
|
|
644
720
|
reason_code="missing_file"
|
|
645
721
|
reason_details="1 critical goal-check validation error: goal-check-candidate.json"
|
|
646
722
|
# shellcheck disable=SC2016
|
|
647
|
-
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 /
|
|
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
|
|
648
724
|
elif ! validate_goal_check_artifact_with_node "$candidate_artifact" "$final_artifact" "$attempt" "$validation_error_file"; then
|
|
649
725
|
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')"
|
|
650
726
|
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')"
|
|
@@ -652,7 +728,7 @@ validate_goal_check_artifact() {
|
|
|
652
728
|
|
|
653
729
|
printf '%s\n' "$reason_code" > "$reason_file"
|
|
654
730
|
printf '%s\n' "$reason_details" > "$summary_file"
|
|
655
|
-
printf '[goal-check-validation] reason=%s details=%s\n' "$reason_code" "$reason_details" | tee -a /
|
|
731
|
+
printf '[goal-check-validation] reason=%s details=%s\n' "$reason_code" "$reason_details" | tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log
|
|
656
732
|
rm -f "$validation_error_file" 2>/dev/null || true
|
|
657
733
|
[ "$reason_code" = "valid" ]
|
|
658
734
|
}
|
|
@@ -661,20 +737,20 @@ emit_progress() {
|
|
|
661
737
|
local stage="$1"
|
|
662
738
|
local detail="$2"
|
|
663
739
|
local status="${3:-info}"
|
|
664
|
-
append_jsonl_object /
|
|
740
|
+
append_jsonl_object ${KASEKI_RESULTS_DIR}/progress.jsonl \
|
|
665
741
|
"timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
666
742
|
"component=kaseki-agent" \
|
|
667
743
|
"stage=$stage" \
|
|
668
744
|
"status=$status" \
|
|
669
745
|
"instance=$INSTANCE_NAME" \
|
|
670
746
|
"detail=$detail"
|
|
671
|
-
printf '[progress] %s %s: %s\n' "$stage" "$status" "$detail" | tee -a /
|
|
747
|
+
printf '[progress] %s %s: %s\n' "$stage" "$status" "$detail" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
672
748
|
}
|
|
673
749
|
|
|
674
750
|
emit_event() {
|
|
675
751
|
local event_type="$1"
|
|
676
752
|
shift
|
|
677
|
-
append_jsonl_object /
|
|
753
|
+
append_jsonl_object ${KASEKI_RESULTS_DIR}/progress.jsonl \
|
|
678
754
|
"timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
679
755
|
"component=kaseki-agent" \
|
|
680
756
|
"event_type=$event_type" \
|
|
@@ -687,7 +763,7 @@ emit_error_event() {
|
|
|
687
763
|
local detail="$2"
|
|
688
764
|
local recovery="${3:-continue}"
|
|
689
765
|
emit_event "error" "error_type=$error_type" "detail=$detail" "recovery_action=$recovery"
|
|
690
|
-
printf '[error] %s: %s (recovery: %s)\n' "$error_type" "$detail" "$recovery" | tee -a /
|
|
766
|
+
printf '[error] %s: %s (recovery: %s)\n' "$error_type" "$detail" "$recovery" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
691
767
|
}
|
|
692
768
|
|
|
693
769
|
write_metadata() {
|
|
@@ -705,7 +781,7 @@ write_metadata() {
|
|
|
705
781
|
stages_json="[\"unknown\"]"
|
|
706
782
|
fi
|
|
707
783
|
|
|
708
|
-
cat > /
|
|
784
|
+
cat > ${KASEKI_RESULTS_DIR}/metadata.json <<META
|
|
709
785
|
{
|
|
710
786
|
"instance": $(printf '%s' "$INSTANCE_NAME" | json_encode),
|
|
711
787
|
"repo_url": $(printf '%s' "$REPO_URL" | json_encode),
|
|
@@ -826,7 +902,7 @@ write_metadata() {
|
|
|
826
902
|
"stages": $stages_json
|
|
827
903
|
}
|
|
828
904
|
META
|
|
829
|
-
printf '%s\n' "$exit_code" > /
|
|
905
|
+
printf '%s\n' "$exit_code" > ${KASEKI_RESULTS_DIR}/exit_code
|
|
830
906
|
}
|
|
831
907
|
|
|
832
908
|
set_current_stage() {
|
|
@@ -881,7 +957,7 @@ build_stages_array() {
|
|
|
881
957
|
|
|
882
958
|
write_result_summary() {
|
|
883
959
|
local changed_files changed_files_markdown validation_status pr_status github_skip_reasons_summary goal_check_status
|
|
884
|
-
changed_files="$(cat /
|
|
960
|
+
changed_files="$(cat ${KASEKI_RESULTS_DIR}/changed-files.txt 2>/dev/null || true)"
|
|
885
961
|
if [ -n "$changed_files" ]; then
|
|
886
962
|
changed_files_markdown="$(printf '%s\n' "$changed_files" | sed 's/^/ - /')"
|
|
887
963
|
else
|
|
@@ -934,7 +1010,7 @@ write_result_summary() {
|
|
|
934
1010
|
goal_check_status="not reached"
|
|
935
1011
|
fi
|
|
936
1012
|
|
|
937
|
-
cat > /
|
|
1013
|
+
cat > ${KASEKI_RESULTS_DIR}/result-summary.md <<SUMMARY
|
|
938
1014
|
# Kaseki Result: $INSTANCE_NAME
|
|
939
1015
|
|
|
940
1016
|
- Status: $(if [ "$STATUS" -eq 0 ]; then printf 'passed'; else printf 'failed'; fi)
|
|
@@ -959,7 +1035,7 @@ $(if [ -n "$VALIDATION_ALLOWLIST_FAILURE_REASON" ]; then printf ' - Allowlist r
|
|
|
959
1035
|
$(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)
|
|
960
1036
|
- Test failure analysis: $TEST_FAILURE_CLASSIFICATION_STATUS
|
|
961
1037
|
$(if [ "$TEST_FAILURE_CLASSIFICATION_STATUS" = "completed" ] && [ "$NEWLY_INTRODUCED_FAILURES_COUNT" -gt 0 ]; then printf ' - ⚠️ **Newly introduced failures: %d**\n' "$NEWLY_INTRODUCED_FAILURES_COUNT"; fi)
|
|
962
|
-
$(if [ "$TEST_FAILURE_CLASSIFICATION_STATUS" = "completed" ] && [ -f /
|
|
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)
|
|
963
1039
|
- Quality checks: $QUALITY_EXIT
|
|
964
1040
|
- Secret scan: $SECRET_SCAN_EXIT
|
|
965
1041
|
- GitHub PR: $pr_status
|
|
@@ -1001,12 +1077,12 @@ SUMMARY
|
|
|
1001
1077
|
write_failure_json() {
|
|
1002
1078
|
local exit_code="$1"
|
|
1003
1079
|
local stderr_tail
|
|
1004
|
-
stderr_tail="$(tail -20 /
|
|
1080
|
+
stderr_tail="$(tail -20 ${KASEKI_RESULTS_DIR}/stderr.log 2>/dev/null || true)"
|
|
1005
1081
|
if [ "$exit_code" -eq 0 ]; then
|
|
1006
|
-
: > /
|
|
1082
|
+
: > ${KASEKI_RESULTS_DIR}/failure.json
|
|
1007
1083
|
return 0
|
|
1008
1084
|
fi
|
|
1009
|
-
cat > /
|
|
1085
|
+
cat > ${KASEKI_RESULTS_DIR}/failure.json <<FAILURE
|
|
1010
1086
|
{
|
|
1011
1087
|
"instance": $(printf '%s' "$INSTANCE_NAME" | json_encode),
|
|
1012
1088
|
"exit_code": $exit_code,
|
|
@@ -1024,7 +1100,7 @@ write_failure_json() {
|
|
|
1024
1100
|
"goal_check_met": $GOAL_CHECK_MET,
|
|
1025
1101
|
"stage": $(printf '%s' "$CURRENT_STAGE" | json_encode),
|
|
1026
1102
|
"stderr_tail": $(printf '%s' "$stderr_tail" | json_encode),
|
|
1027
|
-
"artifacts_dir": "
|
|
1103
|
+
"artifacts_dir": "${KASEKI_RESULTS_DIR}",
|
|
1028
1104
|
"metadata": "metadata.json",
|
|
1029
1105
|
"stderr": "stderr.log",
|
|
1030
1106
|
"stdout": "stdout.log",
|
|
@@ -1036,28 +1112,28 @@ FAILURE
|
|
|
1036
1112
|
|
|
1037
1113
|
collect_git_artifacts() {
|
|
1038
1114
|
DIFF_NONEMPTY=false
|
|
1039
|
-
if [ -d /
|
|
1115
|
+
if [ -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
1040
1116
|
while IFS= read -r untracked_file || [ -n "$untracked_file" ]; do
|
|
1041
1117
|
[ -z "$untracked_file" ] && continue
|
|
1042
|
-
git -C /
|
|
1043
|
-
done < <(git -C /
|
|
1044
|
-
git -C /
|
|
1045
|
-
git -C /
|
|
1046
|
-
git -C /
|
|
1047
|
-
if [ -s /
|
|
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
|
|
1048
1124
|
DIFF_NONEMPTY=true
|
|
1049
1125
|
fi
|
|
1050
1126
|
else
|
|
1051
|
-
: > /
|
|
1052
|
-
: > /
|
|
1053
|
-
: > /
|
|
1127
|
+
: > ${KASEKI_RESULTS_DIR}/git.status
|
|
1128
|
+
: > ${KASEKI_RESULTS_DIR}/git.diff
|
|
1129
|
+
: > ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
1054
1130
|
fi
|
|
1055
1131
|
}
|
|
1056
1132
|
|
|
1057
1133
|
run_static_test_impact_check() {
|
|
1058
|
-
local changed_files_file="/
|
|
1059
|
-
local diff_file="/
|
|
1060
|
-
local artifact="${TEST_IMPACT_WARNINGS_ARTIFACT
|
|
1134
|
+
local changed_files_file="${KASEKI_RESULTS_DIR}/changed-files.txt"
|
|
1135
|
+
local diff_file="${KASEKI_RESULTS_DIR}/git.diff"
|
|
1136
|
+
local artifact="${TEST_IMPACT_WARNINGS_ARTIFACT:-${KASEKI_RESULTS_DIR}/test-impact-warnings.log}"
|
|
1061
1137
|
local indicator_regex='(parse|parser|regex|regexp|stage|event|format|serialize|name)'
|
|
1062
1138
|
local production_matches diff_matches warning_detail
|
|
1063
1139
|
|
|
@@ -1099,7 +1175,7 @@ run_static_test_impact_check() {
|
|
|
1099
1175
|
"warning_type=test_impact_without_tests" \
|
|
1100
1176
|
"artifact=$artifact" \
|
|
1101
1177
|
"detail=$warning_detail"
|
|
1102
|
-
printf '[warning] test-impact: %s (artifact: %s)\n' "$warning_detail" "$artifact" | tee -a /
|
|
1178
|
+
printf '[warning] test-impact: %s (artifact: %s)\n' "$warning_detail" "$artifact" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
1103
1179
|
return 0
|
|
1104
1180
|
}
|
|
1105
1181
|
|
|
@@ -1112,21 +1188,21 @@ run_expectation_mismatch_detector() {
|
|
|
1112
1188
|
fi
|
|
1113
1189
|
|
|
1114
1190
|
: > "$EXPECTATION_MISMATCH_WARNINGS_ARTIFACT"
|
|
1115
|
-
if [ ! -s /
|
|
1116
|
-
printf '[expectation-mismatch] skipped: /
|
|
1191
|
+
if [ ! -s ${KASEKI_RESULTS_DIR}/git.diff ]; then
|
|
1192
|
+
printf '[expectation-mismatch] skipped: ${KASEKI_RESULTS_DIR}/git.diff is empty\n' >> ${KASEKI_RESULTS_DIR}/progress.log
|
|
1117
1193
|
return 0
|
|
1118
1194
|
fi
|
|
1119
1195
|
if [ ! -f "$detector_script" ]; then
|
|
1120
|
-
printf '[expectation-mismatch] skipped: detector script not found (%s)\n' "$detector_script" | tee -a /
|
|
1196
|
+
printf '[expectation-mismatch] skipped: detector script not found (%s)\n' "$detector_script" | tee -a ${KASEKI_RESULTS_DIR}/progress.log
|
|
1121
1197
|
return 0
|
|
1122
1198
|
fi
|
|
1123
1199
|
|
|
1124
1200
|
if ! node "$detector_script" \
|
|
1125
|
-
--repo /
|
|
1126
|
-
--diff /
|
|
1201
|
+
--repo ${KASEKI_WORKSPACE_DIR}/repo \
|
|
1202
|
+
--diff ${KASEKI_RESULTS_DIR}/git.diff \
|
|
1127
1203
|
--output "$EXPECTATION_MISMATCH_WARNINGS_ARTIFACT" \
|
|
1128
|
-
--progress /
|
|
1129
|
-
printf '[expectation-mismatch] warning: detector failed; continuing to validation\n' | tee -a /
|
|
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
|
|
1130
1206
|
fi
|
|
1131
1207
|
}
|
|
1132
1208
|
|
|
@@ -1162,9 +1238,22 @@ if [ ! -r "$SCOUTING_ALLOWLIST_HELPER" ] && [ -r /app/scripts/scouting-allowlist
|
|
|
1162
1238
|
SCOUTING_ALLOWLIST_HELPER="/app/scripts/scouting-allowlist.js"
|
|
1163
1239
|
fi
|
|
1164
1240
|
# shellcheck source=scripts/allowlist-helper.sh
|
|
1165
|
-
. "$ALLOWLIST_HELPER"
|
|
1241
|
+
. "$ALLOWLIST_HELPER" || {
|
|
1242
|
+
printf 'ERROR: Failed to source %s (exit code: %d)\n' "$ALLOWLIST_HELPER" $? >&2
|
|
1243
|
+
exit 1
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
# Verify the helper was sourced successfully by checking for the required function
|
|
1247
|
+
if ! declare -f build_allowlist_regex >/dev/null 2>&1; then
|
|
1248
|
+
printf 'ERROR: build_allowlist_regex function not found after sourcing %s\n' "$ALLOWLIST_HELPER" >&2
|
|
1249
|
+
exit 1
|
|
1250
|
+
fi
|
|
1251
|
+
|
|
1166
1252
|
if [ "${KASEKI_AGENT_HELPER_RESOLUTION_CHECK:-0}" = "1" ]; then
|
|
1167
|
-
build_allowlist_regex "${KASEKI_CHANGED_FILES_ALLOWLIST:-}" >/dev/null
|
|
1253
|
+
build_allowlist_regex "${KASEKI_CHANGED_FILES_ALLOWLIST:-}" >/dev/null 2>&1 || {
|
|
1254
|
+
printf 'ERROR: build_allowlist_regex exited with status %d\n' $? >&2
|
|
1255
|
+
exit 1
|
|
1256
|
+
}
|
|
1168
1257
|
printf 'allowlist_helper=%s\n' "$ALLOWLIST_HELPER"
|
|
1169
1258
|
exit 0
|
|
1170
1259
|
fi
|
|
@@ -1224,7 +1313,7 @@ run_scouting_allowlist_coverage() {
|
|
|
1224
1313
|
local scouting_artifact agent_patterns validation_patterns
|
|
1225
1314
|
scouting_artifact="${1:?missing scouting artifact path}"
|
|
1226
1315
|
|
|
1227
|
-
if [ ! -f "$scouting_artifact" ] || [ ! -f /
|
|
1316
|
+
if [ ! -f "$scouting_artifact" ] || [ ! -f ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
1228
1317
|
return 0
|
|
1229
1318
|
fi
|
|
1230
1319
|
|
|
@@ -1239,7 +1328,7 @@ run_scouting_allowlist_coverage() {
|
|
|
1239
1328
|
validation_warnings=""
|
|
1240
1329
|
|
|
1241
1330
|
if [ -n "$agent_patterns" ] && command -v dry-run-allowlist.sh >/dev/null 2>&1; then
|
|
1242
|
-
agent_coverage="$(dry-run-allowlist.sh --result-dir
|
|
1331
|
+
agent_coverage="$(dry-run-allowlist.sh --result-dir ${KASEKI_RESULTS_DIR} --allowlist "$agent_patterns" 2>/dev/null | grep -oP '(?<=Coverage: )\d+(?=%)' | head -n 1 || true)"
|
|
1243
1332
|
[ -z "$agent_coverage" ] && agent_coverage="0"
|
|
1244
1333
|
|
|
1245
1334
|
# Check for problematic coverage
|
|
@@ -1251,7 +1340,7 @@ run_scouting_allowlist_coverage() {
|
|
|
1251
1340
|
fi
|
|
1252
1341
|
|
|
1253
1342
|
if [ -n "$validation_patterns" ] && command -v dry-run-allowlist.sh >/dev/null 2>&1; then
|
|
1254
|
-
validation_coverage="$(dry-run-allowlist.sh --result-dir
|
|
1343
|
+
validation_coverage="$(dry-run-allowlist.sh --result-dir ${KASEKI_RESULTS_DIR} --allowlist "$validation_patterns" 2>/dev/null | grep -oP '(?<=Coverage: )\d+(?=%)' | head -n 1 || true)"
|
|
1255
1344
|
[ -z "$validation_coverage" ] && validation_coverage="0"
|
|
1256
1345
|
|
|
1257
1346
|
if [ "$validation_coverage" -lt 30 ]; then
|
|
@@ -1285,12 +1374,12 @@ run_scouting_allowlist_coverage() {
|
|
|
1285
1374
|
if [ -n "$validation_warnings" ]; then
|
|
1286
1375
|
printf ' ⚠ validation_phase warning: %s\n' "$validation_warnings"
|
|
1287
1376
|
fi
|
|
1288
|
-
} | tee -a /
|
|
1377
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/scouting-report.md >> ${KASEKI_RESULTS_DIR}/quality.log
|
|
1289
1378
|
fi
|
|
1290
1379
|
}
|
|
1291
1380
|
|
|
1292
1381
|
restore_disallowed_changes() {
|
|
1293
|
-
if [ "$KASEKI_RESTORE_DISALLOWED_CHANGES" != "1" ] || [ ! -d /
|
|
1382
|
+
if [ "$KASEKI_RESTORE_DISALLOWED_CHANGES" != "1" ] || [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
1294
1383
|
return 0
|
|
1295
1384
|
fi
|
|
1296
1385
|
|
|
@@ -1303,7 +1392,7 @@ restore_disallowed_changes() {
|
|
|
1303
1392
|
coverage=0
|
|
1304
1393
|
|
|
1305
1394
|
# Initialize restoration tracking file
|
|
1306
|
-
: > /
|
|
1395
|
+
: > ${KASEKI_RESULTS_DIR}/restoration.jsonl
|
|
1307
1396
|
|
|
1308
1397
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
1309
1398
|
[ -z "$changed_file" ] && continue
|
|
@@ -1313,21 +1402,21 @@ restore_disallowed_changes() {
|
|
|
1313
1402
|
{
|
|
1314
1403
|
printf '{"timestamp":"%s","event":"file_evaluated","file":"%s","status":"kept","reason":"matched_allowlist"}\n' \
|
|
1315
1404
|
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$(printf '%s' "$changed_file" | sed 's/"/\\"/g')"
|
|
1316
|
-
} >> /
|
|
1405
|
+
} >> ${KASEKI_RESULTS_DIR}/restoration.jsonl
|
|
1317
1406
|
continue
|
|
1318
1407
|
fi
|
|
1319
1408
|
# File did not match allowlist - restore it
|
|
1320
1409
|
restored_count=$((restored_count + 1))
|
|
1321
|
-
printf -- 'Restoring changed file outside allowlist before validation: %s\n' "$changed_file" | tee -a /
|
|
1410
|
+
printf -- 'Restoring changed file outside allowlist before validation: %s\n' "$changed_file" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
1322
1411
|
emit_event "quality_gate_rule_evaluated" "rule=allowlist_restore" "passed=true" "file=$changed_file"
|
|
1323
1412
|
{
|
|
1324
1413
|
printf '{"timestamp":"%s","event":"file_restored","file":"%s","status":"restored","reason":"not_in_allowlist"}\n' \
|
|
1325
1414
|
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$(printf '%s' "$changed_file" | sed 's/"/\\"/g')"
|
|
1326
|
-
} >> /
|
|
1327
|
-
git -C /
|
|
1328
|
-
git -C /
|
|
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
|
|
1329
1418
|
restored_any=1
|
|
1330
|
-
done < /
|
|
1419
|
+
done < ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
1331
1420
|
|
|
1332
1421
|
# Emit restoration summary to quality.log with actionable guidance
|
|
1333
1422
|
if [ $((restored_count + kept_count)) -gt 0 ]; then
|
|
@@ -1338,12 +1427,12 @@ restore_disallowed_changes() {
|
|
|
1338
1427
|
printf '\n[allowlist summary] Restored: %d files; Kept: %d files (coverage: %d%%)\n' "$restored_count" "$kept_count" "$coverage"
|
|
1339
1428
|
if [ "$restored_count" -gt 0 ] && [ "$coverage" -lt 50 ]; then
|
|
1340
1429
|
printf '[allowlist note] Low coverage detected. To improve:\n'
|
|
1341
|
-
printf ' 1. Run: ./scripts/suggest-allowlist.sh
|
|
1430
|
+
printf ' 1. Run: ./scripts/suggest-allowlist.sh ${KASEKI_RESULTS_DIR} (or /agents/kaseki-results/<instance>)\n'
|
|
1342
1431
|
printf ' 2. Review suggested patterns in allowlist-suggestions.md\n'
|
|
1343
1432
|
printf ' 3. Update KASEKI_CHANGED_FILES_ALLOWLIST and re-run\n'
|
|
1344
1433
|
printf 'See docs/QUALITY_GATES.md for more guidance.\n'
|
|
1345
1434
|
fi
|
|
1346
|
-
} | tee -a /
|
|
1435
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
1347
1436
|
emit_event "allowlist_restoration_complete" "restored=$restored_count" "kept=$kept_count" "coverage=$coverage"
|
|
1348
1437
|
fi
|
|
1349
1438
|
|
|
@@ -1353,7 +1442,7 @@ restore_disallowed_changes() {
|
|
|
1353
1442
|
}
|
|
1354
1443
|
|
|
1355
1444
|
generate_restoration_report() {
|
|
1356
|
-
if [ ! -f /
|
|
1445
|
+
if [ ! -f ${KASEKI_RESULTS_DIR}/restoration.jsonl ]; then
|
|
1357
1446
|
printf '[debug] restoration report: skipping - restoration.jsonl not found\n' >&2
|
|
1358
1447
|
return 0
|
|
1359
1448
|
fi
|
|
@@ -1362,7 +1451,7 @@ generate_restoration_report() {
|
|
|
1362
1451
|
|
|
1363
1452
|
# Safely extract counts from restoration.jsonl with validation
|
|
1364
1453
|
printf '[debug] restoration report: extracting counts from restoration.jsonl\n' >&2
|
|
1365
|
-
restored_count=$(grep -c '"status":"restored"' /
|
|
1454
|
+
restored_count=$(grep -c '"status":"restored"' ${KASEKI_RESULTS_DIR}/restoration.jsonl 2>/dev/null || true)
|
|
1366
1455
|
restored_count=${restored_count:-0}
|
|
1367
1456
|
printf '[debug] restoration report: restored_count="%s"\n' "$restored_count" >&2
|
|
1368
1457
|
if ! validate_numeric "restored_count" "$restored_count"; then
|
|
@@ -1370,7 +1459,7 @@ generate_restoration_report() {
|
|
|
1370
1459
|
return 1
|
|
1371
1460
|
fi
|
|
1372
1461
|
|
|
1373
|
-
kept_count=$(grep -c '"status":"kept"' /
|
|
1462
|
+
kept_count=$(grep -c '"status":"kept"' ${KASEKI_RESULTS_DIR}/restoration.jsonl 2>/dev/null || true)
|
|
1374
1463
|
kept_count=${kept_count:-0}
|
|
1375
1464
|
printf '[debug] restoration report: kept_count="%s"\n' "$kept_count" >&2
|
|
1376
1465
|
if ! validate_numeric "kept_count" "$kept_count"; then
|
|
@@ -1408,12 +1497,12 @@ generate_restoration_report() {
|
|
|
1408
1497
|
if [ "$restored_count" -gt 0 ]; then
|
|
1409
1498
|
printf '## Restored Files\n\n'
|
|
1410
1499
|
printf 'These files were modified by the agent but restored because they fall outside the allowlist:\n\n'
|
|
1411
|
-
grep '"status":"restored"' /
|
|
1500
|
+
grep '"status":"restored"' ${KASEKI_RESULTS_DIR}/restoration.jsonl | \
|
|
1412
1501
|
sed "s/.*\"file\":\"\([^\"]*\)\".*/- \`\1\`/" | \
|
|
1413
|
-
sort | uniq >> /
|
|
1414
|
-
if [ -f /
|
|
1415
|
-
cat /
|
|
1416
|
-
rm -f /
|
|
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
|
|
1417
1506
|
fi
|
|
1418
1507
|
printf '\n'
|
|
1419
1508
|
fi
|
|
@@ -1421,12 +1510,12 @@ generate_restoration_report() {
|
|
|
1421
1510
|
if [ "$kept_count" -gt 0 ]; then
|
|
1422
1511
|
printf '## Kept Files (Allowlist Matches)\n\n'
|
|
1423
1512
|
printf 'These files were in the allowlist and were kept:\n\n'
|
|
1424
|
-
grep '"status":"kept"' /
|
|
1513
|
+
grep '"status":"kept"' ${KASEKI_RESULTS_DIR}/restoration.jsonl | \
|
|
1425
1514
|
sed "s/.*\"file\":\"\([^\"]*\)\".*/- \`\1\`/" | \
|
|
1426
|
-
sort | uniq >> /
|
|
1427
|
-
if [ -f /
|
|
1428
|
-
cat /
|
|
1429
|
-
rm -f /
|
|
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
|
|
1430
1519
|
fi
|
|
1431
1520
|
printf '\n'
|
|
1432
1521
|
fi
|
|
@@ -1444,14 +1533,14 @@ generate_restoration_report() {
|
|
|
1444
1533
|
printf 'KASEKI_CHANGED_FILES_ALLOWLIST="<your-pattern>" ./run-kaseki.sh\n'
|
|
1445
1534
|
printf '```\n\n'
|
|
1446
1535
|
printf "For help on allowlist patterns, see \`docs/QUALITY_GATES.md\`.\n"
|
|
1447
|
-
} > /
|
|
1536
|
+
} > ${KASEKI_RESULTS_DIR}/restoration-report.md
|
|
1448
1537
|
}
|
|
1449
1538
|
|
|
1450
1539
|
check_validation_allowlist() {
|
|
1451
1540
|
if [ -z "$KASEKI_VALIDATION_ALLOWLIST" ]; then
|
|
1452
1541
|
return 0
|
|
1453
1542
|
fi
|
|
1454
|
-
if [ ! -d /
|
|
1543
|
+
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
1455
1544
|
return 0
|
|
1456
1545
|
fi
|
|
1457
1546
|
|
|
@@ -1460,9 +1549,9 @@ check_validation_allowlist() {
|
|
|
1460
1549
|
allowlist_regex="$(build_allowlist_regex "$KASEKI_VALIDATION_ALLOWLIST")"
|
|
1461
1550
|
[ -z "$allowlist_regex" ] && return 0
|
|
1462
1551
|
validation_violation_count=0
|
|
1463
|
-
validation_before_state_file="/
|
|
1464
|
-
validation_after_state_file="/
|
|
1465
|
-
validation_changed_file="/
|
|
1552
|
+
validation_before_state_file="${KASEKI_RESULTS_DIR}/validation-before-state.txt"
|
|
1553
|
+
validation_after_state_file="${KASEKI_RESULTS_DIR}/validation-after-state.txt"
|
|
1554
|
+
validation_changed_file="${KASEKI_RESULTS_DIR}/validation-changed-files.txt"
|
|
1466
1555
|
: > "$validation_changed_file"
|
|
1467
1556
|
|
|
1468
1557
|
if [ -f "$validation_before_state_file" ] && [ -f "$validation_after_state_file" ]; then
|
|
@@ -1477,14 +1566,14 @@ check_validation_allowlist() {
|
|
|
1477
1566
|
}
|
|
1478
1567
|
}
|
|
1479
1568
|
' "$validation_before_state_file" "$validation_after_state_file" | LC_ALL=C sort -u > "$validation_changed_file"
|
|
1480
|
-
elif [ -f /
|
|
1481
|
-
cp /
|
|
1569
|
+
elif [ -f ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
1570
|
+
cp ${KASEKI_RESULTS_DIR}/changed-files.txt "$validation_changed_file"
|
|
1482
1571
|
fi
|
|
1483
1572
|
|
|
1484
1573
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
1485
1574
|
[ -z "$changed_file" ] && continue
|
|
1486
1575
|
if ! printf '%s\n' "$changed_file" | grep -Eq "^(${allowlist_regex})$"; then
|
|
1487
|
-
printf 'Validation-phase file outside allowlist: %s\n' "$changed_file" | tee -a /
|
|
1576
|
+
printf 'Validation-phase file outside allowlist: %s\n' "$changed_file" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
1488
1577
|
validation_violation_count=$((validation_violation_count + 1))
|
|
1489
1578
|
emit_event "quality_gate_rule_evaluated" "rule=validation_allowlist" "passed=false" "file=$changed_file"
|
|
1490
1579
|
else
|
|
@@ -1496,14 +1585,14 @@ check_validation_allowlist() {
|
|
|
1496
1585
|
QUALITY_EXIT=7
|
|
1497
1586
|
VALIDATION_ALLOWLIST_FAILURE_REASON="validation_allowlist_check: $validation_violation_count file(s) changed during validation outside KASEKI_VALIDATION_ALLOWLIST"
|
|
1498
1587
|
QUALITY_FAILURE_REASON="$VALIDATION_ALLOWLIST_FAILURE_REASON"
|
|
1499
|
-
printf '\n[validation-allowlist] %d file(s) modified during validation outside allowlist\n' "$validation_violation_count" | tee -a /
|
|
1588
|
+
printf '\n[validation-allowlist] %d file(s) modified during validation outside allowlist\n' "$validation_violation_count" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
1500
1589
|
return 1
|
|
1501
1590
|
fi
|
|
1502
1591
|
return 0
|
|
1503
1592
|
}
|
|
1504
1593
|
|
|
1505
1594
|
check_secret_scan_allowlist() {
|
|
1506
|
-
local allowlist_file="/
|
|
1595
|
+
local allowlist_file="${KASEKI_WORKSPACE_DIR}/repo/.kaseki-secret-allowlist"
|
|
1507
1596
|
|
|
1508
1597
|
# If no allowlist file exists, all matches are failures (real leaks)
|
|
1509
1598
|
if [ ! -f "$allowlist_file" ]; then
|
|
@@ -1516,7 +1605,7 @@ check_secret_scan_allowlist() {
|
|
|
1516
1605
|
|
|
1517
1606
|
# Read the log into a temp variable to avoid SC2094 (read-write in same pipeline)
|
|
1518
1607
|
local temp_log
|
|
1519
|
-
temp_log=$(cat /
|
|
1608
|
+
temp_log=$(cat ${KASEKI_RESULTS_DIR}/secret-scan.log)
|
|
1520
1609
|
|
|
1521
1610
|
while IFS= read -r match_line || [ -n "$match_line" ]; do
|
|
1522
1611
|
[ -z "$match_line" ] && continue
|
|
@@ -1530,8 +1619,8 @@ check_secret_scan_allowlist() {
|
|
|
1530
1619
|
|
|
1531
1620
|
[ -z "$pattern" ] && continue
|
|
1532
1621
|
|
|
1533
|
-
# Normalize file path: remove leading /
|
|
1534
|
-
file_path="${file_path
|
|
1622
|
+
# Normalize file path: remove leading ${KASEKI_WORKSPACE_DIR}/repo/, repo/, and ./ if present
|
|
1623
|
+
file_path="${file_path#${KASEKI_WORKSPACE_DIR}/repo/}"
|
|
1535
1624
|
file_path="${file_path#repo/}"
|
|
1536
1625
|
file_path="${file_path#./}"
|
|
1537
1626
|
|
|
@@ -1556,7 +1645,7 @@ check_secret_scan_allowlist() {
|
|
|
1556
1645
|
for match in "${secret_matches[@]}"; do
|
|
1557
1646
|
printf '%s\n' "$match"
|
|
1558
1647
|
done
|
|
1559
|
-
} > /
|
|
1648
|
+
} > ${KASEKI_RESULTS_DIR}/secret-scan.log
|
|
1560
1649
|
|
|
1561
1650
|
# Exit code 6 only if there are unallowlisted matches
|
|
1562
1651
|
if [ "$unallowlisted_count" -gt 0 ]; then
|
|
@@ -1590,9 +1679,9 @@ finish() {
|
|
|
1590
1679
|
printf '[unexpected-failure] Exit code: %d\n' "$code"
|
|
1591
1680
|
printf '[unexpected-failure] Last command: %s\n' "$LAST_COMMAND"
|
|
1592
1681
|
printf '[unexpected-failure] Current stage: %s\n' "$CURRENT_STAGE"
|
|
1593
|
-
if [ -f /
|
|
1682
|
+
if [ -f ${KASEKI_RESULTS_DIR}/progress.log ]; then
|
|
1594
1683
|
printf '[unexpected-failure] Last 5 progress entries:\n'
|
|
1595
|
-
tail -5 /
|
|
1684
|
+
tail -5 ${KASEKI_RESULTS_DIR}/progress.log | sed 's/^/ /'
|
|
1596
1685
|
fi
|
|
1597
1686
|
} | tee -a "$LAST_COMMAND_LOG" >&2
|
|
1598
1687
|
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"
|
|
@@ -1601,16 +1690,16 @@ finish() {
|
|
|
1601
1690
|
maybe_call_finish_helper collect_git_artifacts
|
|
1602
1691
|
|
|
1603
1692
|
# Analyze test failures and compare baseline vs. working results
|
|
1604
|
-
if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ] && [ -f /
|
|
1693
|
+
if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ] && [ -f ${KASEKI_RESULTS_DIR}/validation-baseline.log ] && [ -f ${KASEKI_RESULTS_DIR}/pre-validation.log ]; then
|
|
1605
1694
|
set_current_stage "test failure analysis"
|
|
1606
1695
|
if analyze_test_failures_baseline; then
|
|
1607
1696
|
TEST_FAILURE_CLASSIFICATION_STATUS="completed"
|
|
1608
1697
|
# Try to extract newly_introduced_failures_count from JSON output (if jq available)
|
|
1609
|
-
if [ -f /
|
|
1610
|
-
NEWLY_INTRODUCED_FAILURES_COUNT=$(jq -r '.summary.total_newly_introduced // 0' /
|
|
1611
|
-
elif [ -f /
|
|
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
|
|
1612
1701
|
# Fallback: try to extract with grep/sed if jq not available
|
|
1613
|
-
NEWLY_INTRODUCED_FAILURES_COUNT=$(grep -o '"total_newly_introduced": [0-9]*' /
|
|
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')
|
|
1614
1703
|
fi
|
|
1615
1704
|
else
|
|
1616
1705
|
TEST_FAILURE_CLASSIFICATION_STATUS="failed"
|
|
@@ -1624,8 +1713,8 @@ finish() {
|
|
|
1624
1713
|
fi
|
|
1625
1714
|
|
|
1626
1715
|
# Debug output for restoration report generation
|
|
1627
|
-
if [ -f /
|
|
1628
|
-
printf '[debug] restoration.jsonl exists (size=%d bytes)\n' "$(wc -c < /
|
|
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
|
|
1629
1718
|
else
|
|
1630
1719
|
printf '[debug] restoration.jsonl does not exist\n' >&2
|
|
1631
1720
|
fi
|
|
@@ -1643,12 +1732,12 @@ finish() {
|
|
|
1643
1732
|
|
|
1644
1733
|
# Calculate and record maturity score
|
|
1645
1734
|
if [ -x /app/scripts/kaseki-maturity-score.sh ]; then
|
|
1646
|
-
/app/scripts/kaseki-maturity-score.sh /
|
|
1735
|
+
/app/scripts/kaseki-maturity-score.sh ${KASEKI_WORKSPACE_DIR}/repo ${KASEKI_RESULTS_DIR}/maturity-score.json 2>/dev/null || true
|
|
1647
1736
|
fi
|
|
1648
1737
|
|
|
1649
1738
|
# Calculate and record performance metrics
|
|
1650
|
-
if [ -x /app/scripts/kaseki-performance-metrics.sh ] && [ -f /
|
|
1651
|
-
/app/scripts/kaseki-performance-metrics.sh /
|
|
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
|
|
1652
1741
|
fi
|
|
1653
1742
|
|
|
1654
1743
|
maybe_call_finish_helper write_result_summary
|
|
@@ -1656,7 +1745,7 @@ finish() {
|
|
|
1656
1745
|
# Generate inspect-report.md for inspect mode on success
|
|
1657
1746
|
if [ "$KASEKI_TASK_MODE" = "inspect" ] && [ "$STATUS" -eq 0 ]; then
|
|
1658
1747
|
if [ -x /app/scripts/generate-inspect-report.js ]; then
|
|
1659
|
-
node /app/scripts/generate-inspect-report.js
|
|
1748
|
+
node /app/scripts/generate-inspect-report.js ${KASEKI_RESULTS_DIR} 2>/dev/null || true
|
|
1660
1749
|
fi
|
|
1661
1750
|
fi
|
|
1662
1751
|
|
|
@@ -1701,7 +1790,7 @@ run_step_dry() {
|
|
|
1701
1790
|
printf '\n==> %s (DRY-RUN: simulated)\n' "$label"
|
|
1702
1791
|
emit_progress "$label" "started (dry-run)"
|
|
1703
1792
|
# Show what commands would be run without executing them
|
|
1704
|
-
printf '%s\n' "$@" >> /
|
|
1793
|
+
printf '%s\n' "$@" >> ${KASEKI_RESULTS_DIR}/validation.log
|
|
1705
1794
|
step_end="$(date +%s)"
|
|
1706
1795
|
emit_progress "$label" "finished (dry-run, simulated exit 0)"
|
|
1707
1796
|
record_stage_timing "$label" "0" "$((step_end - step_start))" "dry-run"
|
|
@@ -1736,9 +1825,9 @@ is_valid_git_mirror() {
|
|
|
1736
1825
|
}
|
|
1737
1826
|
|
|
1738
1827
|
run_direct_clone() {
|
|
1739
|
-
rm -rf /
|
|
1828
|
+
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1740
1829
|
GIT_CLONE_STRATEGY="direct_shallow"
|
|
1741
|
-
git clone --depth 1 --branch "$GIT_REF" "$REPO_URL" /
|
|
1830
|
+
git clone --depth 1 --branch "$GIT_REF" "$REPO_URL" ${KASEKI_WORKSPACE_DIR}/repo
|
|
1742
1831
|
}
|
|
1743
1832
|
|
|
1744
1833
|
clone_with_git_cache() {
|
|
@@ -1815,25 +1904,25 @@ clone_with_git_cache() {
|
|
|
1815
1904
|
fi
|
|
1816
1905
|
flock -u 9 || true
|
|
1817
1906
|
|
|
1818
|
-
rm -rf /
|
|
1907
|
+
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1819
1908
|
GIT_CLONE_STRATEGY="reference_shallow"
|
|
1820
|
-
git clone --reference-if-able "$mirror" --depth 1 --branch "$GIT_REF" "$REPO_URL" /
|
|
1909
|
+
git clone --reference-if-able "$mirror" --depth 1 --branch "$GIT_REF" "$REPO_URL" ${KASEKI_WORKSPACE_DIR}/repo
|
|
1821
1910
|
clone_rc=$?
|
|
1822
1911
|
if [ "$clone_rc" -eq 0 ]; then
|
|
1823
1912
|
return 0
|
|
1824
1913
|
fi
|
|
1825
1914
|
|
|
1826
|
-
rm -rf /
|
|
1915
|
+
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1827
1916
|
GIT_CLONE_STRATEGY="mirror_local"
|
|
1828
1917
|
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"
|
|
1829
|
-
git clone --branch "$GIT_REF" "$mirror" /
|
|
1918
|
+
git clone --branch "$GIT_REF" "$mirror" ${KASEKI_WORKSPACE_DIR}/repo
|
|
1830
1919
|
clone_rc=$?
|
|
1831
|
-
if [ "$clone_rc" -eq 0 ] && git -C /
|
|
1832
|
-
git -C /
|
|
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
|
|
1833
1922
|
return 0
|
|
1834
1923
|
fi
|
|
1835
1924
|
|
|
1836
|
-
rm -rf /
|
|
1925
|
+
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1837
1926
|
GIT_CACHE_STATUS="mirror_clone_failed"
|
|
1838
1927
|
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"
|
|
1839
1928
|
run_direct_clone
|
|
@@ -2110,7 +2199,7 @@ record_skipped_npm_script_command() {
|
|
|
2110
2199
|
local command="$1"
|
|
2111
2200
|
local script_name="$2"
|
|
2112
2201
|
local duration_seconds="$3"
|
|
2113
|
-
local log_file="${4
|
|
2202
|
+
local log_file="${4:-${KASEKI_RESULTS_DIR}/validation.log}"
|
|
2114
2203
|
local timings_file="${5:-$VALIDATION_TIMINGS_FILE}"
|
|
2115
2204
|
local skip_label="${6:-skipped}"
|
|
2116
2205
|
local classification="${7:-}"
|
|
@@ -2144,7 +2233,7 @@ classify_auto_lint_cleanup_command_exit() {
|
|
|
2144
2233
|
}
|
|
2145
2234
|
|
|
2146
2235
|
record_skipped_validation_command() {
|
|
2147
|
-
record_skipped_npm_script_command "$1" "$2" "$3" "${4
|
|
2236
|
+
record_skipped_npm_script_command "$1" "$2" "$3" "${4:-${KASEKI_RESULTS_DIR}/validation.log}" "${5:-$VALIDATION_TIMINGS_FILE}" "skipped"
|
|
2148
2237
|
}
|
|
2149
2238
|
|
|
2150
2239
|
has_typescript_project() {
|
|
@@ -2213,9 +2302,9 @@ run_typescript_precheck() {
|
|
|
2213
2302
|
if ! has_npm_build_command "$KASEKI_TS_CHECK_COMMAND"; then
|
|
2214
2303
|
local missing_script
|
|
2215
2304
|
missing_script="$(npm_run_script_name "$KASEKI_TS_CHECK_COMMAND")" || missing_script="$KASEKI_TS_CHECK_COMMAND"
|
|
2216
|
-
printf '\n==> TypeScript pre-check\n' | tee -a /
|
|
2217
|
-
printf 'Command: %s\n' "$KASEKI_TS_CHECK_COMMAND" | tee -a /
|
|
2218
|
-
printf 'skipped: npm script "%s" not found in package.json\n' "$missing_script" | tee -a /
|
|
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
|
|
2219
2308
|
emit_error_event "typescript_precheck_skipped_missing_script" "TypeScript check skipped: npm script '$missing_script' not defined" "continue"
|
|
2220
2309
|
emit_progress "typescript precheck" "skipped (npm script '$missing_script' not found)"
|
|
2221
2310
|
record_stage_timing "typescript precheck" 0 0 "skipped_missing_script"
|
|
@@ -2230,8 +2319,8 @@ run_typescript_precheck() {
|
|
|
2230
2319
|
{
|
|
2231
2320
|
printf '\n==> TypeScript pre-check\n'
|
|
2232
2321
|
printf 'Command: %s\n' "$KASEKI_TS_CHECK_COMMAND"
|
|
2233
|
-
eval "cd /
|
|
2234
|
-
} 2>&1 | tee -a /
|
|
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
|
|
2235
2324
|
ts_check_exit="${PIPESTATUS[0]}"
|
|
2236
2325
|
|
|
2237
2326
|
ts_check_end="$(date +%s)"
|
|
@@ -2255,7 +2344,7 @@ run_typescript_precheck() {
|
|
|
2255
2344
|
append_validation_failure_tail() {
|
|
2256
2345
|
local raw_log="$1"
|
|
2257
2346
|
local visible_log="$2"
|
|
2258
|
-
local quality_log="${3
|
|
2347
|
+
local quality_log="${3:-${KASEKI_RESULTS_DIR}/quality.log}"
|
|
2259
2348
|
|
|
2260
2349
|
if ! [ -s "$raw_log" ]; then
|
|
2261
2350
|
return 0
|
|
@@ -2304,14 +2393,14 @@ run_trailing_whitespace_cleanup_for_changed_tracked_text_files() {
|
|
|
2304
2393
|
collect_changed_file_set() {
|
|
2305
2394
|
local output_file="$1"
|
|
2306
2395
|
: > "$output_file"
|
|
2307
|
-
if [ ! -d /
|
|
2396
|
+
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
2308
2397
|
return 0
|
|
2309
2398
|
fi
|
|
2310
2399
|
|
|
2311
2400
|
{
|
|
2312
|
-
git -C /
|
|
2313
|
-
git -C /
|
|
2314
|
-
git -C /
|
|
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
|
|
2315
2404
|
} | sed '/^$/d' | LC_ALL=C sort -u > "$output_file"
|
|
2316
2405
|
}
|
|
2317
2406
|
|
|
@@ -2319,7 +2408,7 @@ collect_changed_file_state() {
|
|
|
2319
2408
|
local output_file="$1"
|
|
2320
2409
|
local changed_files_file path staged_hash unstaged_hash content_hash state
|
|
2321
2410
|
: > "$output_file"
|
|
2322
|
-
if [ ! -d /
|
|
2411
|
+
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
2323
2412
|
return 0
|
|
2324
2413
|
fi
|
|
2325
2414
|
|
|
@@ -2328,14 +2417,14 @@ collect_changed_file_state() {
|
|
|
2328
2417
|
|
|
2329
2418
|
while IFS= read -r path || [ -n "$path" ]; do
|
|
2330
2419
|
[ -z "$path" ] && continue
|
|
2331
|
-
if git -C /
|
|
2332
|
-
staged_hash="$(git -C /
|
|
2333
|
-
unstaged_hash="$(git -C /
|
|
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}')"
|
|
2334
2423
|
state="tracked:staged=${staged_hash}:unstaged=${unstaged_hash}"
|
|
2335
|
-
elif [ -f "/
|
|
2336
|
-
content_hash="$(git -C /
|
|
2424
|
+
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}')"
|
|
2337
2426
|
state="untracked:file=${content_hash}"
|
|
2338
|
-
elif [ -d "/
|
|
2427
|
+
elif [ -d "${KASEKI_WORKSPACE_DIR}/repo/$path" ]; then
|
|
2339
2428
|
state="untracked:directory"
|
|
2340
2429
|
else
|
|
2341
2430
|
state="untracked:missing"
|
|
@@ -2353,25 +2442,25 @@ restore_cleanup_disallowed_changes() {
|
|
|
2353
2442
|
|
|
2354
2443
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
2355
2444
|
[ -z "$changed_file" ] && continue
|
|
2356
|
-
printf 'Restoring cleanup-created file outside allowlist: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" /
|
|
2445
|
+
printf 'Restoring cleanup-created file outside allowlist: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" ${KASEKI_RESULTS_DIR}/quality.log
|
|
2357
2446
|
emit_event "auto_lint_cleanup_file_restored" "file=$changed_file" "reason=not_in_cleanup_allowlist"
|
|
2358
|
-
git -C /
|
|
2359
|
-
git -C /
|
|
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
|
|
2360
2449
|
done < "$disallowed_file"
|
|
2361
2450
|
}
|
|
2362
2451
|
|
|
2363
2452
|
check_auto_lint_cleanup_allowlist() {
|
|
2364
2453
|
local before_file="$1"
|
|
2365
2454
|
local after_file="$2"
|
|
2366
|
-
local cleanup_created_file="/
|
|
2367
|
-
local disallowed_file="/
|
|
2368
|
-
local post_restore_file="/
|
|
2455
|
+
local cleanup_created_file="${KASEKI_RESULTS_DIR}/auto-lint-cleanup-created-files.txt"
|
|
2456
|
+
local disallowed_file="${KASEKI_RESULTS_DIR}/auto-lint-cleanup-disallowed-files.txt"
|
|
2457
|
+
local post_restore_file="${KASEKI_RESULTS_DIR}/auto-lint-cleanup-post-restore-files.txt"
|
|
2369
2458
|
local allowlist_patterns allowlist_regex changed_file disallowed_count unrestored_count
|
|
2370
2459
|
|
|
2371
2460
|
: > "$cleanup_created_file"
|
|
2372
2461
|
: > "$disallowed_file"
|
|
2373
2462
|
: > "$post_restore_file"
|
|
2374
|
-
if [ ! -d /
|
|
2463
|
+
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
2375
2464
|
return 0
|
|
2376
2465
|
fi
|
|
2377
2466
|
|
|
@@ -2386,7 +2475,7 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2386
2475
|
if [ -n "$allowlist_regex" ] && printf '%s\n' "$changed_file" | grep -Eq "^(${allowlist_regex})$"; then
|
|
2387
2476
|
emit_event "quality_gate_rule_evaluated" "rule=auto_lint_cleanup_allowlist" "passed=true" "file=$changed_file"
|
|
2388
2477
|
else
|
|
2389
|
-
printf 'Auto lint cleanup created changed file outside allowlist: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" /
|
|
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
|
|
2390
2479
|
printf '%s\n' "$changed_file" >> "$disallowed_file"
|
|
2391
2480
|
emit_event "quality_gate_rule_evaluated" "rule=auto_lint_cleanup_allowlist" "passed=false" "file=$changed_file"
|
|
2392
2481
|
fi
|
|
@@ -2403,12 +2492,12 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2403
2492
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
2404
2493
|
[ -z "$changed_file" ] && continue
|
|
2405
2494
|
if grep -Fxq -- "$changed_file" "$post_restore_file"; then
|
|
2406
|
-
printf 'ERROR: Cleanup-created disallowed change could not be restored: %s\n' "$changed_file" | tee -a "$AUTO_LINT_CLEANUP_LOG" /
|
|
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
|
|
2407
2496
|
unrestored_count=$((unrestored_count + 1))
|
|
2408
2497
|
fi
|
|
2409
2498
|
done < "$disallowed_file"
|
|
2410
2499
|
if [ "$unrestored_count" -eq 0 ]; then
|
|
2411
|
-
printf 'Auto lint cleanup restored %s cleanup-created file(s) outside allowlist.\n' "$disallowed_count" | tee -a "$AUTO_LINT_CLEANUP_LOG" /
|
|
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
|
|
2412
2501
|
emit_event "auto_lint_cleanup_allowlist_restoration_complete" "restored=$disallowed_count" "unrestored=0"
|
|
2413
2502
|
collect_git_artifacts
|
|
2414
2503
|
return 0
|
|
@@ -2421,7 +2510,7 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2421
2510
|
AUTO_LINT_CLEANUP_FAILURE_CLASSIFICATION="cleanup_allowlist_failed"
|
|
2422
2511
|
QUALITY_EXIT=7
|
|
2423
2512
|
QUALITY_FAILURE_REASON="auto_lint_cleanup_allowlist: $disallowed_count cleanup-created file(s) outside KASEKI_CHANGED_FILES_ALLOWLIST/KASEKI_VALIDATION_ALLOWLIST"
|
|
2424
|
-
printf 'ERROR: %s\n' "$QUALITY_FAILURE_REASON" | tee -a "$AUTO_LINT_CLEANUP_LOG" /
|
|
2513
|
+
printf 'ERROR: %s\n' "$QUALITY_FAILURE_REASON" | tee -a "$AUTO_LINT_CLEANUP_LOG" ${KASEKI_RESULTS_DIR}/quality.log
|
|
2425
2514
|
emit_error_event "auto_lint_cleanup_allowlist_failed" "$QUALITY_FAILURE_REASON" "continue"
|
|
2426
2515
|
return 1
|
|
2427
2516
|
}
|
|
@@ -2481,12 +2570,12 @@ run_auto_lint_cleanup() {
|
|
|
2481
2570
|
return 0
|
|
2482
2571
|
fi
|
|
2483
2572
|
|
|
2484
|
-
if ! [ -d /
|
|
2573
|
+
if ! [ -d ${KASEKI_WORKSPACE_DIR}/repo ]; then
|
|
2485
2574
|
AUTO_LINT_CLEANUP_EXIT=1
|
|
2486
2575
|
AUTO_LINT_CLEANUP_RESULT="failed"
|
|
2487
2576
|
AUTO_LINT_CLEANUP_CLASSIFICATION="directory_missing"
|
|
2488
2577
|
AUTO_LINT_CLEANUP_FAILURE_CLASSIFICATION="directory_missing"
|
|
2489
|
-
printf 'ERROR: Working directory /
|
|
2578
|
+
printf 'ERROR: Working directory ${KASEKI_WORKSPACE_DIR}/repo does not exist before auto lint cleanup.\n' | tee -a "$AUTO_LINT_CLEANUP_LOG"
|
|
2490
2579
|
printf 'workspace_missing\t%s\t0\tclassification=directory_missing\n' "$AUTO_LINT_CLEANUP_EXIT" >> "$AUTO_LINT_CLEANUP_TIMINGS_FILE"
|
|
2491
2580
|
record_stage_timing "$stage_label" "$AUTO_LINT_CLEANUP_EXIT" "$(($(date +%s) - stage_start))" "directory_missing classification=directory_missing"
|
|
2492
2581
|
emit_event "auto_lint_cleanup_finished" "exit_code=$AUTO_LINT_CLEANUP_EXIT" "result=failed" "classification=directory_missing" "reason=directory_missing"
|
|
@@ -2494,8 +2583,8 @@ run_auto_lint_cleanup() {
|
|
|
2494
2583
|
return 0
|
|
2495
2584
|
fi
|
|
2496
2585
|
|
|
2497
|
-
cleanup_before_file="/
|
|
2498
|
-
cleanup_after_file="/
|
|
2586
|
+
cleanup_before_file="${KASEKI_RESULTS_DIR}/auto-lint-cleanup-before-files.txt"
|
|
2587
|
+
cleanup_after_file="${KASEKI_RESULTS_DIR}/auto-lint-cleanup-after-files.txt"
|
|
2499
2588
|
collect_changed_file_set "$cleanup_before_file"
|
|
2500
2589
|
|
|
2501
2590
|
set +e
|
|
@@ -2585,7 +2674,7 @@ baseline_validation_cache_key() {
|
|
|
2585
2674
|
}
|
|
2586
2675
|
|
|
2587
2676
|
baseline_validation_cache_dir() {
|
|
2588
|
-
local cache_root="${KASEKI_BASELINE_CACHE_ROOT
|
|
2677
|
+
local cache_root="${KASEKI_BASELINE_CACHE_ROOT:-${KASEKI_CACHE_DIR}/kaseki-baseline}"
|
|
2589
2678
|
local cache_key
|
|
2590
2679
|
cache_key="$(baseline_validation_cache_key)"
|
|
2591
2680
|
printf '%s/%s' "$cache_root" "$cache_key"
|
|
@@ -2619,19 +2708,19 @@ restore_baseline_validation_from_cache() {
|
|
|
2619
2708
|
fi
|
|
2620
2709
|
|
|
2621
2710
|
# Restore cached files to results directory
|
|
2622
|
-
mkdir -p
|
|
2711
|
+
mkdir -p ${KASEKI_RESULTS_DIR}
|
|
2623
2712
|
|
|
2624
|
-
if ! cp "$cache_dir/validation.log" /
|
|
2713
|
+
if ! cp "$cache_dir/validation.log" ${KASEKI_RESULTS_DIR}/validation-baseline.log 2>/dev/null; then
|
|
2625
2714
|
return 1
|
|
2626
2715
|
fi
|
|
2627
|
-
if ! cp "$cache_dir/validation-raw.log" /
|
|
2716
|
+
if ! cp "$cache_dir/validation-raw.log" ${KASEKI_RESULTS_DIR}/validation-baseline-raw.log 2>/dev/null; then
|
|
2628
2717
|
return 1
|
|
2629
2718
|
fi
|
|
2630
|
-
if ! cp "$cache_dir/validation-timings.tsv" /
|
|
2719
|
+
if ! cp "$cache_dir/validation-timings.tsv" ${KASEKI_RESULTS_DIR}/validation-baseline-timings.tsv 2>/dev/null; then
|
|
2631
2720
|
return 1
|
|
2632
2721
|
fi
|
|
2633
2722
|
if [ -f "$cache_dir/validation-env.log" ]; then
|
|
2634
|
-
cp "$cache_dir/validation-env.log" /
|
|
2723
|
+
cp "$cache_dir/validation-env.log" ${KASEKI_RESULTS_DIR}/validation-baseline-env.log 2>/dev/null || true
|
|
2635
2724
|
fi
|
|
2636
2725
|
|
|
2637
2726
|
return 0
|
|
@@ -2648,27 +2737,27 @@ save_baseline_validation_to_cache() {
|
|
|
2648
2737
|
mkdir -p "$cache_dir" || return 1
|
|
2649
2738
|
|
|
2650
2739
|
# Save validation results to cache
|
|
2651
|
-
if [ -f /
|
|
2652
|
-
cp /
|
|
2740
|
+
if [ -f ${KASEKI_RESULTS_DIR}/validation-baseline.log ]; then
|
|
2741
|
+
cp ${KASEKI_RESULTS_DIR}/validation-baseline.log "$cache_dir/validation.log" || return 1
|
|
2653
2742
|
fi
|
|
2654
2743
|
|
|
2655
|
-
if [ -f /
|
|
2656
|
-
cp /
|
|
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
|
|
2657
2746
|
fi
|
|
2658
2747
|
|
|
2659
|
-
if [ -f /
|
|
2660
|
-
cp /
|
|
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
|
|
2661
2750
|
fi
|
|
2662
2751
|
|
|
2663
|
-
if [ -f /
|
|
2664
|
-
cp /
|
|
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
|
|
2665
2754
|
fi
|
|
2666
2755
|
|
|
2667
2756
|
return 0
|
|
2668
2757
|
}
|
|
2669
2758
|
|
|
2670
2759
|
checkout_baseline_repo() {
|
|
2671
|
-
local baseline_dir="
|
|
2760
|
+
local baseline_dir="${KASEKI_WORKSPACE_BASELINE_DIR}"
|
|
2672
2761
|
|
|
2673
2762
|
# Clean up any existing baseline
|
|
2674
2763
|
rm -rf "$baseline_dir" 2>/dev/null || true
|
|
@@ -2687,20 +2776,20 @@ checkout_baseline_repo() {
|
|
|
2687
2776
|
emit_progress "baseline preparation" "installing baseline dependencies"
|
|
2688
2777
|
if ! cd "$baseline_dir" && npm ci --prefer-offline 2>>"$KASEKI_LOG_DIR/baseline-npm-ci.log"; then
|
|
2689
2778
|
emit_error_event "baseline_deps_failed" "Failed to install baseline dependencies" "continue"
|
|
2690
|
-
cd /
|
|
2779
|
+
cd ${KASEKI_WORKSPACE_DIR}/repo
|
|
2691
2780
|
return 1
|
|
2692
2781
|
fi
|
|
2693
|
-
cd /
|
|
2782
|
+
cd ${KASEKI_WORKSPACE_DIR}/repo
|
|
2694
2783
|
fi
|
|
2695
2784
|
|
|
2696
2785
|
return 0
|
|
2697
2786
|
}
|
|
2698
2787
|
|
|
2699
2788
|
run_baseline_validation() {
|
|
2700
|
-
local baseline_dir="
|
|
2701
|
-
local baseline_log="/
|
|
2702
|
-
local baseline_raw_log="/
|
|
2703
|
-
local baseline_timings="/
|
|
2789
|
+
local baseline_dir="${KASEKI_WORKSPACE_BASELINE_DIR}"
|
|
2790
|
+
local baseline_log="${KASEKI_RESULTS_DIR}/validation-baseline.log"
|
|
2791
|
+
local baseline_raw_log="${KASEKI_RESULTS_DIR}/validation-baseline-raw.log"
|
|
2792
|
+
local baseline_timings="${KASEKI_RESULTS_DIR}/validation-baseline-timings.tsv"
|
|
2704
2793
|
local baseline_exit_var="BASELINE_VALIDATION_EXIT"
|
|
2705
2794
|
local baseline_detail_var="BASELINE_VALIDATION_FAILED_COMMAND_DETAIL"
|
|
2706
2795
|
local baseline_reason_var="BASELINE_VALIDATION_FAILURE_REASON"
|
|
@@ -2722,7 +2811,7 @@ run_baseline_validation() {
|
|
|
2722
2811
|
"$baseline_log" \
|
|
2723
2812
|
"$baseline_raw_log" \
|
|
2724
2813
|
"$baseline_timings" \
|
|
2725
|
-
"/
|
|
2814
|
+
"${KASEKI_RESULTS_DIR}/validation-baseline-env.log" \
|
|
2726
2815
|
"baseline_validation_failed" \
|
|
2727
2816
|
"$baseline_exit_var" \
|
|
2728
2817
|
"$baseline_detail_var" \
|
|
@@ -2742,10 +2831,10 @@ run_baseline_validation() {
|
|
|
2742
2831
|
}
|
|
2743
2832
|
|
|
2744
2833
|
analyze_test_failures_baseline() {
|
|
2745
|
-
local baseline_log="/
|
|
2746
|
-
local working_log="/
|
|
2747
|
-
local output_file="/
|
|
2748
|
-
local results_dir="
|
|
2834
|
+
local baseline_log="${KASEKI_RESULTS_DIR}/validation-baseline.log"
|
|
2835
|
+
local working_log="${KASEKI_RESULTS_DIR}/pre-validation.log"
|
|
2836
|
+
local output_file="${KASEKI_RESULTS_DIR}/test-baseline-comparison.json"
|
|
2837
|
+
local results_dir="${KASEKI_RESULTS_DIR}"
|
|
2749
2838
|
|
|
2750
2839
|
if [ ! -f "$baseline_log" ] || [ ! -f "$working_log" ]; then
|
|
2751
2840
|
emit_progress "test failure analysis" "skipped (baseline or working log missing)"
|
|
@@ -2786,11 +2875,11 @@ analyze_test_failures_baseline() {
|
|
|
2786
2875
|
}
|
|
2787
2876
|
|
|
2788
2877
|
analyze_validation_failure_causality() {
|
|
2789
|
-
local baseline_log="/
|
|
2790
|
-
local post_change_log="/
|
|
2791
|
-
local git_diff="/
|
|
2792
|
-
local changed_files="/
|
|
2793
|
-
local output_file="/
|
|
2878
|
+
local baseline_log="${KASEKI_RESULTS_DIR}/validation-baseline.log"
|
|
2879
|
+
local post_change_log="${KASEKI_RESULTS_DIR}/validation.log"
|
|
2880
|
+
local git_diff="${KASEKI_RESULTS_DIR}/git.diff"
|
|
2881
|
+
local changed_files="${KASEKI_RESULTS_DIR}/changed-files.txt"
|
|
2882
|
+
local output_file="${KASEKI_RESULTS_DIR}/validation-causality-analysis.json"
|
|
2794
2883
|
|
|
2795
2884
|
# Skip if no baseline (first run)
|
|
2796
2885
|
if [ ! -f "$baseline_log" ]; then
|
|
@@ -2936,13 +3025,13 @@ run_validation_commands() {
|
|
|
2936
3025
|
record_stage_timing "$stage_label" 0 0 "skipped_by_config"
|
|
2937
3026
|
else
|
|
2938
3027
|
# Checkpoint: Verify working directory exists before validation.
|
|
2939
|
-
if ! [ -d /
|
|
2940
|
-
printf 'ERROR: Working directory /
|
|
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"
|
|
2941
3030
|
printf 'Current pwd: %s\n' "$(pwd 2>&1 || echo '<pwd failed>')" | tee -a "$log_file"
|
|
2942
3031
|
printf 'Filesystem state:\n' | tee -a "$log_file"
|
|
2943
3032
|
find /workspace -maxdepth 3 -type f 2>&1 | head -100 | tee -a "$log_file"
|
|
2944
3033
|
validation_exit_ref=1
|
|
2945
|
-
validation_detail_ref="Working directory /
|
|
3034
|
+
validation_detail_ref="Working directory ${KASEKI_WORKSPACE_DIR}/repo missing before $stage_label"
|
|
2946
3035
|
validation_reason_ref="$failure_reason_prefix: workspace_missing"
|
|
2947
3036
|
record_stage_timing "$stage_label" "$validation_exit_ref" "$(($(date +%s) - stage_start))" "directory_missing"
|
|
2948
3037
|
else
|
|
@@ -2968,7 +3057,7 @@ run_validation_commands() {
|
|
|
2968
3057
|
printf '[validation command] working_directory=%s\n' "$(pwd 2>&1 || echo '<pwd failed>')"
|
|
2969
3058
|
printf '[validation command] node_version=%s\n' "$(node --version 2>&1 || echo '<node not found>')"
|
|
2970
3059
|
printf '[validation command] npm_version=%s\n' "$(npm --version 2>&1 || echo '<npm not found>')"
|
|
2971
|
-
printf '[validation command] disk_available=%s\n' "$(df -h
|
|
3060
|
+
printf '[validation command] disk_available=%s\n' "$(df -h ${KASEKI_RESULTS_DIR} 2>/dev/null | tail -1 | awk '{print $4}' || echo '<df failed>')"
|
|
2972
3061
|
} | tee -a "$env_log"
|
|
2973
3062
|
# Use pipefail to catch errors in any stage of the pipe.
|
|
2974
3063
|
pipefail_was_enabled=0
|
|
@@ -3030,7 +3119,7 @@ run_validation_commands() {
|
|
|
3030
3119
|
{
|
|
3031
3120
|
printf '\n[DIAGNOSTICS] Validation pipeline stderr from filter/tee (last 50 lines):\n'
|
|
3032
3121
|
printf '%s\n' "$FILTER_STDERR_TAIL"
|
|
3033
|
-
} | tee -a "$log_file" /
|
|
3122
|
+
} | tee -a "$log_file" ${KASEKI_RESULTS_DIR}/quality.log
|
|
3034
3123
|
{
|
|
3035
3124
|
printf '\n[validation pipeline stderr tail]\n'
|
|
3036
3125
|
printf '%s\n' "$FILTER_STDERR_TAIL"
|
|
@@ -3058,7 +3147,7 @@ run_validation_commands() {
|
|
|
3058
3147
|
else
|
|
3059
3148
|
printf ' (No stderr captured from filter/tee)\n'
|
|
3060
3149
|
fi
|
|
3061
|
-
} | tee -a "$log_file" /
|
|
3150
|
+
} | tee -a "$log_file" ${KASEKI_RESULTS_DIR}/quality.log "$FILTER_DIAGNOSTICS_LOG"
|
|
3062
3151
|
fi
|
|
3063
3152
|
|
|
3064
3153
|
if [ "$validation_infra_failure" = "true" ] && [ "$validation_exit_ref" -eq 0 ]; then
|
|
@@ -3082,13 +3171,13 @@ run_validation_commands() {
|
|
|
3082
3171
|
printf '\n[DIAGNOSTICS] Validation command failed with directory access error:\n'
|
|
3083
3172
|
printf 'Working directory status:\n'
|
|
3084
3173
|
printf ' Current pwd: %s\n' "$(pwd 2>&1 || echo '<pwd failed>')"
|
|
3085
|
-
printf ' /
|
|
3086
|
-
if [ -L /
|
|
3087
|
-
printf ' node_modules is symlink → %s\n' "$(readlink /
|
|
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>')"
|
|
3088
3177
|
fi
|
|
3089
3178
|
printf 'Last 20 lines of validation log:\n'
|
|
3090
3179
|
tail -20 "$log_file"
|
|
3091
|
-
} | tee -a /
|
|
3180
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
3092
3181
|
fi
|
|
3093
3182
|
# Fail-fast: if enabled, stop validation loop at first failure.
|
|
3094
3183
|
if [ "$KASEKI_VALIDATION_FAIL_FAST" -eq 1 ]; then
|
|
@@ -3169,7 +3258,7 @@ write_repo_memory_summary() {
|
|
|
3169
3258
|
return 0
|
|
3170
3259
|
fi
|
|
3171
3260
|
local updated_at
|
|
3172
|
-
REPO_MEMORY_COMMIT_SHA="$(git -C /
|
|
3261
|
+
REPO_MEMORY_COMMIT_SHA="$(git -C ${KASEKI_WORKSPACE_DIR}/repo rev-parse HEAD 2>/dev/null || printf 'unknown')"
|
|
3173
3262
|
updated_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
3174
3263
|
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' || {
|
|
3175
3264
|
const fs = require('fs');
|
|
@@ -3349,9 +3438,9 @@ is_transient_goal_setting_failure() {
|
|
|
3349
3438
|
local stderr_content="$2"
|
|
3350
3439
|
|
|
3351
3440
|
# First, check if we have an explicit validation reason code from our helper
|
|
3352
|
-
if [ -f /
|
|
3441
|
+
if [ -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt ]; then
|
|
3353
3442
|
local reason_code
|
|
3354
|
-
reason_code=$(cat /
|
|
3443
|
+
reason_code=$(cat ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || echo "")
|
|
3355
3444
|
case "$reason_code" in
|
|
3356
3445
|
valid)
|
|
3357
3446
|
return 1
|
|
@@ -3530,7 +3619,7 @@ validate_goal_setting_artifact() {
|
|
|
3530
3619
|
local candidate_artifact="$1"
|
|
3531
3620
|
local final_artifact="$2"
|
|
3532
3621
|
local reason_file="$3"
|
|
3533
|
-
local results_dir="${KASEKI_RESULTS_DIR
|
|
3622
|
+
local results_dir="${KASEKI_RESULTS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
3534
3623
|
|
|
3535
3624
|
if ! [ -f "$candidate_artifact" ]; then
|
|
3536
3625
|
{
|
|
@@ -3570,7 +3659,7 @@ validate_goal_setting_artifact() {
|
|
|
3570
3659
|
validate_goal_setting_artifact_with_node() {
|
|
3571
3660
|
local candidate_artifact="$1"
|
|
3572
3661
|
local reason_file="$2"
|
|
3573
|
-
local results_dir="${KASEKI_RESULTS_DIR
|
|
3662
|
+
local results_dir="${KASEKI_RESULTS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
3574
3663
|
|
|
3575
3664
|
local validation_output
|
|
3576
3665
|
validation_output=$(node -e "
|
|
@@ -3755,13 +3844,13 @@ run_goal_setting_agent() {
|
|
|
3755
3844
|
set_current_stage "pi goal-setting agent"
|
|
3756
3845
|
|
|
3757
3846
|
if [ "$KASEKI_GOAL_SETTING" = "0" ]; then
|
|
3758
|
-
printf 'Pi goal-setting agent skipped because KASEKI_GOAL_SETTING=0.\n' | tee -a /
|
|
3847
|
+
printf 'Pi goal-setting agent skipped because KASEKI_GOAL_SETTING=0.\n' | tee -a ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log
|
|
3759
3848
|
record_stage_timing "pi goal-setting agent" 0 0 "skipped_by_config"
|
|
3760
3849
|
return 0
|
|
3761
3850
|
fi
|
|
3762
3851
|
|
|
3763
3852
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
3764
|
-
printf 'DRY-RUN: Pi goal-setting agent would upgrade the task prompt into a mature goal.\n' | tee -a /
|
|
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
|
|
3765
3854
|
record_stage_timing "pi goal-setting agent" 0 0 "dry_run=true"
|
|
3766
3855
|
return 0
|
|
3767
3856
|
fi
|
|
@@ -3773,23 +3862,23 @@ run_goal_setting_agent() {
|
|
|
3773
3862
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
3774
3863
|
timeout --signal=SIGTERM "$KASEKI_GOAL_SETTING_TIMEOUT_SECONDS" \
|
|
3775
3864
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_GOAL_SETTING_MODEL" "$goal_setting_prompt" \
|
|
3776
|
-
2> >(tee -a /
|
|
3865
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log >&2) \
|
|
3777
3866
|
| tee "$GOAL_SETTING_RAW_EVENTS" \
|
|
3778
|
-
| kaseki-pi-progress-stream /
|
|
3867
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
3779
3868
|
GOAL_SETTING_EXIT="${PIPESTATUS[0]}"
|
|
3780
3869
|
GOAL_SETTING_DURATION_SECONDS=$(($(date +%s) - goal_setting_start))
|
|
3781
3870
|
unset goal_setting_prompt
|
|
3782
3871
|
set +e
|
|
3783
3872
|
|
|
3784
|
-
if [ "$GOAL_SETTING_EXIT" -eq 0 ] && ! validate_goal_setting_artifact "$GOAL_SETTING_CANDIDATE_ARTIFACT" "$GOAL_SETTING_ARTIFACT" "/
|
|
3873
|
+
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
|
|
3785
3874
|
GOAL_SETTING_EXIT=86
|
|
3786
|
-
goal_setting_validation_summary="$(cat /
|
|
3787
|
-
emit_error_event "pi_goal_setting_artifact_invalid" "Pi goal-setting artifact invalid: $goal_setting_validation_summary (full details: /
|
|
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"
|
|
3788
3877
|
fi
|
|
3789
3878
|
|
|
3790
3879
|
rm -f "$GOAL_SETTING_CANDIDATE_ARTIFACT"
|
|
3791
|
-
kaseki-pi-event-filter "$GOAL_SETTING_RAW_EVENTS" /
|
|
3792
|
-
GOAL_SETTING_ACTUAL_MODEL="$(node -e 'try { const s=require("/
|
|
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
|
|
3881
|
+
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)"
|
|
3793
3882
|
|
|
3794
3883
|
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"
|
|
3795
3884
|
|
|
@@ -3799,7 +3888,7 @@ run_goal_setting_agent() {
|
|
|
3799
3888
|
fi
|
|
3800
3889
|
|
|
3801
3890
|
emit_progress "pi goal-setting agent" "wrote goal-setting artifact"
|
|
3802
|
-
rm -f /
|
|
3891
|
+
rm -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || true
|
|
3803
3892
|
|
|
3804
3893
|
return 0
|
|
3805
3894
|
}
|
|
@@ -3834,7 +3923,7 @@ write_goal_setting_metrics() {
|
|
|
3834
3923
|
model: '${GOAL_SETTING_ACTUAL_MODEL:-unknown}',
|
|
3835
3924
|
timeout_seconds: ${KASEKI_GOAL_SETTING_TIMEOUT_SECONDS:-300}
|
|
3836
3925
|
};
|
|
3837
|
-
fs.writeFileSync('/
|
|
3926
|
+
fs.writeFileSync('${KASEKI_RESULTS_DIR}/goal-setting-metrics.json', JSON.stringify(metrics, null, 2) + '\n');
|
|
3838
3927
|
" 2>/dev/null || {
|
|
3839
3928
|
# Fallback to jq or printf if node fails
|
|
3840
3929
|
{
|
|
@@ -3850,7 +3939,7 @@ write_goal_setting_metrics() {
|
|
|
3850
3939
|
printf ' "model": "%s",\n' "${GOAL_SETTING_ACTUAL_MODEL:-unknown}"
|
|
3851
3940
|
printf ' "timeout_seconds": %d\n' "${KASEKI_GOAL_SETTING_TIMEOUT_SECONDS:-300}"
|
|
3852
3941
|
printf '}\n'
|
|
3853
|
-
} > /
|
|
3942
|
+
} > ${KASEKI_RESULTS_DIR}/goal-setting-metrics.json
|
|
3854
3943
|
}
|
|
3855
3944
|
}
|
|
3856
3945
|
|
|
@@ -3859,9 +3948,9 @@ classify_goal_setting_error() {
|
|
|
3859
3948
|
local stderr_content="$2"
|
|
3860
3949
|
|
|
3861
3950
|
# Check validation reason file first (most authoritative)
|
|
3862
|
-
if [ -f /
|
|
3951
|
+
if [ -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt ]; then
|
|
3863
3952
|
local reason_code
|
|
3864
|
-
reason_code=$(cat /
|
|
3953
|
+
reason_code=$(cat ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || echo "")
|
|
3865
3954
|
case "$reason_code" in
|
|
3866
3955
|
schema_mismatch)
|
|
3867
3956
|
echo "GOAL_SETTING_SCHEMA_MISMATCH"
|
|
@@ -3940,7 +4029,7 @@ run_goal_setting_agent_with_retry() {
|
|
|
3940
4029
|
set -e
|
|
3941
4030
|
|
|
3942
4031
|
# Append stderr to results for logging
|
|
3943
|
-
cat "$goal_setting_stderr_capture" >> /
|
|
4032
|
+
cat "$goal_setting_stderr_capture" >> ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log 2>/dev/null || true
|
|
3944
4033
|
goal_setting_last_stderr="$(cat "$goal_setting_stderr_capture" 2>/dev/null || true)"
|
|
3945
4034
|
rm -f "$goal_setting_stderr_capture"
|
|
3946
4035
|
|
|
@@ -3972,7 +4061,7 @@ run_goal_setting_agent_with_retry() {
|
|
|
3972
4061
|
attempt=$((attempt + 1))
|
|
3973
4062
|
# Reset goal-setting artifacts for retry
|
|
3974
4063
|
rm -f "$GOAL_SETTING_ARTIFACT" "$GOAL_SETTING_RAW_EVENTS" 2>/dev/null || true
|
|
3975
|
-
rm -f /
|
|
4064
|
+
rm -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || true
|
|
3976
4065
|
continue
|
|
3977
4066
|
fi
|
|
3978
4067
|
else
|
|
@@ -4006,9 +4095,9 @@ is_transient_scouting_failure() {
|
|
|
4006
4095
|
local stderr_content="$2"
|
|
4007
4096
|
|
|
4008
4097
|
# First, check if we have an explicit validation reason code from our helper
|
|
4009
|
-
if [ -f /
|
|
4098
|
+
if [ -f ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt ]; then
|
|
4010
4099
|
local reason_code
|
|
4011
|
-
reason_code=$(cat /
|
|
4100
|
+
reason_code=$(cat ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt 2>/dev/null || echo "")
|
|
4012
4101
|
case "$reason_code" in
|
|
4013
4102
|
valid)
|
|
4014
4103
|
# This shouldn't happen when exit_code=86, but just in case
|
|
@@ -4143,48 +4232,48 @@ run_scouting_agent() {
|
|
|
4143
4232
|
printf '\n==> pi scouting agent\n'
|
|
4144
4233
|
set_current_stage "pi scouting agent"
|
|
4145
4234
|
if [ "$KASEKI_SCOUTING" = "0" ]; then
|
|
4146
|
-
printf 'Pi scouting agent skipped because KASEKI_SCOUTING=0.\n' | tee -a /
|
|
4235
|
+
printf 'Pi scouting agent skipped because KASEKI_SCOUTING=0.\n' | tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
4147
4236
|
record_stage_timing "pi scouting agent" 0 0 "skipped_by_config"
|
|
4148
4237
|
return 0
|
|
4149
4238
|
fi
|
|
4150
4239
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
4151
|
-
printf 'DRY-RUN: Pi scouting agent would inspect the task before coding.\n' | tee -a /
|
|
4240
|
+
printf 'DRY-RUN: Pi scouting agent would inspect the task before coding.\n' | tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
4152
4241
|
record_stage_timing "pi scouting agent" 0 0 "dry_run=true"
|
|
4153
4242
|
return 0
|
|
4154
4243
|
fi
|
|
4155
4244
|
|
|
4156
4245
|
scouting_prompt="$(build_scouting_prompt)"
|
|
4157
4246
|
scouting_start="$(date +%s)"
|
|
4158
|
-
scout_dirty_before="$(git status --porcelain 2>> /
|
|
4159
|
-
chmod -R a-w /
|
|
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
|
|
4160
4249
|
set +e
|
|
4161
4250
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
4162
4251
|
timeout --signal=SIGTERM "$KASEKI_SCOUTING_TIMEOUT_SECONDS" \
|
|
4163
4252
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_SCOUTING_MODEL" "$scouting_prompt" \
|
|
4164
|
-
2> >(tee -a /
|
|
4253
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log >&2) \
|
|
4165
4254
|
| tee "$SCOUTING_RAW_EVENTS" \
|
|
4166
|
-
| kaseki-pi-progress-stream /
|
|
4255
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
4167
4256
|
SCOUTING_EXIT="${PIPESTATUS[0]}"
|
|
4168
4257
|
SCOUTING_DURATION_SECONDS=$(($(date +%s) - scouting_start))
|
|
4169
4258
|
unset scouting_prompt
|
|
4170
4259
|
set +e
|
|
4171
|
-
chmod -R u+w /
|
|
4260
|
+
chmod -R u+w ${KASEKI_WORKSPACE_DIR}/repo 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true
|
|
4172
4261
|
|
|
4173
|
-
if [ "$SCOUTING_EXIT" -eq 0 ] && ! validate_scouting_artifact "$SCOUTING_CANDIDATE_ARTIFACT" "$SCOUTING_ARTIFACT" "/
|
|
4262
|
+
if [ "$SCOUTING_EXIT" -eq 0 ] && ! validate_scouting_artifact "$SCOUTING_CANDIDATE_ARTIFACT" "$SCOUTING_ARTIFACT" "${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt"; then
|
|
4174
4263
|
SCOUTING_EXIT=86
|
|
4175
|
-
scouting_validation_summary="$(cat /
|
|
4176
|
-
emit_error_event "pi_scouting_artifact_invalid" "Pi scouting handoff invalid: $scouting_validation_summary (full details: /
|
|
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"
|
|
4177
4266
|
fi
|
|
4178
|
-
scout_dirty_after="$(git status --porcelain 2>> /
|
|
4267
|
+
scout_dirty_after="$(git status --porcelain 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true)"
|
|
4179
4268
|
if [ "$SCOUTING_EXIT" -eq 0 ] && [ "$scout_dirty_before" != "$scout_dirty_after" ]; then
|
|
4180
4269
|
SCOUTING_EXIT=86
|
|
4181
4270
|
emit_error_event "pi_scouting_workspace_modified" "Read-only scouting changed repository state before coding" "exit"
|
|
4182
4271
|
fi
|
|
4183
4272
|
rm -f "$SCOUTING_CANDIDATE_ARTIFACT"
|
|
4184
|
-
git reset --hard -q HEAD 2>> /
|
|
4185
|
-
git clean -fd -q 2>> /
|
|
4186
|
-
kaseki-pi-event-filter "$SCOUTING_RAW_EVENTS" /
|
|
4187
|
-
SCOUTING_ACTUAL_MODEL="$(node -e 'try { const s=require("/
|
|
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
|
+
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)"
|
|
4188
4277
|
record_stage_timing "pi scouting agent" "$SCOUTING_EXIT" "$SCOUTING_DURATION_SECONDS" "artifact=$SCOUTING_ARTIFACT timeout_seconds=$KASEKI_SCOUTING_TIMEOUT_SECONDS"
|
|
4189
4278
|
if [ "$SCOUTING_EXIT" -ne 0 ]; then
|
|
4190
4279
|
STATUS="$SCOUTING_EXIT"
|
|
@@ -4194,7 +4283,7 @@ run_scouting_agent() {
|
|
|
4194
4283
|
fi
|
|
4195
4284
|
emit_progress "pi scouting agent" "wrote scouting artifact"
|
|
4196
4285
|
# Clean up validation reason file on success
|
|
4197
|
-
rm -f /
|
|
4286
|
+
rm -f ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt 2>/dev/null || true
|
|
4198
4287
|
return 0
|
|
4199
4288
|
}
|
|
4200
4289
|
|
|
@@ -4222,7 +4311,7 @@ run_scouting_agent_with_retry() {
|
|
|
4222
4311
|
set -e
|
|
4223
4312
|
|
|
4224
4313
|
# Append stderr to results for logging
|
|
4225
|
-
cat "$scouting_stderr_capture" >> /
|
|
4314
|
+
cat "$scouting_stderr_capture" >> ${KASEKI_RESULTS_DIR}/scouting-stderr.log 2>/dev/null || true
|
|
4226
4315
|
scouting_last_stderr="$(cat "$scouting_stderr_capture" 2>/dev/null || true)"
|
|
4227
4316
|
rm -f "$scouting_stderr_capture"
|
|
4228
4317
|
|
|
@@ -4241,7 +4330,7 @@ run_scouting_agent_with_retry() {
|
|
|
4241
4330
|
# Reset scouting artifacts for retry
|
|
4242
4331
|
rm -f "$SCOUTING_ARTIFACT" "$SCOUTING_RAW_EVENTS" 2>/dev/null || true
|
|
4243
4332
|
# Clean up validation reason file from previous attempt
|
|
4244
|
-
rm -f /
|
|
4333
|
+
rm -f ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt 2>/dev/null || true
|
|
4245
4334
|
continue
|
|
4246
4335
|
fi
|
|
4247
4336
|
else
|
|
@@ -4265,13 +4354,13 @@ run_scouting_agent_with_retry() {
|
|
|
4265
4354
|
|
|
4266
4355
|
snapshot_attempt_artifacts() {
|
|
4267
4356
|
local attempt_dir
|
|
4268
|
-
attempt_dir="/
|
|
4357
|
+
attempt_dir="${KASEKI_RESULTS_DIR}/attempt-$1"
|
|
4269
4358
|
mkdir -p "$attempt_dir" 2>/dev/null || return 0
|
|
4270
4359
|
for artifact in \
|
|
4271
4360
|
pi-events.jsonl pi-summary.json pi-stderr.log git.diff git.status changed-files.txt \
|
|
4272
4361
|
quality.log validation.log validation-raw.log validation-timings.tsv goal-check.json; do
|
|
4273
|
-
if [ -e "
|
|
4274
|
-
cp "
|
|
4362
|
+
if [ -e "${KASEKI_RESULTS_DIR}/$artifact" ]; then
|
|
4363
|
+
cp "${KASEKI_RESULTS_DIR}/$artifact" "$attempt_dir/$artifact" 2>/dev/null || true
|
|
4275
4364
|
fi
|
|
4276
4365
|
done
|
|
4277
4366
|
}
|
|
@@ -4279,7 +4368,7 @@ snapshot_attempt_artifacts() {
|
|
|
4279
4368
|
collect_goal_check_feedback() {
|
|
4280
4369
|
local instance_name="$1"
|
|
4281
4370
|
local goal_setting_path="$GOAL_SETTING_ARTIFACT"
|
|
4282
|
-
local results_dir="${KASEKI_RESULTS_DIR
|
|
4371
|
+
local results_dir="${KASEKI_RESULTS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
4283
4372
|
local goal_check_path="$results_dir/goal-check.json"
|
|
4284
4373
|
local metadata_path="$results_dir/metadata.json"
|
|
4285
4374
|
local feedback_file="$results_dir/goal-feedback.jsonl"
|
|
@@ -4295,9 +4384,9 @@ collect_goal_check_feedback() {
|
|
|
4295
4384
|
|
|
4296
4385
|
collect_run_evaluation_feedback() {
|
|
4297
4386
|
local instance_name="$1"
|
|
4298
|
-
local run_evaluation_path="/
|
|
4299
|
-
local metadata_path="/
|
|
4300
|
-
local feedback_file="/
|
|
4387
|
+
local run_evaluation_path="${KASEKI_RESULTS_DIR}/run-evaluation.json"
|
|
4388
|
+
local metadata_path="${KASEKI_RESULTS_DIR}/metadata.json"
|
|
4389
|
+
local feedback_file="${KASEKI_RESULTS_DIR}/kaseki-improvements.jsonl"
|
|
4301
4390
|
|
|
4302
4391
|
# Only collect if run-evaluation succeeded and artifacts exist
|
|
4303
4392
|
if [ ! -f "$run_evaluation_path" ] || [ "$RUN_EVALUATION_EXIT" -ne 0 ]; then
|
|
@@ -4311,14 +4400,14 @@ collect_run_evaluation_feedback() {
|
|
|
4311
4400
|
|
|
4312
4401
|
build_goal_check_prompt() {
|
|
4313
4402
|
local validation_tail progress_tail goal_setting_context validation_context test_impact_context causality_context
|
|
4314
|
-
validation_tail="$(tail -80 /
|
|
4403
|
+
validation_tail="$(tail -80 ${KASEKI_RESULTS_DIR}/validation.log 2>/dev/null || true)"
|
|
4315
4404
|
if [ -n "$(printf '%s' "$validation_tail" | tr -d '[:space:]')" ]; then
|
|
4316
4405
|
validation_context="Validation log tail (last 80 lines):
|
|
4317
4406
|
$validation_tail"
|
|
4318
4407
|
else
|
|
4319
|
-
validation_context="Validation log: /
|
|
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."
|
|
4320
4409
|
fi
|
|
4321
|
-
progress_tail="$(tail -80 /
|
|
4410
|
+
progress_tail="$(tail -80 ${KASEKI_RESULTS_DIR}/progress.log 2>/dev/null || true)"
|
|
4322
4411
|
if [ -s "$TEST_IMPACT_WARNINGS_ARTIFACT" ]; then
|
|
4323
4412
|
test_impact_context="Static test-impact warnings artifact ($TEST_IMPACT_WARNINGS_ARTIFACT):
|
|
4324
4413
|
$(cat "$TEST_IMPACT_WARNINGS_ARTIFACT" 2>/dev/null)
|
|
@@ -4344,7 +4433,7 @@ $(head -n 200 "$GOAL_SETTING_ARTIFACT" 2>/dev/null)
|
|
|
4344
4433
|
fi
|
|
4345
4434
|
|
|
4346
4435
|
# Include causality assessment if available (helps interpret validation failures)
|
|
4347
|
-
if [ -f /
|
|
4436
|
+
if [ -f ${KASEKI_RESULTS_DIR}/validation-causality-analysis.json ]; then
|
|
4348
4437
|
# shellcheck disable=SC2016
|
|
4349
4438
|
causality_context="VALIDATION FAILURE CAUSALITY ASSESSMENT:
|
|
4350
4439
|
|
|
@@ -4404,11 +4493,11 @@ Determine if the agent successfully met the requirements specified in the goal-s
|
|
|
4404
4493
|
|
|
4405
4494
|
**Agent Artifacts** (use to verify requirements were met):
|
|
4406
4495
|
- Scouting report: $SCOUTING_ARTIFACT
|
|
4407
|
-
- Changed files: /
|
|
4408
|
-
- Git diff: /
|
|
4409
|
-
- Validation outcomes (optional evidence; may be absent during pre-validation checks): /
|
|
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
|
|
4410
4499
|
- Static test-impact warnings (non-blocking): $TEST_IMPACT_WARNINGS_ARTIFACT
|
|
4411
|
-
- Coding-agent events: /
|
|
4500
|
+
- Coding-agent events: ${KASEKI_RESULTS_DIR}/pi-summary.json and ${KASEKI_RESULTS_DIR}/pi-events.jsonl
|
|
4412
4501
|
|
|
4413
4502
|
## Evaluation Framework: SMART Criteria Check
|
|
4414
4503
|
|
|
@@ -4467,7 +4556,7 @@ Example: "Null handling is done (parseRole returns 'Unnamed Role'), but test cov
|
|
|
4467
4556
|
- Do not print, inspect, or expose environment variables, secrets, credentials, API keys, or mounted secret files.
|
|
4468
4557
|
- Decide whether the goal requirements were realized. Do not evaluate code style, architecture, or elegance.
|
|
4469
4558
|
- If anti-patterns were specified in goal-setting (do_not_modify, do_not_break), verify they were respected.
|
|
4470
|
-
- Validation logs are optional evidence. If /
|
|
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.
|
|
4471
4560
|
|
|
4472
4561
|
## Required JSON artifact
|
|
4473
4562
|
|
|
@@ -4518,12 +4607,12 @@ run_goal_check() {
|
|
|
4518
4607
|
printf '\n==> goal check\n'
|
|
4519
4608
|
set_current_stage "goal check"
|
|
4520
4609
|
if [ "$KASEKI_GOAL_CHECK" != "1" ]; then
|
|
4521
|
-
printf 'Goal check skipped because KASEKI_GOAL_CHECK=%s.\n' "$KASEKI_GOAL_CHECK" | tee -a /
|
|
4610
|
+
printf 'Goal check skipped because KASEKI_GOAL_CHECK=%s.\n' "$KASEKI_GOAL_CHECK" | tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log
|
|
4522
4611
|
record_stage_timing "goal check" 0 0 "skipped_by_config attempt=$attempt"
|
|
4523
4612
|
return 0
|
|
4524
4613
|
fi
|
|
4525
4614
|
if [ ! -s "$SCOUTING_ARTIFACT" ]; then
|
|
4526
|
-
printf 'Goal check skipped because scouting artifact is unavailable.\n' | tee -a /
|
|
4615
|
+
printf 'Goal check skipped because scouting artifact is unavailable.\n' | tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log
|
|
4527
4616
|
record_stage_timing "goal check" 0 0 "skipped_no_scouting attempt=$attempt"
|
|
4528
4617
|
return 0
|
|
4529
4618
|
fi
|
|
@@ -4534,15 +4623,15 @@ run_goal_check() {
|
|
|
4534
4623
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
4535
4624
|
timeout --signal=SIGTERM "$KASEKI_GOAL_CHECK_TIMEOUT_SECONDS" \
|
|
4536
4625
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_GOAL_CHECK_MODEL" "$goal_prompt" \
|
|
4537
|
-
2> >(tee -a /
|
|
4626
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log >&2) \
|
|
4538
4627
|
| tee "$GOAL_CHECK_RAW_EVENTS" \
|
|
4539
|
-
| kaseki-pi-progress-stream /
|
|
4628
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
4540
4629
|
GOAL_CHECK_EXIT="${PIPESTATUS[0]}"
|
|
4541
4630
|
unset goal_prompt
|
|
4542
4631
|
GOAL_CHECK_DURATION_SECONDS=$((GOAL_CHECK_DURATION_SECONDS + $(date +%s) - goal_start))
|
|
4543
4632
|
set +e
|
|
4544
4633
|
|
|
4545
|
-
kaseki-pi-event-filter "$GOAL_CHECK_RAW_EVENTS" /
|
|
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
|
|
4546
4635
|
|
|
4547
4636
|
if [ "$GOAL_CHECK_EXIT" -eq 0 ] && [ ! -f "$GOAL_CHECK_CANDIDATE_ARTIFACT" ]; then
|
|
4548
4637
|
# Recover from goal-check agents that printed the verdict in assistant text instead of writing the artifact.
|
|
@@ -4640,38 +4729,38 @@ if (valid.size === 1) {
|
|
|
4640
4729
|
const recovered = [...valid.values()][0];
|
|
4641
4730
|
fs.writeFileSync(candidatePath, JSON.stringify(recovered, null, 2) + "\n");
|
|
4642
4731
|
const note = { timestamp: new Date().toISOString(), attempt, event: "goal_check_artifact_recovered_from_assistant_text", artifact: candidatePath, raw_events: rawPath, filtered_events: filteredPath };
|
|
4643
|
-
fs.appendFileSync("/
|
|
4732
|
+
fs.appendFileSync(process.env.KASEKI_RESULTS_DIR + "/goal-check-stderr.log", JSON.stringify(note) + "\n");
|
|
4644
4733
|
}
|
|
4645
|
-
' "$GOAL_CHECK_CANDIDATE_ARTIFACT" "$GOAL_CHECK_RAW_EVENTS" /
|
|
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
|
|
4646
4735
|
fi
|
|
4647
4736
|
|
|
4648
|
-
if [ "$GOAL_CHECK_EXIT" -eq 0 ] && ! validate_goal_check_artifact "$GOAL_CHECK_CANDIDATE_ARTIFACT" /
|
|
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
|
|
4649
4738
|
GOAL_CHECK_EXIT=86
|
|
4650
|
-
goal_check_validation_reason="$(cat /
|
|
4651
|
-
goal_check_validation_summary="$(cat /
|
|
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')"
|
|
4652
4741
|
case "$goal_check_validation_reason" in
|
|
4653
4742
|
missing_file)
|
|
4654
4743
|
GOAL_CHECK_FAILURE_REASON="goal_check_artifact_missing"
|
|
4655
|
-
emit_error_event "goal_check_artifact_missing" "Goal-check candidate artifact was missing: $GOAL_CHECK_CANDIDATE_ARTIFACT ($goal_check_validation_summary; full details: /
|
|
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"
|
|
4656
4745
|
;;
|
|
4657
4746
|
malformed_json)
|
|
4658
4747
|
GOAL_CHECK_FAILURE_REASON="goal_check_artifact_malformed"
|
|
4659
|
-
emit_error_event "goal_check_artifact_malformed" "Goal-check Pi wrote malformed JSON: $goal_check_validation_summary (full details: /
|
|
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"
|
|
4660
4749
|
;;
|
|
4661
4750
|
*)
|
|
4662
4751
|
GOAL_CHECK_FAILURE_REASON="goal_check_artifact_invalid"
|
|
4663
|
-
emit_error_event "goal_check_artifact_invalid" "Goal-check Pi did not write a schema-valid JSON verdict: $goal_check_validation_summary (full details: /
|
|
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"
|
|
4664
4753
|
;;
|
|
4665
4754
|
esac
|
|
4666
4755
|
fi
|
|
4667
4756
|
rm -f "$GOAL_CHECK_CANDIDATE_ARTIFACT"
|
|
4668
|
-
GOAL_CHECK_ACTUAL_MODEL="$(node -e 'try { const s=require("/
|
|
4757
|
+
GOAL_CHECK_ACTUAL_MODEL="$(node -e 'try { const s=require(process.env.KASEKI_RESULTS_DIR + "/goal-check-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)"
|
|
4669
4758
|
|
|
4670
4759
|
if [ "$GOAL_CHECK_EXIT" -eq 0 ]; then
|
|
4671
|
-
verdict_met="$(node -e 'const v=require(
|
|
4672
|
-
retry_prompt="$(node -e 'const v=require(
|
|
4673
|
-
verdict_summary="$(node -e 'const v=require(
|
|
4674
|
-
confidence="$(node -e 'const v=require(
|
|
4760
|
+
verdict_met="$(node -e 'try { const v=require(process.argv[1]); console.log(v.met ? "true" : "false"); } catch { console.log("false"); }' "${KASEKI_RESULTS_DIR}/goal-check.json" 2>/dev/null || printf 'false')"
|
|
4761
|
+
retry_prompt="$(node -e 'try { const v=require(process.argv[1]); console.log(v.retry_prompt || ""); } catch { console.log(""); }' "${KASEKI_RESULTS_DIR}/goal-check.json" 2>/dev/null || true)"
|
|
4762
|
+
verdict_summary="$(node -e 'try { const v=require(process.argv[1]); console.log(v.summary || ""); } catch { console.log(""); }' "${KASEKI_RESULTS_DIR}/goal-check.json" 2>/dev/null || true)"
|
|
4763
|
+
confidence="$(node -e 'try { const v=require(process.argv[1]); console.log(v.confidence || "unknown"); } catch { console.log("unknown"); }' "${KASEKI_RESULTS_DIR}/goal-check.json" 2>/dev/null || true)"
|
|
4675
4764
|
if [ "$verdict_met" = "true" ]; then
|
|
4676
4765
|
GOAL_CHECK_MET=true
|
|
4677
4766
|
GOAL_CHECK_RETRY_PROMPT=""
|
|
@@ -4694,12 +4783,12 @@ if (valid.size === 1) {
|
|
|
4694
4783
|
|
|
4695
4784
|
build_run_evaluation_prompt() {
|
|
4696
4785
|
local validation_tail progress_tail stage_timings dependency_cache restoration_report draft_pr_body metadata_text goal_setting_context test_impact_context
|
|
4697
|
-
validation_tail="$(tail -80 /
|
|
4698
|
-
progress_tail="$(tail -80 /
|
|
4699
|
-
stage_timings="$(tail -80 /
|
|
4700
|
-
dependency_cache="$(tail -80 /
|
|
4701
|
-
restoration_report="$(tail -80 /
|
|
4702
|
-
metadata_text="$(cat /
|
|
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)"
|
|
4703
4792
|
draft_pr_body="$(build_pr_body)"
|
|
4704
4793
|
if [ -s "$TEST_IMPACT_WARNINGS_ARTIFACT" ]; then
|
|
4705
4794
|
test_impact_context="Static test-impact warnings artifact ($TEST_IMPACT_WARNINGS_ARTIFACT):
|
|
@@ -4745,15 +4834,15 @@ This is NOT another goal-check. The goal-check evaluator already determined if t
|
|
|
4745
4834
|
- Quality metrics, SMART criteria, anti-patterns
|
|
4746
4835
|
|
|
4747
4836
|
**Agent Artifacts** (verify goal was realized):
|
|
4748
|
-
- Goal-check verdict: /
|
|
4749
|
-
- Scouting report: /
|
|
4750
|
-
- Changed files: /
|
|
4751
|
-
- Git diff and status: /
|
|
4752
|
-
- Validation timings/logs: /
|
|
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
|
|
4753
4842
|
- Static test-impact warnings (non-blocking): $TEST_IMPACT_WARNINGS_ARTIFACT
|
|
4754
|
-
- Stage timings: /
|
|
4755
|
-
- Progress log: /
|
|
4756
|
-
- Metadata: /
|
|
4843
|
+
- Stage timings: ${KASEKI_RESULTS_DIR}/stage-timings.tsv
|
|
4844
|
+
- Progress log: ${KASEKI_RESULTS_DIR}/progress.log
|
|
4845
|
+
- Metadata: ${KASEKI_RESULTS_DIR}/metadata.json
|
|
4757
4846
|
|
|
4758
4847
|
## Evaluation Framework
|
|
4759
4848
|
|
|
@@ -4967,12 +5056,12 @@ run_run_evaluation() {
|
|
|
4967
5056
|
printf '\n==> run evaluation\n'
|
|
4968
5057
|
set_current_stage "run evaluation"
|
|
4969
5058
|
if [ "$KASEKI_RUN_EVALUATION" != "1" ]; then
|
|
4970
|
-
printf 'Run evaluation skipped because KASEKI_RUN_EVALUATION=%s.\n' "$KASEKI_RUN_EVALUATION" | tee -a /
|
|
5059
|
+
printf 'Run evaluation skipped because KASEKI_RUN_EVALUATION=%s.\n' "$KASEKI_RUN_EVALUATION" | tee -a ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log
|
|
4971
5060
|
record_stage_timing "run evaluation" 0 0 "skipped_by_config"
|
|
4972
5061
|
return 0
|
|
4973
5062
|
fi
|
|
4974
5063
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
4975
|
-
printf 'Run evaluation skipped for dry-run/startup-check mode.\n' | tee -a /
|
|
5064
|
+
printf 'Run evaluation skipped for dry-run/startup-check mode.\n' | tee -a ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log
|
|
4976
5065
|
record_stage_timing "run evaluation" 0 0 "dry_run=true"
|
|
4977
5066
|
return 0
|
|
4978
5067
|
fi
|
|
@@ -4981,19 +5070,19 @@ run_run_evaluation() {
|
|
|
4981
5070
|
write_metadata "$STATUS"
|
|
4982
5071
|
evaluation_prompt="$(build_run_evaluation_prompt)"
|
|
4983
5072
|
evaluation_start="$(date +%s)"
|
|
4984
|
-
eval_dirty_before="$(git status --porcelain 2>> /
|
|
4985
|
-
chmod -R a-w /
|
|
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
|
|
4986
5075
|
set +e
|
|
4987
5076
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
4988
5077
|
timeout --signal=SIGTERM "$KASEKI_RUN_EVALUATION_TIMEOUT_SECONDS" \
|
|
4989
5078
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_RUN_EVALUATION_MODEL" "$evaluation_prompt" \
|
|
4990
|
-
2> >(tee -a /
|
|
5079
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log >&2) \
|
|
4991
5080
|
| tee "$RUN_EVALUATION_RAW_EVENTS" \
|
|
4992
|
-
| kaseki-pi-progress-stream /
|
|
5081
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
4993
5082
|
RUN_EVALUATION_EXIT="${PIPESTATUS[0]}"
|
|
4994
5083
|
unset evaluation_prompt
|
|
4995
5084
|
RUN_EVALUATION_DURATION_SECONDS=$((RUN_EVALUATION_DURATION_SECONDS + $(date +%s) - evaluation_start))
|
|
4996
|
-
chmod -R u+w /
|
|
5085
|
+
chmod -R u+w ${KASEKI_WORKSPACE_DIR}/repo 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true
|
|
4997
5086
|
set +e
|
|
4998
5087
|
|
|
4999
5088
|
if [ "$RUN_EVALUATION_EXIT" -eq 0 ] && ! node -e '
|
|
@@ -5023,15 +5112,15 @@ artifact.timestamp = new Date().toISOString();
|
|
|
5023
5112
|
artifact.model = model;
|
|
5024
5113
|
artifact.actual_model = actualModel;
|
|
5025
5114
|
fs.writeFileSync(output, JSON.stringify(artifact, null, 2) + "\n");
|
|
5026
|
-
' "$RUN_EVALUATION_CANDIDATE_ARTIFACT" "$RUN_EVALUATION_ARTIFACT" "$KASEKI_RUN_EVALUATION_MODEL" "$RUN_EVALUATION_ACTUAL_MODEL" 2>> /
|
|
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
|
|
5027
5116
|
RUN_EVALUATION_EXIT=86
|
|
5028
5117
|
emit_error_event "run_evaluation_artifact_invalid" "Run-evaluation Pi did not write a schema-valid JSON artifact" "continue"
|
|
5029
5118
|
fi
|
|
5030
5119
|
rm -f "$RUN_EVALUATION_CANDIDATE_ARTIFACT"
|
|
5031
|
-
kaseki-pi-event-filter "$RUN_EVALUATION_RAW_EVENTS" /
|
|
5032
|
-
RUN_EVALUATION_ACTUAL_MODEL="$(node -e 'try { const s=require("/
|
|
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
|
|
5121
|
+
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)"
|
|
5033
5122
|
if [ -s "$RUN_EVALUATION_ARTIFACT" ]; then
|
|
5034
|
-
node - "$RUN_EVALUATION_ARTIFACT" "$RUN_EVALUATION_ACTUAL_MODEL" <<'NODE' 2>> /
|
|
5123
|
+
node - "$RUN_EVALUATION_ARTIFACT" "$RUN_EVALUATION_ACTUAL_MODEL" <<'NODE' 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true
|
|
5035
5124
|
const fs = require('fs');
|
|
5036
5125
|
const [file, actualModel] = process.argv.slice(2);
|
|
5037
5126
|
const artifact = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
@@ -5040,12 +5129,12 @@ fs.writeFileSync(file, JSON.stringify(artifact, null, 2) + '\n');
|
|
|
5040
5129
|
NODE
|
|
5041
5130
|
fi
|
|
5042
5131
|
|
|
5043
|
-
eval_dirty_after="$(git status --porcelain 2>> /
|
|
5132
|
+
eval_dirty_after="$(git status --porcelain 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true)"
|
|
5044
5133
|
if [ "$eval_dirty_before" != "$eval_dirty_after" ]; then
|
|
5045
5134
|
RUN_EVALUATION_EXIT=86
|
|
5046
5135
|
emit_error_event "run_evaluation_workspace_modified" "Read-only run evaluation changed repository state; restoring workspace" "continue"
|
|
5047
|
-
git reset --hard -q HEAD 2>> /
|
|
5048
|
-
git clean -fd -q 2>> /
|
|
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
|
|
5049
5138
|
fi
|
|
5050
5139
|
|
|
5051
5140
|
if [ "$RUN_EVALUATION_EXIT" -ne 0 ] || [ ! -s "$RUN_EVALUATION_ARTIFACT" ]; then
|
|
@@ -5142,19 +5231,19 @@ META
|
|
|
5142
5231
|
log_github_private_key_metadata() {
|
|
5143
5232
|
local key_file="$1"
|
|
5144
5233
|
local health_log="$2"
|
|
5145
|
-
local metadata_file="/
|
|
5234
|
+
local metadata_file="${KASEKI_RESULTS_DIR}/github-app-private-key-metadata.json"
|
|
5146
5235
|
github_private_key_metadata_json "$key_file" > "$metadata_file"
|
|
5147
5236
|
printf '[health-check] GitHub App private key metadata: %s\n' "$(tr -d '\n' < "$metadata_file")" | tee -a "$health_log"
|
|
5148
5237
|
}
|
|
5149
5238
|
|
|
5150
5239
|
|
|
5151
5240
|
github_askpass_runtime_dir() {
|
|
5152
|
-
printf '%s\n' "${KASEKI_GITHUB_ASKPASS_DIR
|
|
5241
|
+
printf '%s\n' "${KASEKI_GITHUB_ASKPASS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
5153
5242
|
}
|
|
5154
5243
|
|
|
5155
5244
|
create_github_askpass_helper() {
|
|
5156
5245
|
local log_file log_prefix askpass_dir askpass_file username_smoke_output password_smoke_output
|
|
5157
|
-
log_file="${1
|
|
5246
|
+
log_file="${1:-${KASEKI_RESULTS_DIR}/git-push.log}"
|
|
5158
5247
|
log_prefix="${2:-[github-askpass]}"
|
|
5159
5248
|
GITHUB_ASKPASS_FILE=""
|
|
5160
5249
|
|
|
@@ -5232,7 +5321,7 @@ EOF_ASKPASS
|
|
|
5232
5321
|
check_github_operations_health() {
|
|
5233
5322
|
# Preflight health check for github operations before pi agent runs
|
|
5234
5323
|
# Tests: GitHub App secrets, git config, Node.js token generation capability
|
|
5235
|
-
local health_log="${KASEKI_HEALTH_LOG
|
|
5324
|
+
local health_log="${KASEKI_HEALTH_LOG:-${KASEKI_RESULTS_DIR}/github-health-check.log}"
|
|
5236
5325
|
github_preflight_fail() {
|
|
5237
5326
|
local classification="$1"
|
|
5238
5327
|
local remediation="$2"
|
|
@@ -5486,7 +5575,7 @@ validate_github_api_response() {
|
|
|
5486
5575
|
local http_status response log_file error_type error_message json_valid
|
|
5487
5576
|
http_status="$1"
|
|
5488
5577
|
response="$2"
|
|
5489
|
-
log_file="${3
|
|
5578
|
+
log_file="${3:-${KASEKI_RESULTS_DIR}/git-push.log}"
|
|
5490
5579
|
|
|
5491
5580
|
# Try to parse error info from response
|
|
5492
5581
|
error_type="unknown"
|
|
@@ -5594,7 +5683,7 @@ apply_github_pr_labels() {
|
|
|
5594
5683
|
repo="$2"
|
|
5595
5684
|
issue_number="$3"
|
|
5596
5685
|
token="$4"
|
|
5597
|
-
log_file="${5
|
|
5686
|
+
log_file="${5:-${KASEKI_RESULTS_DIR}/git-push.log}"
|
|
5598
5687
|
|
|
5599
5688
|
if [ -z "$owner" ] || [ -z "$repo" ] || [ -z "$issue_number" ] || [ -z "$token" ]; then
|
|
5600
5689
|
printf 'Warning: skipping PR label application because owner, repo, issue number, or token is missing\n' | tee -a "$log_file" >&2
|
|
@@ -5648,7 +5737,7 @@ request_owner_review() {
|
|
|
5648
5737
|
local pr_response token log_file owner_login owner_type pr_number repo owner
|
|
5649
5738
|
pr_response="$1"
|
|
5650
5739
|
token="$2"
|
|
5651
|
-
log_file="${3
|
|
5740
|
+
log_file="${3:-${KASEKI_RESULTS_DIR}/git-push.log}"
|
|
5652
5741
|
|
|
5653
5742
|
if [ -z "$pr_response" ] || [ -z "$token" ]; then
|
|
5654
5743
|
printf 'Warning: skipping owner review request because PR response or token is missing\n' | tee -a "$log_file" >&2
|
|
@@ -5713,7 +5802,7 @@ request_owner_review() {
|
|
|
5713
5802
|
|
|
5714
5803
|
# Request owner review with retry logic
|
|
5715
5804
|
local retry_count=0 max_retries=2 request_success=0 backoff_delay=2
|
|
5716
|
-
local review_request_log="/
|
|
5805
|
+
local review_request_log="${KASEKI_RESULTS_DIR}/owner-review-request.log"
|
|
5717
5806
|
: > "$review_request_log"
|
|
5718
5807
|
|
|
5719
5808
|
while [ $retry_count -le "$max_retries" ]; do
|
|
@@ -5906,7 +5995,7 @@ derive_pr_title() {
|
|
|
5906
5995
|
|
|
5907
5996
|
candidate="$(printf '%s' "${TASK_PROMPT:-}" | sanitize_pr_metadata_text)"
|
|
5908
5997
|
prompt_for_prefix="$candidate"
|
|
5909
|
-
if [ -s /
|
|
5998
|
+
if [ -s ${KASEKI_RESULTS_DIR}/result-summary.md ]; then
|
|
5910
5999
|
summary_candidate="$(
|
|
5911
6000
|
awk '
|
|
5912
6001
|
/^##[[:space:]]+Summary[[:space:]]*$/ { in_summary=1; next }
|
|
@@ -5917,13 +6006,13 @@ derive_pr_title() {
|
|
|
5917
6006
|
sub(/^[[:space:]]*[0-9]+[.)][[:space:]]+/, "", line)
|
|
5918
6007
|
if (line !~ /^[[:space:]]*$/) { print line; exit }
|
|
5919
6008
|
}
|
|
5920
|
-
' /
|
|
6009
|
+
' ${KASEKI_RESULTS_DIR}/result-summary.md 2>/dev/null | sanitize_pr_metadata_text
|
|
5921
6010
|
)"
|
|
5922
6011
|
fi
|
|
5923
6012
|
if [ -n "$summary_candidate" ]; then
|
|
5924
6013
|
candidate="$summary_candidate"
|
|
5925
|
-
elif [ -z "$candidate" ] && [ -s /
|
|
5926
|
-
candidate="$(sed -n '/^- Status:/p; /^- Changed files:/p; /^- Validation:/p' /
|
|
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)"
|
|
5927
6016
|
fi
|
|
5928
6017
|
|
|
5929
6018
|
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:]]+$//')"
|
|
@@ -5933,8 +6022,8 @@ derive_pr_title() {
|
|
|
5933
6022
|
candidate="$stripped"
|
|
5934
6023
|
fi
|
|
5935
6024
|
|
|
5936
|
-
if [ -s /
|
|
5937
|
-
changed_files="$(sanitize_pr_metadata_text < /
|
|
6025
|
+
if [ -s ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
6026
|
+
changed_files="$(sanitize_pr_metadata_text < ${KASEKI_RESULTS_DIR}/changed-files.txt || true)"
|
|
5938
6027
|
else
|
|
5939
6028
|
changed_files=""
|
|
5940
6029
|
fi
|
|
@@ -6005,7 +6094,7 @@ format_pr_command_results() {
|
|
|
6005
6094
|
}
|
|
6006
6095
|
|
|
6007
6096
|
format_pr_changed_files() {
|
|
6008
|
-
local changed_files_file="/
|
|
6097
|
+
local changed_files_file="${KASEKI_RESULTS_DIR}/changed-files.txt"
|
|
6009
6098
|
local details_threshold=8
|
|
6010
6099
|
if [ ! -s "$changed_files_file" ]; then
|
|
6011
6100
|
printf '0 files changed.\n'
|
|
@@ -6095,8 +6184,8 @@ build_pr_agent_review() {
|
|
|
6095
6184
|
case "$validation_pass_flag" in
|
|
6096
6185
|
''|*[!0-9-]*) validation_pass_flag=0 ;;
|
|
6097
6186
|
esac
|
|
6098
|
-
local goal_file="/
|
|
6099
|
-
local scouting_file="/
|
|
6187
|
+
local goal_file="${KASEKI_RESULTS_DIR}/goal-check.json"
|
|
6188
|
+
local scouting_file="${KASEKI_RESULTS_DIR}/scouting.json"
|
|
6100
6189
|
local goal_summary evidence missing validation_notes risks
|
|
6101
6190
|
|
|
6102
6191
|
goal_summary=""
|
|
@@ -6145,7 +6234,7 @@ NODE
|
|
|
6145
6234
|
}
|
|
6146
6235
|
|
|
6147
6236
|
build_pr_agent_evaluation() {
|
|
6148
|
-
local evaluation_file="/
|
|
6237
|
+
local evaluation_file="${KASEKI_RESULTS_DIR}/run-evaluation.json"
|
|
6149
6238
|
if [ ! -s "$evaluation_file" ]; then
|
|
6150
6239
|
return 0
|
|
6151
6240
|
fi
|
|
@@ -6243,8 +6332,8 @@ NODE
|
|
|
6243
6332
|
}
|
|
6244
6333
|
|
|
6245
6334
|
build_pr_improvements_summary() {
|
|
6246
|
-
local changed_files_file="/
|
|
6247
|
-
local diff_file="/
|
|
6335
|
+
local changed_files_file="${KASEKI_RESULTS_DIR}/changed-files.txt"
|
|
6336
|
+
local diff_file="${KASEKI_RESULTS_DIR}/git.diff"
|
|
6248
6337
|
local total=0 source_count=0 test_count=0 docs_count=0 config_count=0 other_count=0
|
|
6249
6338
|
local path lower additions deletions summary_rows=0 summary_source=""
|
|
6250
6339
|
local artifact raw_line line safe_line summary_capture=0 content json_text
|
|
@@ -6264,10 +6353,10 @@ build_pr_improvements_summary() {
|
|
|
6264
6353
|
done < "$changed_files_file"
|
|
6265
6354
|
fi
|
|
6266
6355
|
|
|
6267
|
-
if [ -s /
|
|
6268
|
-
summary_source="/
|
|
6356
|
+
if [ -s ${KASEKI_RESULTS_DIR}/result-summary.md ]; then
|
|
6357
|
+
summary_source="${KASEKI_RESULTS_DIR}/result-summary.md"
|
|
6269
6358
|
else
|
|
6270
|
-
for artifact in /
|
|
6359
|
+
for artifact in ${KASEKI_RESULTS_DIR}/analysis.md ${KASEKI_RESULTS_DIR}/pi-summary.json; do
|
|
6271
6360
|
if [ -s "$artifact" ]; then
|
|
6272
6361
|
summary_source="$artifact"
|
|
6273
6362
|
break
|
|
@@ -6327,7 +6416,7 @@ EOF_JSON_SUMMARY
|
|
|
6327
6416
|
continue
|
|
6328
6417
|
;;
|
|
6329
6418
|
esac
|
|
6330
|
-
if [ "$summary_capture" -eq 0 ] && [ "$summary_source" = "/
|
|
6419
|
+
if [ "$summary_capture" -eq 0 ] && [ "$summary_source" = "${KASEKI_RESULTS_DIR}/result-summary.md" ]; then
|
|
6331
6420
|
continue
|
|
6332
6421
|
fi
|
|
6333
6422
|
line="$(printf '%s' "$raw_line" | sanitize_pr_metadata_text)"
|
|
@@ -6453,7 +6542,7 @@ $(build_pr_improvements_summary)
|
|
|
6453
6542
|
## Agent review
|
|
6454
6543
|
$(build_pr_agent_review "$all_validation_statuses_pass")
|
|
6455
6544
|
|
|
6456
|
-
$(if [ -s /
|
|
6545
|
+
$(if [ -s ${KASEKI_RESULTS_DIR}/run-evaluation.json ]; then printf '## Agent evaluation\n%s\n\n' "$(build_pr_agent_evaluation)"; fi)
|
|
6457
6546
|
## Validation
|
|
6458
6547
|
### Validation statuses
|
|
6459
6548
|
- Pre-agent validation: $pre_validation_status
|
|
@@ -6502,11 +6591,11 @@ run_github_operations() {
|
|
|
6502
6591
|
owner="$GITHUB_REPO_OWNER"
|
|
6503
6592
|
repo="$GITHUB_REPO_NAME"
|
|
6504
6593
|
else
|
|
6505
|
-
printf -- 'Cannot parse GitHub repo URL: %s\n' "$REPO_URL" | tee -a /
|
|
6594
|
+
printf -- 'Cannot parse GitHub repo URL: %s\n' "$REPO_URL" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6506
6595
|
return 7
|
|
6507
6596
|
fi
|
|
6508
6597
|
|
|
6509
|
-
printf -- 'GitHub operations: owner=%s, repo=%s\n' "$owner" "$repo" | tee -a /
|
|
6598
|
+
printf -- 'GitHub operations: owner=%s, repo=%s\n' "$owner" "$repo" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6510
6599
|
GITHUB_OPERATION_PHASE="setup"
|
|
6511
6600
|
|
|
6512
6601
|
# Set git user for commits
|
|
@@ -6515,7 +6604,7 @@ run_github_operations() {
|
|
|
6515
6604
|
|
|
6516
6605
|
# Generate GitHub App installation token
|
|
6517
6606
|
GITHUB_OPERATION_PHASE="token_generation"
|
|
6518
|
-
printf 'Generating GitHub App installation token...\n' | tee -a /
|
|
6607
|
+
printf 'Generating GitHub App installation token...\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6519
6608
|
local github_app_token_helper="${KASEKI_GITHUB_APP_TOKEN_HELPER:-/usr/local/bin/github-app-token}"
|
|
6520
6609
|
local token_stdout_tmp token_stderr_tmp token_exit_code token_stderr token_parse_result token_error token_http_status
|
|
6521
6610
|
token_stdout_tmp="$(mktemp /tmp/github-app-token-stdout.XXXXXX)" || { printf 'Failed to create token stdout temp file\n' >&2; return 7; }
|
|
@@ -6536,7 +6625,7 @@ run_github_operations() {
|
|
|
6536
6625
|
if [ "$token_parse_result" != "$token_error" ]; then
|
|
6537
6626
|
token_http_status="${token_parse_result#*$'\t'}"
|
|
6538
6627
|
fi
|
|
6539
|
-
printf 'Failed to generate token: %s\n' "$token_error" | tee -a /
|
|
6628
|
+
printf 'Failed to generate token: %s\n' "$token_error" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6540
6629
|
GITHUB_API_ERROR_TYPE="github_app_token_error"
|
|
6541
6630
|
GITHUB_API_ERROR_MESSAGE="$token_error"
|
|
6542
6631
|
GITHUB_API_HTTP_STATUS="$token_http_status"
|
|
@@ -6546,83 +6635,83 @@ run_github_operations() {
|
|
|
6546
6635
|
fi
|
|
6547
6636
|
|
|
6548
6637
|
# Use helper to extract token from JSON response
|
|
6549
|
-
if ! run_node_subprocess token "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); process.stdout.write(d.token || '')" "$token_data" /
|
|
6550
|
-
printf -- 'Failed to extract token from response: %s\n' "$token_data" | tee -a /
|
|
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
|
|
6551
6640
|
GITHUB_PUSH_EXIT=7
|
|
6552
6641
|
return 7
|
|
6553
6642
|
fi
|
|
6554
6643
|
|
|
6555
6644
|
if [ -z "$token" ]; then
|
|
6556
|
-
printf -- 'Failed to extract token from response (empty result)\n' | tee -a /
|
|
6645
|
+
printf -- 'Failed to extract token from response (empty result)\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6557
6646
|
GITHUB_PUSH_EXIT=7
|
|
6558
6647
|
return 7
|
|
6559
6648
|
fi
|
|
6560
6649
|
|
|
6561
|
-
printf 'Token generated successfully\n' | tee -a /
|
|
6650
|
+
printf 'Token generated successfully\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6562
6651
|
|
|
6563
6652
|
# Create and push feature branch
|
|
6564
6653
|
GITHUB_OPERATION_PHASE="branch_creation"
|
|
6565
6654
|
feature_branch="kaseki/$INSTANCE_NAME"
|
|
6566
|
-
printf -- 'Creating feature branch: %s\n' "$feature_branch" | tee -a /
|
|
6655
|
+
printf -- 'Creating feature branch: %s\n' "$feature_branch" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6567
6656
|
git checkout -b "$feature_branch" || {
|
|
6568
|
-
printf 'Failed to create branch\n' | tee -a /
|
|
6657
|
+
printf 'Failed to create branch\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6569
6658
|
GITHUB_PUSH_EXIT=7
|
|
6570
6659
|
return 7
|
|
6571
6660
|
}
|
|
6572
6661
|
|
|
6573
6662
|
# Commit changes (git should already have changes from pi agent)
|
|
6574
6663
|
GITHUB_OPERATION_PHASE="commit"
|
|
6575
|
-
printf 'Committing changes...\n' | tee -a /
|
|
6576
|
-
if [ ! -s /
|
|
6577
|
-
printf 'No changed files to stage\n' | tee -a /
|
|
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
|
|
6578
6667
|
GITHUB_PUSH_EXIT=7
|
|
6579
6668
|
return 7
|
|
6580
6669
|
fi
|
|
6581
6670
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
6582
6671
|
[ -z "$changed_file" ] && continue
|
|
6583
6672
|
git add -- "$changed_file" || {
|
|
6584
|
-
printf -- 'Failed to stage changed file: %s\n' "$changed_file" | tee -a /
|
|
6673
|
+
printf -- 'Failed to stage changed file: %s\n' "$changed_file" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6585
6674
|
GITHUB_PUSH_EXIT=7
|
|
6586
6675
|
return 7
|
|
6587
6676
|
}
|
|
6588
|
-
done < /
|
|
6677
|
+
done < ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
6589
6678
|
if ! git commit -m "Kaseki: $INSTANCE_NAME"; then
|
|
6590
|
-
printf 'No changes to commit or commit failed\n' | tee -a /
|
|
6679
|
+
printf 'No changes to commit or commit failed\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6591
6680
|
GITHUB_PUSH_EXIT=7
|
|
6592
6681
|
return 7
|
|
6593
6682
|
fi
|
|
6594
6683
|
|
|
6595
6684
|
# Push branch
|
|
6596
6685
|
GITHUB_OPERATION_PHASE="push"
|
|
6597
|
-
printf 'Pushing branch to GitHub...\n' | tee -a /
|
|
6686
|
+
printf 'Pushing branch to GitHub...\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6598
6687
|
local askpass_file
|
|
6599
|
-
if ! create_github_askpass_helper /
|
|
6688
|
+
if ! create_github_askpass_helper ${KASEKI_RESULTS_DIR}/git-push.log 'GitHub credential helper'; then
|
|
6600
6689
|
return 8
|
|
6601
6690
|
fi
|
|
6602
6691
|
askpass_file="$GITHUB_ASKPASS_FILE"
|
|
6603
6692
|
|
|
6604
6693
|
KASEKI_GITHUB_TOKEN="$token" GIT_ASKPASS="$askpass_file" GIT_TERMINAL_PROMPT=0 \
|
|
6605
|
-
git push "https://github.com/$owner/$repo.git" "$feature_branch" --force-with-lease 2>&1 | tee -a /
|
|
6694
|
+
git push "https://github.com/$owner/$repo.git" "$feature_branch" --force-with-lease 2>&1 | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6606
6695
|
git_push_exit="${PIPESTATUS[0]:-1}"
|
|
6607
6696
|
if [ "$git_push_exit" -eq 0 ]; then
|
|
6608
|
-
printf 'Branch pushed successfully\n' | tee -a /
|
|
6697
|
+
printf 'Branch pushed successfully\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6609
6698
|
else
|
|
6610
6699
|
rm -f "$askpass_file"
|
|
6611
|
-
printf 'Failed to push branch (exit %s)\n' "$git_push_exit" | tee -a /
|
|
6700
|
+
printf 'Failed to push branch (exit %s)\n' "$git_push_exit" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6612
6701
|
GITHUB_PUSH_EXIT="$git_push_exit"
|
|
6613
6702
|
return "$git_push_exit"
|
|
6614
6703
|
fi
|
|
6615
6704
|
rm -f "$askpass_file"
|
|
6616
6705
|
|
|
6617
6706
|
if [ "$KASEKI_PUBLISH_MODE" = "branch" ]; then
|
|
6618
|
-
printf 'Publish mode branch: skipping pull request creation.\n' | tee -a /
|
|
6707
|
+
printf 'Publish mode branch: skipping pull request creation.\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6619
6708
|
GITHUB_PR_EXIT=0
|
|
6620
6709
|
GITHUB_OPERATION_PHASE="completed"
|
|
6621
6710
|
unset token
|
|
6622
6711
|
return 0
|
|
6623
6712
|
fi
|
|
6624
6713
|
if ! is_pr_creation_mode; then
|
|
6625
|
-
printf 'Publish mode %s: skipping pull request creation.\n' "$KASEKI_PUBLISH_MODE" | tee -a /
|
|
6714
|
+
printf 'Publish mode %s: skipping pull request creation.\n' "$KASEKI_PUBLISH_MODE" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6626
6715
|
GITHUB_PR_EXIT=0
|
|
6627
6716
|
GITHUB_OPERATION_PHASE="completed"
|
|
6628
6717
|
unset token
|
|
@@ -6632,7 +6721,7 @@ run_github_operations() {
|
|
|
6632
6721
|
# Create pull request. Both pr and draft_pr push a branch and create a PR;
|
|
6633
6722
|
# only draft_pr marks the GitHub Pulls API request as draft.
|
|
6634
6723
|
GITHUB_OPERATION_PHASE="pr_creation"
|
|
6635
|
-
printf 'Creating pull request...\n' | tee -a /
|
|
6724
|
+
printf 'Creating pull request...\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6636
6725
|
emit_progress "github operations" "pr_creation_starting"
|
|
6637
6726
|
local pr_title pr_body pr_response pr_url pr_number pr_http_status pr_draft_json
|
|
6638
6727
|
pr_title="$(derive_pr_title)"
|
|
@@ -6656,7 +6745,7 @@ run_github_operations() {
|
|
|
6656
6745
|
- Generated at (UTC): $fallback_timestamp
|
|
6657
6746
|
EOF
|
|
6658
6747
|
)
|
|
6659
|
-
printf 'WARN: build_pr_body returned empty content after sanitization; using fallback PR body.\n' | tee -a /
|
|
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
|
|
6660
6749
|
fi
|
|
6661
6750
|
if is_pr_draft_mode; then
|
|
6662
6751
|
pr_draft_json=true
|
|
@@ -6670,7 +6759,7 @@ EOF
|
|
|
6670
6759
|
|
|
6671
6760
|
while [ $retry_count -le "$max_retries" ]; do
|
|
6672
6761
|
if [ $retry_count -gt 0 ]; then
|
|
6673
|
-
printf 'Retrying PR creation (attempt %d of %d) after %ds delay...\n' $((retry_count + 1)) "$max_retries" "$backoff_delay" | tee -a /
|
|
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
|
|
6674
6763
|
emit_progress "github operations" "pr_creation_attempt $((retry_count + 1))/$max_retries"
|
|
6675
6764
|
sleep "$backoff_delay"
|
|
6676
6765
|
# Exponential backoff: 2s, 4s, 8s
|
|
@@ -6680,31 +6769,31 @@ EOF
|
|
|
6680
6769
|
|
|
6681
6770
|
# Capture both response and HTTP status code
|
|
6682
6771
|
local pr_response_file temp_status_file
|
|
6683
|
-
pr_response_file="$(mktemp /tmp/kaseki-pr-response.XXXXXX)" || { printf 'Failed to create temp file for PR response\n' | tee -a /
|
|
6684
|
-
temp_status_file="$(mktemp /tmp/kaseki-pr-status.XXXXXX)" || { printf 'Failed to create temp file for PR status\n' | tee -a /
|
|
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; }
|
|
6685
6774
|
|
|
6686
6775
|
if [ $retry_count -eq 0 ] && [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6687
|
-
printf 'Debug: Creating PR with head=%s, base=%s, draft=%s\n' "$feature_branch" "$GIT_REF" "$pr_draft_json" | tee -a /
|
|
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
|
|
6688
6777
|
fi
|
|
6689
6778
|
|
|
6690
6779
|
# Encode PR title and body as JSON strings
|
|
6691
6780
|
local pr_title_json pr_body_json
|
|
6692
6781
|
pr_title_json='""'
|
|
6693
6782
|
pr_body_json='""'
|
|
6694
|
-
if ! run_node_subprocess pr_title_json "console.log(JSON.stringify(require('fs').readFileSync(0, 'utf8')))" "$pr_title" /
|
|
6695
|
-
printf 'ERROR: Failed to JSON encode PR title\n' | tee -a /
|
|
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
|
|
6696
6785
|
GITHUB_PR_EXIT=8
|
|
6697
6786
|
return 8
|
|
6698
6787
|
fi
|
|
6699
|
-
if ! run_node_subprocess pr_body_json "console.log(JSON.stringify(require('fs').readFileSync(0, 'utf8')))" "$pr_body" /
|
|
6700
|
-
printf 'ERROR: Failed to JSON encode PR body\n' | tee -a /
|
|
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
|
|
6701
6790
|
GITHUB_PR_EXIT=8
|
|
6702
6791
|
return 8
|
|
6703
6792
|
fi
|
|
6704
6793
|
|
|
6705
6794
|
# Validate both variables are non-empty before using in curl
|
|
6706
6795
|
if [ -z "$pr_title_json" ] || [ -z "$pr_body_json" ]; then
|
|
6707
|
-
printf 'ERROR: JSON encoding produced empty values (title=%s, body=%s)\n' "$pr_title_json" "$pr_body_json" | tee -a /
|
|
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
|
|
6708
6797
|
GITHUB_PR_EXIT=8
|
|
6709
6798
|
return 8
|
|
6710
6799
|
fi
|
|
@@ -6729,7 +6818,7 @@ EOF
|
|
|
6729
6818
|
|
|
6730
6819
|
if [ $curl_exit -ne 0 ]; then
|
|
6731
6820
|
# curl command itself failed (network error, timeout, etc.)
|
|
6732
|
-
printf 'GitHub PR API curl command failed with exit code %d (attempt %d)\n' "$curl_exit" $((retry_count + 1)) | tee -a /
|
|
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
|
|
6733
6822
|
GITHUB_API_HTTP_STATUS="0"
|
|
6734
6823
|
if is_github_pr_error_retryable "0" "curl_error" && [ "$retry_count" -lt "$((max_retries - 1))" ]; then
|
|
6735
6824
|
retry_count=$((retry_count + 1))
|
|
@@ -6747,43 +6836,43 @@ EOF
|
|
|
6747
6836
|
fi
|
|
6748
6837
|
|
|
6749
6838
|
if [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6750
|
-
printf 'Debug: PR API response HTTP status: %s (attempt %d)\n' "$pr_http_status" $((retry_count + 1)) | tee -a /
|
|
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
|
|
6751
6840
|
fi
|
|
6752
6841
|
|
|
6753
6842
|
# Validate the API response
|
|
6754
|
-
if validate_github_api_response "$pr_http_status" "$pr_response" /
|
|
6843
|
+
if validate_github_api_response "$pr_http_status" "$pr_response" ${KASEKI_RESULTS_DIR}/git-push.log; then
|
|
6755
6844
|
# API returned success (201); now extract the URL and issue number using helper
|
|
6756
|
-
if ! run_node_subprocess pr_url "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); process.stdout.write(d.html_url || '')" "$pr_response" /
|
|
6757
|
-
printf 'ERROR: Failed to extract PR URL from API response\n' | tee -a /
|
|
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
|
|
6758
6847
|
emit_error_event "github_pr_response_malformed" "Failed to parse PR API response to extract html_url" "exit"
|
|
6759
6848
|
GITHUB_PR_EXIT=9
|
|
6760
6849
|
pr_url=""
|
|
6761
6850
|
fi
|
|
6762
|
-
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" /
|
|
6763
|
-
printf 'Warning: failed to extract PR number from API response; leaving PR unlabeled\n' | tee -a /
|
|
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
|
|
6764
6853
|
pr_number=""
|
|
6765
6854
|
fi
|
|
6766
6855
|
|
|
6767
6856
|
if [ -n "$pr_url" ]; then
|
|
6768
6857
|
GITHUB_PR_URL="$pr_url"
|
|
6769
6858
|
GITHUB_PR_EXIT=0
|
|
6770
|
-
printf 'Pull request created: %s\n' "$pr_url" | tee -a /
|
|
6859
|
+
printf 'Pull request created: %s\n' "$pr_url" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6771
6860
|
if [ -n "$pr_number" ]; then
|
|
6772
|
-
apply_github_pr_labels "$owner" "$repo" "$pr_number" "$token" /
|
|
6861
|
+
apply_github_pr_labels "$owner" "$repo" "$pr_number" "$token" ${KASEKI_RESULTS_DIR}/git-push.log || true
|
|
6773
6862
|
# Request repository owner as reviewer for personal repos
|
|
6774
|
-
request_owner_review "$pr_response" "$token" /
|
|
6863
|
+
request_owner_review "$pr_response" "$token" ${KASEKI_RESULTS_DIR}/git-push.log || true
|
|
6775
6864
|
else
|
|
6776
|
-
printf 'Warning: PR API response missing number field; leaving PR unlabeled\n' | tee -a /
|
|
6865
|
+
printf 'Warning: PR API response missing number field; leaving PR unlabeled\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6777
6866
|
fi
|
|
6778
6867
|
pr_created=1
|
|
6779
6868
|
rm -f "$pr_response_file"
|
|
6780
6869
|
break
|
|
6781
6870
|
else
|
|
6782
6871
|
# HTTP 201 but no html_url in response - malformed response
|
|
6783
|
-
printf 'Pull request API returned success (201) but response missing html_url field\n' | tee -a /
|
|
6872
|
+
printf 'Pull request API returned success (201) but response missing html_url field\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6784
6873
|
emit_error_event "github_pr_response_malformed" "GitHub PR API returned 201 but response missing html_url field" "exit"
|
|
6785
6874
|
if [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6786
|
-
printf 'Debug: Full API response:\n%s\n' "$pr_response" | tee -a /
|
|
6875
|
+
printf 'Debug: Full API response:\n%s\n' "$pr_response" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6787
6876
|
fi
|
|
6788
6877
|
GITHUB_PR_EXIT=9
|
|
6789
6878
|
pr_created=0
|
|
@@ -6793,17 +6882,17 @@ EOF
|
|
|
6793
6882
|
else
|
|
6794
6883
|
# API returned an error
|
|
6795
6884
|
if is_github_pr_error_retryable "$pr_http_status" "$GITHUB_API_ERROR_TYPE" && [ "$retry_count" -lt "$((max_retries - 1))" ]; then
|
|
6796
|
-
printf 'GitHub API returned retryable error (attempt %d): %s (HTTP %s)\n' $((retry_count + 1)) "$GITHUB_API_ERROR_TYPE" "$pr_http_status" | tee -a /
|
|
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
|
|
6797
6886
|
retry_count=$((retry_count + 1))
|
|
6798
6887
|
rm -f "$pr_response_file"
|
|
6799
6888
|
continue
|
|
6800
6889
|
else
|
|
6801
6890
|
# Permanent error, give up
|
|
6802
|
-
printf 'Failed to create PR. API error: %s\n' "$GITHUB_API_ERROR_MESSAGE" | tee -a /
|
|
6891
|
+
printf 'Failed to create PR. API error: %s\n' "$GITHUB_API_ERROR_MESSAGE" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6803
6892
|
emit_error_event "github_pr_api_failed" "GitHub API error ($GITHUB_API_ERROR_TYPE): $GITHUB_API_ERROR_MESSAGE (HTTP $GITHUB_API_HTTP_STATUS)" "exit"
|
|
6804
6893
|
if [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6805
|
-
printf 'Debug: API error type: %s, HTTP status: %s\n' "$GITHUB_API_ERROR_TYPE" "$GITHUB_API_HTTP_STATUS" | tee -a /
|
|
6806
|
-
printf 'Debug: Full response:\n%s\n' "$pr_response" | tee -a /
|
|
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
|
|
6807
6896
|
fi
|
|
6808
6897
|
GITHUB_PR_EXIT=9
|
|
6809
6898
|
pr_created=0
|
|
@@ -6836,7 +6925,7 @@ if [ "$GITHUB_APP_ENABLED" = "1" ]; then
|
|
|
6836
6925
|
printf 'ERROR: GitHub operations preflight health check failed\n' >&2
|
|
6837
6926
|
printf 'GitHub App is enabled but configuration or dependencies are missing.\n' >&2
|
|
6838
6927
|
printf 'Proceeding with kaseki run, but GitHub operations will be skipped or fail.\n' >&2
|
|
6839
|
-
emit_error_event "github_preflight_failed" "GitHub operations health check failed; check /
|
|
6928
|
+
emit_error_event "github_preflight_failed" "GitHub operations health check failed; check ${KASEKI_RESULTS_DIR}/github-health-check.log for details" "continue"
|
|
6840
6929
|
fi
|
|
6841
6930
|
fi
|
|
6842
6931
|
|
|
@@ -6860,7 +6949,7 @@ unset OPENROUTER_API_KEY secret_content
|
|
|
6860
6949
|
if [ -z "$openrouter_api_key" ]; then
|
|
6861
6950
|
set_current_stage "agent setup"
|
|
6862
6951
|
openrouter_api_key_file="${OPENROUTER_API_KEY_FILE:-/agents/secrets/openrouter_api_key}"
|
|
6863
|
-
printf 'Missing OpenRouter API key. Set OPENROUTER_API_KEY or provide %s.\n' "$openrouter_api_key_file" | tee -a /
|
|
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
|
|
6864
6953
|
: > "$RAW_EVENTS"
|
|
6865
6954
|
PI_EXIT=2
|
|
6866
6955
|
STATUS=2
|
|
@@ -6871,7 +6960,7 @@ fi
|
|
|
6871
6960
|
if ! run_clone_repository; then
|
|
6872
6961
|
exit 0
|
|
6873
6962
|
fi
|
|
6874
|
-
cd /
|
|
6963
|
+
cd ${KASEKI_WORKSPACE_DIR}/repo || { STATUS=1; FAILED_COMMAND="enter repository"; exit "$STATUS"; }
|
|
6875
6964
|
|
|
6876
6965
|
prepare_dependencies() {
|
|
6877
6966
|
if [ ! -f package.json ]; then
|
|
@@ -7101,7 +7190,7 @@ if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ] && [ "$KASEKI_PRE_AGENT_VALID
|
|
|
7101
7190
|
emit_progress "baseline validation cache" "failed to save (non-blocking)"
|
|
7102
7191
|
fi
|
|
7103
7192
|
# Cleanup baseline workspace to save space
|
|
7104
|
-
rm -rf
|
|
7193
|
+
rm -rf ${KASEKI_WORKSPACE_BASELINE_DIR} 2>/dev/null || true
|
|
7105
7194
|
else
|
|
7106
7195
|
BASELINE_CACHE_STATUS="checkout_failed"
|
|
7107
7196
|
emit_error_event "baseline_checkout_failed" "Failed to setup baseline for test failure comparison; continuing without baseline" "continue"
|
|
@@ -7118,13 +7207,13 @@ if [ "$KASEKI_PRE_AGENT_VALIDATION" = "0" ]; then
|
|
|
7118
7207
|
printf '\n==> pre-agent validation\n'
|
|
7119
7208
|
set_current_stage "pre-agent validation"
|
|
7120
7209
|
emit_progress "pre-agent validation" "skipped by KASEKI_PRE_AGENT_VALIDATION=0"
|
|
7121
|
-
printf 'Pre-agent validation skipped because KASEKI_PRE_AGENT_VALIDATION=0.\n' | tee -a /
|
|
7210
|
+
printf 'Pre-agent validation skipped because KASEKI_PRE_AGENT_VALIDATION=0.\n' | tee -a ${KASEKI_RESULTS_DIR}/pre-validation.log
|
|
7122
7211
|
record_stage_timing "pre-agent validation" 0 0 "skipped_by_config"
|
|
7123
7212
|
else
|
|
7124
7213
|
run_validation_commands \
|
|
7125
7214
|
"pre-agent validation" \
|
|
7126
7215
|
"$KASEKI_PRE_AGENT_VALIDATION_COMMANDS" \
|
|
7127
|
-
/
|
|
7216
|
+
${KASEKI_RESULTS_DIR}/pre-validation.log \
|
|
7128
7217
|
"$PRE_VALIDATION_RAW_LOG" \
|
|
7129
7218
|
"$PRE_VALIDATION_TIMINGS_FILE" \
|
|
7130
7219
|
"$PRE_VALIDATION_ENV_LOG" \
|
|
@@ -7153,7 +7242,7 @@ set_current_stage "typescript precheck"
|
|
|
7153
7242
|
if ! run_typescript_precheck; then
|
|
7154
7243
|
if [ "$KASEKI_SCOUTING" = "1" ]; then
|
|
7155
7244
|
# If scouting is enabled (experimental path), continue anyway with warning
|
|
7156
|
-
printf 'WARNING: TypeScript pre-check failed, but continuing due to scouting mode being enabled.\n' | tee -a /
|
|
7245
|
+
printf 'WARNING: TypeScript pre-check failed, but continuing due to scouting mode being enabled.\n' | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
7157
7246
|
else
|
|
7158
7247
|
# Without scouting, TypeScript failures are fatal
|
|
7159
7248
|
STATUS="$TS_PRE_CHECK_EXIT"
|
|
@@ -7169,16 +7258,16 @@ printf 'Pi version: %s\n' "$PI_VERSION"
|
|
|
7169
7258
|
# === Phase 1: Early Filesystem Diagnostics (Before Scouting) ===
|
|
7170
7259
|
# Detects read-only filesystem constraints that would cause silent scouting failures
|
|
7171
7260
|
check_filesystem_capabilities() {
|
|
7172
|
-
local results_dir="${KASEKI_RESULTS_DIR
|
|
7261
|
+
local results_dir="${KASEKI_RESULTS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
7173
7262
|
local filesystem_writable=true
|
|
7174
7263
|
local readonly_reason=""
|
|
7175
7264
|
|
|
7176
7265
|
emit_progress "filesystem capabilities check" "verifying write capabilities for artifacts"
|
|
7177
7266
|
|
|
7178
|
-
# Test /
|
|
7267
|
+
# Test ${KASEKI_RESULTS_DIR}/ writability
|
|
7179
7268
|
if [ ! -w "$results_dir" ]; then
|
|
7180
7269
|
filesystem_writable=false
|
|
7181
|
-
readonly_reason="
|
|
7270
|
+
readonly_reason="${KASEKI_RESULTS_DIR} is READ-ONLY (Docker mounted with :ro or container --read-only flag)"
|
|
7182
7271
|
emit_error_event "readonly_filesystem_detected" "$readonly_reason" "continue"
|
|
7183
7272
|
{
|
|
7184
7273
|
printf '\n[FILESYSTEM DIAGNOSTIC] READ-ONLY FILESYSTEM DETECTED\n'
|
|
@@ -7188,35 +7277,35 @@ check_filesystem_capabilities() {
|
|
|
7188
7277
|
printf ' - Container UID: %d\n' "$(id -u)"
|
|
7189
7278
|
printf ' - Expected reason: Docker mounted with :ro flag or container --read-only\n'
|
|
7190
7279
|
printf '\nImpact:\n'
|
|
7191
|
-
printf ' - Scouting Pi agent will exit 0 but /
|
|
7280
|
+
printf ' - Scouting Pi agent will exit 0 but ${KASEKI_RESULTS_DIR}/scouting-candidate.json will be MISSING\n'
|
|
7192
7281
|
printf ' - Validation logs and artifacts cannot be written\n'
|
|
7193
7282
|
printf ' - This causes exit code 86 (scouting validation failure)\n'
|
|
7194
|
-
printf '\nFix: Remount
|
|
7195
|
-
printf ' docker run -v /path/to
|
|
7283
|
+
printf '\nFix: Remount ${KASEKI_RESULTS_DIR} as read-write\n'
|
|
7284
|
+
printf ' docker run -v /path/to${KASEKI_RESULTS_DIR}:${KASEKI_RESULTS_DIR}:rw ...\n'
|
|
7196
7285
|
printf 'Or remove --read-only flag from Docker run command\n'
|
|
7197
|
-
} | tee -a /
|
|
7286
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
7198
7287
|
else
|
|
7199
7288
|
# Test actual write capability
|
|
7200
7289
|
local test_file="$results_dir/.kaseki-fs-test-$$"
|
|
7201
7290
|
if ! touch "$test_file" 2>/dev/null; then
|
|
7202
7291
|
filesystem_writable=false
|
|
7203
|
-
readonly_reason="
|
|
7292
|
+
readonly_reason="${KASEKI_RESULTS_DIR} is not writable (touch failed despite appearing writable)"
|
|
7204
7293
|
emit_error_event "filesystem_write_test_failed" "$readonly_reason" "continue"
|
|
7205
7294
|
else
|
|
7206
7295
|
rm -f "$test_file" 2>/dev/null || true
|
|
7207
|
-
emit_progress "filesystem capabilities check" "✓
|
|
7296
|
+
emit_progress "filesystem capabilities check" "✓ ${KASEKI_RESULTS_DIR} is writable"
|
|
7208
7297
|
fi
|
|
7209
7298
|
fi
|
|
7210
7299
|
|
|
7211
7300
|
# Record in metadata for post-mortem analysis
|
|
7212
|
-
printf '%s\n' "$filesystem_writable" > /
|
|
7213
|
-
[ -n "$readonly_reason" ] && printf '%s\n' "$readonly_reason" > /
|
|
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
|
|
7214
7303
|
|
|
7215
7304
|
if [ "$filesystem_writable" = "false" ]; then
|
|
7216
7305
|
if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ]; then
|
|
7217
7306
|
emit_progress "baseline validation preparation" "DISABLED due to read-only filesystem detected"
|
|
7218
7307
|
KASEKI_BASELINE_VALIDATION_ENABLED="0"
|
|
7219
|
-
printf '[filesystem-diagnostic] Baseline validation auto-disabled due to read-only filesystem\n' | tee -a /
|
|
7308
|
+
printf '[filesystem-diagnostic] Baseline validation auto-disabled due to read-only filesystem\n' | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
7220
7309
|
fi
|
|
7221
7310
|
return 1
|
|
7222
7311
|
fi
|
|
@@ -7266,7 +7355,7 @@ if [ "$KASEKI_SCOUTING" = "1" ] && [ -f "$SCOUTING_ARTIFACT" ]; then
|
|
|
7266
7355
|
export KASEKI_VALIDATION_ALLOWLIST="$merged_validation_allowlist"
|
|
7267
7356
|
|
|
7268
7357
|
# Log merge decisions with structured JSON construction so pattern text is escaped safely.
|
|
7269
|
-
append_jsonl_object /
|
|
7358
|
+
append_jsonl_object ${KASEKI_RESULTS_DIR}/metadata.jsonl \
|
|
7270
7359
|
"timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
7271
7360
|
"event=allowlist_merge" \
|
|
7272
7361
|
"scouting_agent_patterns=$scouting_agent_patterns" \
|
|
@@ -7279,14 +7368,14 @@ if [ "$KASEKI_SCOUTING" = "1" ] && [ -f "$SCOUTING_ARTIFACT" ]; then
|
|
|
7279
7368
|
allowlist_merge_status="merged"
|
|
7280
7369
|
|
|
7281
7370
|
# Run coverage validation with dry-run
|
|
7282
|
-
if [ -s /
|
|
7283
|
-
run_scouting_allowlist_coverage "$SCOUTING_ARTIFACT" 2>&1 | tee -a /
|
|
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
|
|
7284
7373
|
fi
|
|
7285
7374
|
|
|
7286
7375
|
emit_progress "derive allowlist from scouting" "finished (status=$allowlist_merge_status)"
|
|
7287
7376
|
else
|
|
7288
7377
|
# Pattern validation failed - fail fast
|
|
7289
|
-
printf 'ERROR: Derived allowlist patterns failed validation. Cannot proceed.\n' | tee -a /
|
|
7378
|
+
printf 'ERROR: Derived allowlist patterns failed validation. Cannot proceed.\n' | tee -a ${KASEKI_RESULTS_DIR}/quality.log >&2
|
|
7290
7379
|
STATUS=86
|
|
7291
7380
|
FAILED_COMMAND="allowlist pattern validation"
|
|
7292
7381
|
emit_error_event "scouting_allowlist_invalid" "Derived allowlist patterns failed validation" "exit"
|
|
@@ -7294,7 +7383,7 @@ if [ "$KASEKI_SCOUTING" = "1" ] && [ -f "$SCOUTING_ARTIFACT" ]; then
|
|
|
7294
7383
|
fi
|
|
7295
7384
|
else
|
|
7296
7385
|
# Derivation failed - log and fail fast
|
|
7297
|
-
printf 'ERROR: Failed to derive allowlist from scouting artifact: %s\n' "$scouting_output" | tee -a /
|
|
7386
|
+
printf 'ERROR: Failed to derive allowlist from scouting artifact: %s\n' "$scouting_output" | tee -a ${KASEKI_RESULTS_DIR}/quality.log >&2
|
|
7298
7387
|
STATUS=86
|
|
7299
7388
|
FAILED_COMMAND="allowlist derivation from scouting"
|
|
7300
7389
|
emit_error_event "scouting_allowlist_derivation_failed" "Failed to derive allowlist from scouting artifact" "exit"
|
|
@@ -7332,7 +7421,7 @@ if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
|
7332
7421
|
printf ' Model: %s\n' "$KASEKI_MODEL"
|
|
7333
7422
|
printf ' Timeout: %s seconds\n' "$KASEKI_AGENT_TIMEOUT_SECONDS"
|
|
7334
7423
|
printf ' Task: %s\n' "$TASK_PROMPT"
|
|
7335
|
-
} | tee -a /
|
|
7424
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log
|
|
7336
7425
|
emit_progress "pi coding agent" "skipped (dry-run)"
|
|
7337
7426
|
record_stage_timing "pi coding agent" "0" "$PI_DURATION_SECONDS" "dry_run=true"
|
|
7338
7427
|
else
|
|
@@ -7344,9 +7433,9 @@ else
|
|
|
7344
7433
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
7345
7434
|
timeout --signal=SIGTERM "$KASEKI_AGENT_TIMEOUT_SECONDS" \
|
|
7346
7435
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_MODEL" "$agent_prompt" \
|
|
7347
|
-
2> >(tee -a /
|
|
7436
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log >&2) \
|
|
7348
7437
|
| tee "$RAW_EVENTS" \
|
|
7349
|
-
| kaseki-pi-progress-stream /
|
|
7438
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
7350
7439
|
PI_EXIT="${PIPESTATUS[0]}"
|
|
7351
7440
|
unset agent_prompt
|
|
7352
7441
|
PI_DURATION_SECONDS=$(($(date +%s) - PI_START_EPOCH))
|
|
@@ -7355,7 +7444,7 @@ else
|
|
|
7355
7444
|
record_stage_timing "pi coding agent" "$PI_EXIT" "$PI_DURATION_SECONDS" "timeout_seconds=$KASEKI_AGENT_TIMEOUT_SECONDS"
|
|
7356
7445
|
|
|
7357
7446
|
if [ "$KASEKI_DEBUG_RAW_EVENTS" = "1" ]; then
|
|
7358
|
-
cp "$RAW_EVENTS" /
|
|
7447
|
+
cp "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.raw.jsonl
|
|
7359
7448
|
fi
|
|
7360
7449
|
|
|
7361
7450
|
PI_EXTRACTION_DEPS_OK=1
|
|
@@ -7366,7 +7455,7 @@ else
|
|
|
7366
7455
|
missing_executables+=("$required_exec")
|
|
7367
7456
|
fi
|
|
7368
7457
|
done
|
|
7369
|
-
for helper_file in /
|
|
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
|
|
7370
7459
|
if [ ! -f "$helper_file" ]; then
|
|
7371
7460
|
missing_helpers+=("$helper_file")
|
|
7372
7461
|
fi
|
|
@@ -7379,34 +7468,34 @@ else
|
|
|
7379
7468
|
[ -z "$missing_helpers_joined" ] && missing_helpers_joined="none"
|
|
7380
7469
|
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")
|
|
7381
7470
|
printf '%s
|
|
7382
|
-
' "$extraction_error" | tee -a /
|
|
7471
|
+
' "$extraction_error" | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log ${KASEKI_RESULTS_DIR}/quality.log >&2
|
|
7383
7472
|
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"
|
|
7384
7473
|
if [ "$STATUS" -eq 0 ]; then
|
|
7385
7474
|
STATUS=87
|
|
7386
7475
|
FAILED_COMMAND="pi artifact extraction dependency validation"
|
|
7387
7476
|
fi
|
|
7388
|
-
cp "$RAW_EVENTS" /
|
|
7477
|
+
cp "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.raw.jsonl 2>/dev/null || true
|
|
7389
7478
|
fi
|
|
7390
7479
|
|
|
7391
7480
|
FILTER_EXIT=0
|
|
7392
7481
|
if [ "$PI_EXTRACTION_DEPS_OK" -eq 1 ]; then
|
|
7393
7482
|
set +e
|
|
7394
|
-
kaseki-pi-event-filter "$RAW_EVENTS" /
|
|
7483
|
+
kaseki-pi-event-filter "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.jsonl ${KASEKI_RESULTS_DIR}/pi-summary.json
|
|
7395
7484
|
FILTER_EXIT=$?
|
|
7396
7485
|
set +e
|
|
7397
7486
|
fi
|
|
7398
7487
|
if [ "$FILTER_EXIT" -ne 0 ]; then
|
|
7399
|
-
printf 'pi-event-filter failed with exit %s; raw events preserved as fallback artifact\n' "$FILTER_EXIT" | tee -a /
|
|
7400
|
-
printf 'ERROR: kaseki-pi-event-filter failed with exit %s while exporting Pi events\n' "$FILTER_EXIT" | tee -a /
|
|
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
|
|
7401
7490
|
emit_error_event "pi_event_filter_failed" "kaseki-pi-event-filter exited with code $FILTER_EXIT" "continue"
|
|
7402
7491
|
if [ "$STATUS" -eq 0 ]; then
|
|
7403
7492
|
STATUS="$FILTER_EXIT"
|
|
7404
7493
|
FAILED_COMMAND="kaseki-pi-event-filter"
|
|
7405
7494
|
fi
|
|
7406
|
-
cp "$RAW_EVENTS" /
|
|
7495
|
+
cp "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.raw.jsonl 2>/dev/null || true
|
|
7407
7496
|
fi
|
|
7408
|
-
if [ -s "$RAW_EVENTS" ] && { [ ! -s /
|
|
7409
|
-
printf 'ERROR: pi event export incomplete; raw events are non-empty but event artifacts are missing/empty\n' | tee -a /
|
|
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
|
|
7410
7499
|
emit_error_event "pi_event_export_incomplete" "RAW_EVENTS has data but exported artifacts are empty or missing" "continue"
|
|
7411
7500
|
if [ "$STATUS" -eq 0 ]; then
|
|
7412
7501
|
STATUS=86
|
|
@@ -7415,16 +7504,16 @@ else
|
|
|
7415
7504
|
fi
|
|
7416
7505
|
|
|
7417
7506
|
# Process hashline_edit events (non-fatal phase; failures don't block pipeline)
|
|
7418
|
-
if [ "$KASEKI_HASHLINE_EDITS" != "0" ] && [ -s /
|
|
7507
|
+
if [ "$KASEKI_HASHLINE_EDITS" != "0" ] && [ -s ${KASEKI_RESULTS_DIR}/pi-events.jsonl ]; then
|
|
7419
7508
|
emit_progress "hashline validation" "started"
|
|
7420
7509
|
HASHLINE_EXIT=0
|
|
7421
7510
|
set +e
|
|
7422
|
-
npx tsx /
|
|
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
|
|
7423
7512
|
HASHLINE_EXIT=$?
|
|
7424
7513
|
set +e
|
|
7425
7514
|
|
|
7426
7515
|
if [ "$HASHLINE_EXIT" -ne 0 ]; then
|
|
7427
|
-
printf 'Warning: hashline validation exited with code %s (non-fatal; continuing pipeline)\n' "$HASHLINE_EXIT" | tee -a /
|
|
7516
|
+
printf 'Warning: hashline validation exited with code %s (non-fatal; continuing pipeline)\n' "$HASHLINE_EXIT" | tee -a ${KASEKI_RESULTS_DIR}/hashline-validation.log
|
|
7428
7517
|
emit_event "warning" "warning_type=hashline_validation_failed" "detail=hashline_edit processing exited with code $HASHLINE_EXIT"
|
|
7429
7518
|
else
|
|
7430
7519
|
emit_progress "hashline validation" "completed"
|
|
@@ -7455,7 +7544,7 @@ else
|
|
|
7455
7544
|
}
|
|
7456
7545
|
var m='';
|
|
7457
7546
|
try{
|
|
7458
|
-
var summary=require('/
|
|
7547
|
+
var summary=require('${KASEKI_RESULTS_DIR}/pi-summary.json');
|
|
7459
7548
|
m=clean(summary.selected_model)||clean(summary.model)||fromSummaryModels(summary);
|
|
7460
7549
|
}catch{}
|
|
7461
7550
|
if(!m){
|
|
@@ -7481,7 +7570,7 @@ fi
|
|
|
7481
7570
|
|
|
7482
7571
|
if [ "$KASEKI_DRY_RUN" != "1" ]; then
|
|
7483
7572
|
if [ "$PI_EXIT" -eq 124 ]; then
|
|
7484
|
-
printf 'pi timeout after %ss (exit 124)\n' "$KASEKI_AGENT_TIMEOUT_SECONDS" | tee -a /
|
|
7573
|
+
printf 'pi timeout after %ss (exit 124)\n' "$KASEKI_AGENT_TIMEOUT_SECONDS" | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log >&2
|
|
7485
7574
|
if [ "$STATUS" -eq 0 ]; then
|
|
7486
7575
|
STATUS=124
|
|
7487
7576
|
FAILED_COMMAND="pi coding agent timeout"
|
|
@@ -7520,11 +7609,11 @@ printf '\n==> quality checks\n'
|
|
|
7520
7609
|
set_current_stage "quality checks"
|
|
7521
7610
|
emit_progress "quality checks" "started"
|
|
7522
7611
|
stage_start="$(date +%s)"
|
|
7523
|
-
diff_size="$(wc -c < /
|
|
7612
|
+
diff_size="$(wc -c < ${KASEKI_RESULTS_DIR}/git.diff | tr -d ' ')"
|
|
7524
7613
|
if [ "$diff_size" -gt "$KASEKI_MAX_DIFF_BYTES" ]; then
|
|
7525
7614
|
QUALITY_EXIT=4
|
|
7526
7615
|
QUALITY_FAILURE_REASON="max_diff_bytes: $diff_size bytes exceeds limit of $KASEKI_MAX_DIFF_BYTES bytes"
|
|
7527
|
-
printf 'git.diff is too large: %s bytes > %s bytes\n' "$diff_size" "$KASEKI_MAX_DIFF_BYTES" | tee -a /
|
|
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
|
|
7528
7617
|
emit_event "quality_gate_rule_evaluated" "rule=max_diff_bytes" "passed=false" "actual=$diff_size" "limit=$KASEKI_MAX_DIFF_BYTES"
|
|
7529
7618
|
else
|
|
7530
7619
|
emit_event "quality_gate_rule_evaluated" "rule=max_diff_bytes" "passed=true" "actual=$diff_size" "limit=$KASEKI_MAX_DIFF_BYTES"
|
|
@@ -7539,17 +7628,17 @@ if [ -n "$allowlist_regex" ]; then
|
|
|
7539
7628
|
if ! printf '%s\n' "$changed_file" | grep -Eq "^(${allowlist_regex})$"; then
|
|
7540
7629
|
QUALITY_EXIT=5
|
|
7541
7630
|
QUALITY_FAILURE_REASON="allowlist_check: file '$changed_file' not in allowlist"
|
|
7542
|
-
printf 'changed file outside allowlist: %s\n' "$changed_file" | tee -a /
|
|
7631
|
+
printf 'changed file outside allowlist: %s\n' "$changed_file" | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
7543
7632
|
emit_event "quality_gate_rule_evaluated" "rule=allowlist_check" "passed=false" "file=$changed_file"
|
|
7544
7633
|
else
|
|
7545
7634
|
emit_event "quality_gate_rule_evaluated" "rule=allowlist_check" "passed=true" "file=$changed_file"
|
|
7546
7635
|
fi
|
|
7547
|
-
done < /
|
|
7636
|
+
done < ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
7548
7637
|
fi
|
|
7549
7638
|
|
|
7550
7639
|
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
|
|
7551
7640
|
format_command="npm run format:check"
|
|
7552
|
-
printf '%s\n' "$format_command" >> /
|
|
7641
|
+
printf '%s\n' "$format_command" >> ${KASEKI_RESULTS_DIR}/format-check-command.txt
|
|
7553
7642
|
fi
|
|
7554
7643
|
record_stage_timing "quality checks" "$QUALITY_EXIT" "$(($(date +%s) - stage_start))" "diff_size_bytes=$diff_size"
|
|
7555
7644
|
|
|
@@ -7558,7 +7647,7 @@ run_expectation_mismatch_detector
|
|
|
7558
7647
|
|
|
7559
7648
|
pre_validation_goal_check_diff_hash=""
|
|
7560
7649
|
if [ "$STATUS" -eq 0 ] && [ "$PI_EXIT" -eq 0 ] && [ "$QUALITY_EXIT" -eq 0 ]; then
|
|
7561
|
-
pre_validation_goal_check_diff_hash="$(sha256sum /
|
|
7650
|
+
pre_validation_goal_check_diff_hash="$(sha256sum ${KASEKI_RESULTS_DIR}/git.diff 2>/dev/null | awk '{print $1}')"
|
|
7562
7651
|
run_goal_check "$coding_attempt"
|
|
7563
7652
|
collect_goal_check_feedback "$INSTANCE_NAME"
|
|
7564
7653
|
snapshot_attempt_artifacts "$coding_attempt"
|
|
@@ -7590,18 +7679,18 @@ log_validation_environment() {
|
|
|
7590
7679
|
printf '[validation environment] PATH=%s\n' "$PATH"
|
|
7591
7680
|
printf '[validation environment] NODE_OPTIONS=%s\n' "${NODE_OPTIONS:-<not set>}"
|
|
7592
7681
|
printf '[validation environment] NODE_PATH=%s\n' "${NODE_PATH:-<not set>}"
|
|
7593
|
-
printf '[validation environment] disk_space_available=%s\n' "$(df -h
|
|
7594
|
-
printf '[validation environment] disk_space_used=%s\n' "$(du -sh
|
|
7595
|
-
} | tee -a /
|
|
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"
|
|
7596
7685
|
}
|
|
7597
7686
|
log_validation_environment
|
|
7598
|
-
collect_changed_file_state /
|
|
7687
|
+
collect_changed_file_state ${KASEKI_RESULTS_DIR}/validation-before-state.txt
|
|
7599
7688
|
|
|
7600
7689
|
if [ "$KASEKI_DRY_RUN" = "1" ] || [ -z "$KASEKI_VALIDATION_COMMANDS" ] || [ "$KASEKI_VALIDATION_COMMANDS" = "none" ]; then
|
|
7601
7690
|
run_validation_commands \
|
|
7602
7691
|
"validation" \
|
|
7603
7692
|
"$KASEKI_VALIDATION_COMMANDS" \
|
|
7604
|
-
/
|
|
7693
|
+
${KASEKI_RESULTS_DIR}/validation.log \
|
|
7605
7694
|
"$VALIDATION_RAW_LOG" \
|
|
7606
7695
|
"$VALIDATION_TIMINGS_FILE" \
|
|
7607
7696
|
"$VALIDATION_ENV_LOG" \
|
|
@@ -7610,7 +7699,7 @@ elif [ "$QUALITY_EXIT" -ne 0 ]; then
|
|
|
7610
7699
|
printf '\n==> validation\n'
|
|
7611
7700
|
set_current_stage "validation"
|
|
7612
7701
|
emit_progress "validation" "started"
|
|
7613
|
-
printf 'Validation skipped because quality gates failed with exit %s.\n' "$QUALITY_EXIT" | tee -a /
|
|
7702
|
+
printf 'Validation skipped because quality gates failed with exit %s.\n' "$QUALITY_EXIT" | tee -a ${KASEKI_RESULTS_DIR}/validation.log
|
|
7614
7703
|
VALIDATION_EXIT="$QUALITY_EXIT"
|
|
7615
7704
|
if [ -z "$VALIDATION_FAILURE_REASON" ]; then
|
|
7616
7705
|
VALIDATION_FAILURE_REASON="quality_gate_failed: $QUALITY_FAILURE_REASON"
|
|
@@ -7621,14 +7710,14 @@ elif [ "$PI_EXIT" -ne 0 ] && [ "$KASEKI_VALIDATE_AFTER_AGENT_FAILURE" != "1" ];
|
|
|
7621
7710
|
printf '\n==> validation\n'
|
|
7622
7711
|
set_current_stage "validation"
|
|
7623
7712
|
emit_progress "validation" "started"
|
|
7624
|
-
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 /
|
|
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
|
|
7625
7714
|
record_stage_timing "validation" "$PI_EXIT" 0 "skipped_after_agent_failure"
|
|
7626
7715
|
emit_progress "validation" "finished with exit $VALIDATION_EXIT"
|
|
7627
7716
|
else
|
|
7628
7717
|
run_validation_commands \
|
|
7629
7718
|
"validation" \
|
|
7630
7719
|
"$KASEKI_VALIDATION_COMMANDS" \
|
|
7631
|
-
/
|
|
7720
|
+
${KASEKI_RESULTS_DIR}/validation.log \
|
|
7632
7721
|
"$VALIDATION_RAW_LOG" \
|
|
7633
7722
|
"$VALIDATION_TIMINGS_FILE" \
|
|
7634
7723
|
"$VALIDATION_ENV_LOG" \
|
|
@@ -7642,18 +7731,18 @@ fi
|
|
|
7642
7731
|
|
|
7643
7732
|
# Check validation-phase allowlist (if configured)
|
|
7644
7733
|
if [ "$VALIDATION_EXIT" -eq 0 ]; then
|
|
7645
|
-
collect_changed_file_state /
|
|
7734
|
+
collect_changed_file_state ${KASEKI_RESULTS_DIR}/validation-after-state.txt
|
|
7646
7735
|
collect_git_artifacts
|
|
7647
7736
|
if ! check_validation_allowlist; then
|
|
7648
7737
|
: # Exit code already set in check_validation_allowlist
|
|
7649
7738
|
fi
|
|
7650
7739
|
fi
|
|
7651
7740
|
|
|
7652
|
-
post_validation_goal_check_diff_hash="$(sha256sum /
|
|
7741
|
+
post_validation_goal_check_diff_hash="$(sha256sum ${KASEKI_RESULTS_DIR}/git.diff 2>/dev/null | awk '{print $1}')"
|
|
7653
7742
|
if [ "$STATUS" -eq 0 ] && [ "$PI_EXIT" -eq 0 ] && [ "$QUALITY_EXIT" -eq 0 ] && [ "$VALIDATION_EXIT" -eq 0 ] && \
|
|
7654
7743
|
[ -n "$pre_validation_goal_check_diff_hash" ] && [ -n "$post_validation_goal_check_diff_hash" ] && \
|
|
7655
7744
|
[ "$post_validation_goal_check_diff_hash" != "$pre_validation_goal_check_diff_hash" ]; then
|
|
7656
|
-
printf 'Validation commands changed the final git diff; re-running goal check against post-validation artifacts.\n' | tee -a /
|
|
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
|
|
7657
7746
|
emit_progress "goal check" "re-running after validation changed the final diff (attempt $coding_attempt)"
|
|
7658
7747
|
run_goal_check "$coding_attempt"
|
|
7659
7748
|
collect_goal_check_feedback "$INSTANCE_NAME"
|
|
@@ -7687,14 +7776,14 @@ printf '\n==> secret scan\n'
|
|
|
7687
7776
|
set_current_stage "secret scan"
|
|
7688
7777
|
emit_progress "secret scan" "started"
|
|
7689
7778
|
stage_start="$(date +%s)"
|
|
7690
|
-
: > /
|
|
7779
|
+
: > ${KASEKI_RESULTS_DIR}/secret-scan.log
|
|
7691
7780
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
7692
|
-
printf '🔄 DRY-RUN MODE: Skipping secret scan (no artifacts to scan)\n' | tee -a /
|
|
7781
|
+
printf '🔄 DRY-RUN MODE: Skipping secret scan (no artifacts to scan)\n' | tee -a ${KASEKI_RESULTS_DIR}/secret-scan.log
|
|
7693
7782
|
SECRET_SCAN_EXIT=0
|
|
7694
7783
|
record_stage_timing "secret scan" "0" "$(($(date +%s) - stage_start))" "dry_run=true"
|
|
7695
7784
|
else
|
|
7696
7785
|
# Run the initial scan
|
|
7697
|
-
if grep -R -n -E 'sk-or-[A-Za-z0-9_-]{20,}'
|
|
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
|
|
7698
7787
|
# Matches found - check against allowlist
|
|
7699
7788
|
if check_secret_scan_allowlist; then
|
|
7700
7789
|
# All matches are allowlisted
|
|
@@ -7747,7 +7836,7 @@ printf '\n==> github operations\n'
|
|
|
7747
7836
|
set_current_stage "github operations"
|
|
7748
7837
|
emit_progress "github operations" "started"
|
|
7749
7838
|
stage_start="$(date +%s)"
|
|
7750
|
-
: > /
|
|
7839
|
+
: > ${KASEKI_RESULTS_DIR}/git-push.log
|
|
7751
7840
|
build_github_skip_reasons
|
|
7752
7841
|
if [ "${#GITHUB_SKIP_REASONS[@]}" -eq 0 ]; then
|
|
7753
7842
|
github_app_id_file="$(resolve_github_secret_file "GITHUB_APP_ID_FILE" "github_app_id")"
|
|
@@ -7766,7 +7855,7 @@ if [ "${#GITHUB_SKIP_REASONS[@]}" -eq 0 ]; then
|
|
|
7766
7855
|
else
|
|
7767
7856
|
GITHUB_SKIP_REASONS+=("github_app_secrets_missing")
|
|
7768
7857
|
GITHUB_OPERATION_PHASE="secrets"
|
|
7769
|
-
printf -- 'GitHub operations: skipped (reasons: %s)\n' "$(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")" | tee -a /
|
|
7858
|
+
printf -- 'GitHub operations: skipped (reasons: %s)\n' "$(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
7770
7859
|
emit_progress "github operations" "skipped: $(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")"
|
|
7771
7860
|
GITHUB_PUSH_EXIT=7
|
|
7772
7861
|
fi
|
|
@@ -7778,7 +7867,7 @@ else
|
|
|
7778
7867
|
"$([ "$QUALITY_EXIT" -eq 0 ] && printf 'passed' || printf 'failed')" \
|
|
7779
7868
|
"$([ "$SECRET_SCAN_EXIT" -eq 0 ] && printf 'passed' || printf 'failed')" \
|
|
7780
7869
|
"$DIFF_NONEMPTY" \
|
|
7781
|
-
"$GITHUB_APP_ENABLED" | tee -a /
|
|
7870
|
+
"$GITHUB_APP_ENABLED" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
7782
7871
|
emit_progress "github operations" "skipped: $(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")"
|
|
7783
7872
|
fi
|
|
7784
7873
|
if [ "$GITHUB_APP_ENABLED" = "1" ]; then
|