@cyanautomation/kaseki-agent 1.64.0 → 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 +638 -663
- package/package.json +1 -1
- package/scripts/collect-feedback.js +12 -9
- package/scripts/kaseki-setup-host.sh +96 -38
- package/scripts/scouting-allowlist.js +229 -0
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"
|
|
@@ -470,143 +534,15 @@ validate_scouting_artifact_with_node() {
|
|
|
470
534
|
local final_artifact="$2"
|
|
471
535
|
local validation_error_file="$3"
|
|
472
536
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
function actualType(value) {
|
|
482
|
-
if (value === null) return "null";
|
|
483
|
-
if (Array.isArray(value)) return "array";
|
|
484
|
-
return typeof value;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
function appendValidationFailure(reasonCode, error) {
|
|
488
|
-
fs.appendFileSync(jsonlLog, JSON.stringify({
|
|
489
|
-
timestamp: new Date().toISOString(),
|
|
490
|
-
reason_code: reasonCode,
|
|
491
|
-
...error,
|
|
492
|
-
}) + "\n");
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
function summarize(errors) {
|
|
496
|
-
const critical = errors.filter((error) => error.severity === "critical").length;
|
|
497
|
-
const warning = errors.filter((error) => error.severity === "warning").length;
|
|
498
|
-
const counts = [];
|
|
499
|
-
if (critical) counts.push(`${critical} critical`);
|
|
500
|
-
if (warning) counts.push(`${warning} warning`);
|
|
501
|
-
const fields = errors.slice(0, 2).map((error) => error.field).join(", ");
|
|
502
|
-
const suffix = errors.length > 2 ? `, +${errors.length - 2} more` : "";
|
|
503
|
-
return `${counts.join(", ")} scouting validation ${errors.length === 1 ? "error" : "errors"}: ${fields}${suffix}`;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
let artifact;
|
|
507
|
-
try {
|
|
508
|
-
artifact = JSON.parse(fs.readFileSync(input, "utf8"));
|
|
509
|
-
} catch (err) {
|
|
510
|
-
const reasonCode = "malformed_json";
|
|
511
|
-
const error = {
|
|
512
|
-
field: "root",
|
|
513
|
-
expected: "exactly one valid JSON object",
|
|
514
|
-
actual: err && err.message ? String(err.message) : "JSON parse failed",
|
|
515
|
-
severity: "critical",
|
|
516
|
-
suggestion: "ensure exactly one valid JSON object is written to /results/scouting-candidate.json",
|
|
517
|
-
};
|
|
518
|
-
appendValidationFailure(reasonCode, error);
|
|
519
|
-
fs.writeFileSync(errorLog, JSON.stringify({
|
|
520
|
-
reason_code: reasonCode,
|
|
521
|
-
details: summarize([error]),
|
|
522
|
-
errors: [error],
|
|
523
|
-
}) + "\n");
|
|
524
|
-
process.exit(1);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
const errors = [];
|
|
528
|
-
const addError = (field, expected, actual, severity, suggestion) => {
|
|
529
|
-
errors.push({ field, expected, actual, severity, suggestion });
|
|
530
|
-
};
|
|
531
|
-
const arrayKeys = ["requirements", "relevant_files", "observations", "plan", "validation", "risks", "test_impact"];
|
|
532
|
-
|
|
533
|
-
if (!artifact || Array.isArray(artifact) || typeof artifact !== "object") {
|
|
534
|
-
addError("root", "object", actualType(artifact), "critical", "Scouting artifact must be a JSON object, not an array/null/primitive");
|
|
535
|
-
} else {
|
|
536
|
-
if (typeof artifact.task !== "string" || !artifact.task.trim()) {
|
|
537
|
-
addError("task", "non-empty string", typeof artifact.task === "string" ? "empty string" : actualType(artifact.task), "critical", "task must be a non-empty string describing the requested work");
|
|
538
|
-
}
|
|
539
|
-
for (const key of arrayKeys) {
|
|
540
|
-
if (!Array.isArray(artifact[key])) {
|
|
541
|
-
addError(key, "array", actualType(artifact[key]), "critical", `${key} must be an array in the scouting handoff`);
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
if (Array.isArray(artifact.relevant_files)) {
|
|
545
|
-
artifact.relevant_files.forEach((item, index) => {
|
|
546
|
-
if (!item || typeof item.path !== "string" || typeof item.reason !== "string") {
|
|
547
|
-
addError(`relevant_files[${index}]`, "object with string path and string reason", actualType(item), "warning", "Each relevant_files entry must include path and reason strings");
|
|
548
|
-
}
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
if (Array.isArray(artifact.test_impact)) {
|
|
552
|
-
artifact.test_impact.forEach((item, index) => {
|
|
553
|
-
if (!item || typeof item.path !== "string" || !item.path.trim() || typeof item.reason !== "string" || !item.reason.trim()) {
|
|
554
|
-
addError(`test_impact[${index}]`, "object with non-empty string path and non-empty string reason", actualType(item), "critical", "Each test_impact entry must include the impacted test path and expectation reason strings");
|
|
555
|
-
}
|
|
556
|
-
// Validate optional test_examples field
|
|
557
|
-
if (item.test_examples !== undefined) {
|
|
558
|
-
if (!Array.isArray(item.test_examples)) {
|
|
559
|
-
addError(`test_impact[${index}].test_examples`, "array of example objects or undefined", actualType(item.test_examples), "warning", "test_examples must be an array of objects with type, pattern, description, before, and after fields");
|
|
560
|
-
} else {
|
|
561
|
-
item.test_examples.forEach((example, exIdx) => {
|
|
562
|
-
if (!example || typeof example !== "object" || !["added_assertion", "modified_assertion", "added_test_case", "added_pattern"].includes(example.type)) {
|
|
563
|
-
addError(`test_impact[${index}].test_examples[${exIdx}].type`, "added_assertion|modified_assertion|added_test_case|added_pattern", actualType(example && example.type), "warning", "Each test_example must have a valid type");
|
|
564
|
-
}
|
|
565
|
-
if (!example || typeof example.pattern !== "string") {
|
|
566
|
-
addError(`test_impact[${index}].test_examples[${exIdx}].pattern`, "string", actualType(example && example.pattern), "warning", "Each test_example must have a pattern string");
|
|
567
|
-
}
|
|
568
|
-
if (!example || typeof example.before !== "string" || typeof example.after !== "string") {
|
|
569
|
-
addError(`test_impact[${index}].test_examples[${exIdx}]`, "before and after strings", "missing or invalid", "warning", "Each test_example must have before and after code snippets");
|
|
570
|
-
}
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
// Validate suggested_allowlist (optional but if present, must be valid)
|
|
578
|
-
if (artifact.suggested_allowlist) {
|
|
579
|
-
if (typeof artifact.suggested_allowlist !== "object" || Array.isArray(artifact.suggested_allowlist)) {
|
|
580
|
-
addError("suggested_allowlist", "object", actualType(artifact.suggested_allowlist), "warning", "suggested_allowlist must be an object with agent_patterns and validation_patterns arrays");
|
|
581
|
-
} else {
|
|
582
|
-
if (!Array.isArray(artifact.suggested_allowlist.agent_patterns)) {
|
|
583
|
-
addError("suggested_allowlist.agent_patterns", "array of strings", actualType(artifact.suggested_allowlist.agent_patterns), "warning", "agent_patterns must be an array of glob pattern strings");
|
|
584
|
-
} else if (!artifact.suggested_allowlist.agent_patterns.every((p) => typeof p === "string")) {
|
|
585
|
-
addError("suggested_allowlist.agent_patterns", "array of strings", "array with non-strings", "warning", "All agent_patterns entries must be strings");
|
|
586
|
-
}
|
|
587
|
-
if (!Array.isArray(artifact.suggested_allowlist.validation_patterns)) {
|
|
588
|
-
addError("suggested_allowlist.validation_patterns", "array of strings", actualType(artifact.suggested_allowlist.validation_patterns), "warning", "validation_patterns must be an array of glob pattern strings");
|
|
589
|
-
} else if (!artifact.suggested_allowlist.validation_patterns.every((p) => typeof p === "string")) {
|
|
590
|
-
addError("suggested_allowlist.validation_patterns", "array of strings", "array with non-strings", "warning", "All validation_patterns entries must be strings");
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
537
|
+
node "$SCOUTING_ALLOWLIST_HELPER" validate \
|
|
538
|
+
"$candidate_artifact" \
|
|
539
|
+
"$final_artifact" \
|
|
540
|
+
"$validation_error_file" \
|
|
541
|
+
"${KASEKI_RESULTS_DIR}/scouting-validation-errors.jsonl" \
|
|
542
|
+
>/dev/null \
|
|
543
|
+
2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
594
544
|
}
|
|
595
545
|
|
|
596
|
-
if (errors.length) {
|
|
597
|
-
const onlyTaskMissing = errors.length === 1 && errors[0].field === "task";
|
|
598
|
-
const reasonCode = onlyTaskMissing ? "missing_required_fields" : "schema_mismatch";
|
|
599
|
-
for (const error of errors) appendValidationFailure(reasonCode, error);
|
|
600
|
-
fs.writeFileSync(errorLog, JSON.stringify({
|
|
601
|
-
reason_code: reasonCode,
|
|
602
|
-
details: summarize(errors),
|
|
603
|
-
errors,
|
|
604
|
-
}) + "\n");
|
|
605
|
-
process.exit(1);
|
|
606
|
-
}
|
|
607
|
-
fs.writeFileSync(output, JSON.stringify(artifact, null, 2) + "\n");
|
|
608
|
-
' "$candidate_artifact" "$final_artifact" "$validation_error_file" 2>> /results/scouting-stderr.log
|
|
609
|
-
}
|
|
610
546
|
# Validate scouting artifact and emit structured reason code
|
|
611
547
|
validate_scouting_artifact() {
|
|
612
548
|
local candidate_artifact="$1"
|
|
@@ -618,7 +554,7 @@ validate_scouting_artifact() {
|
|
|
618
554
|
|
|
619
555
|
: > "$validation_error_file"
|
|
620
556
|
if [ ! -f "$candidate_artifact" ]; then
|
|
621
|
-
if [ -f /
|
|
557
|
+
if [ -f ${KASEKI_RESULTS_DIR}/filesystem-readonly-reason.txt ]; then
|
|
622
558
|
reason_code="readonly_filesystem"
|
|
623
559
|
reason_details="1 critical scouting validation error: scouting-candidate.json missing due to read-only filesystem"
|
|
624
560
|
else
|
|
@@ -626,15 +562,15 @@ validate_scouting_artifact() {
|
|
|
626
562
|
reason_details="1 critical scouting validation error: scouting-candidate.json"
|
|
627
563
|
fi
|
|
628
564
|
# shellcheck disable=SC2016
|
|
629
|
-
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
|
|
630
566
|
elif ! validate_scouting_artifact_with_node "$candidate_artifact" "$final_artifact" "$validation_error_file"; then
|
|
631
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')"
|
|
632
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')"
|
|
633
569
|
fi
|
|
634
570
|
|
|
635
571
|
printf '%s\n' "$reason_code" > "$reason_file"
|
|
636
|
-
printf '%s\n' "$reason_details" > /
|
|
637
|
-
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
|
|
638
574
|
rm -f "$validation_error_file" 2>/dev/null || true
|
|
639
575
|
[ "$reason_code" = "valid" ]
|
|
640
576
|
}
|
|
@@ -649,12 +585,14 @@ validate_goal_check_artifact_with_node() {
|
|
|
649
585
|
# shellcheck disable=SC2016
|
|
650
586
|
node -e '
|
|
651
587
|
const fs = require("node:fs");
|
|
588
|
+
const path = require("node:path");
|
|
652
589
|
const input = process.argv[1];
|
|
653
590
|
const output = process.argv[2];
|
|
654
591
|
const attempt = Number(process.argv[3]);
|
|
655
592
|
const errorLog = process.argv[4];
|
|
656
|
-
const
|
|
657
|
-
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");
|
|
658
596
|
|
|
659
597
|
function actualType(value) {
|
|
660
598
|
if (value === null) return "null";
|
|
@@ -663,11 +601,16 @@ function actualType(value) {
|
|
|
663
601
|
}
|
|
664
602
|
|
|
665
603
|
function appendValidationFailure(error) {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
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
|
+
}
|
|
671
614
|
}
|
|
672
615
|
|
|
673
616
|
function summarize(errors) {
|
|
@@ -700,7 +643,7 @@ try {
|
|
|
700
643
|
expected: "valid JSON object",
|
|
701
644
|
actual: error && error.message ? String(error.message) : String(error),
|
|
702
645
|
severity: "critical",
|
|
703
|
-
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",
|
|
704
647
|
}]);
|
|
705
648
|
}
|
|
706
649
|
|
|
@@ -753,8 +696,13 @@ if (errors.length) {
|
|
|
753
696
|
artifact.attempt = attempt;
|
|
754
697
|
artifact.timestamp = new Date().toISOString();
|
|
755
698
|
fs.writeFileSync(output, JSON.stringify(artifact, null, 2) + "\n");
|
|
756
|
-
|
|
757
|
-
|
|
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"
|
|
758
706
|
}
|
|
759
707
|
|
|
760
708
|
validate_goal_check_artifact() {
|
|
@@ -762,7 +710,7 @@ validate_goal_check_artifact() {
|
|
|
762
710
|
local final_artifact="$2"
|
|
763
711
|
local attempt="$3"
|
|
764
712
|
local reason_file="$4"
|
|
765
|
-
local summary_file="${5
|
|
713
|
+
local summary_file="${5:-${KASEKI_RESULTS_DIR}/goal-check-validation-summary.txt}"
|
|
766
714
|
local validation_error_file="/tmp/goal-check-validation-errors.json"
|
|
767
715
|
local reason_code="valid"
|
|
768
716
|
local reason_details="artifact validation passed"
|
|
@@ -772,7 +720,7 @@ validate_goal_check_artifact() {
|
|
|
772
720
|
reason_code="missing_file"
|
|
773
721
|
reason_details="1 critical goal-check validation error: goal-check-candidate.json"
|
|
774
722
|
# shellcheck disable=SC2016
|
|
775
|
-
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
|
|
776
724
|
elif ! validate_goal_check_artifact_with_node "$candidate_artifact" "$final_artifact" "$attempt" "$validation_error_file"; then
|
|
777
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')"
|
|
778
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')"
|
|
@@ -780,7 +728,7 @@ validate_goal_check_artifact() {
|
|
|
780
728
|
|
|
781
729
|
printf '%s\n' "$reason_code" > "$reason_file"
|
|
782
730
|
printf '%s\n' "$reason_details" > "$summary_file"
|
|
783
|
-
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
|
|
784
732
|
rm -f "$validation_error_file" 2>/dev/null || true
|
|
785
733
|
[ "$reason_code" = "valid" ]
|
|
786
734
|
}
|
|
@@ -789,20 +737,20 @@ emit_progress() {
|
|
|
789
737
|
local stage="$1"
|
|
790
738
|
local detail="$2"
|
|
791
739
|
local status="${3:-info}"
|
|
792
|
-
append_jsonl_object /
|
|
740
|
+
append_jsonl_object ${KASEKI_RESULTS_DIR}/progress.jsonl \
|
|
793
741
|
"timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
794
742
|
"component=kaseki-agent" \
|
|
795
743
|
"stage=$stage" \
|
|
796
744
|
"status=$status" \
|
|
797
745
|
"instance=$INSTANCE_NAME" \
|
|
798
746
|
"detail=$detail"
|
|
799
|
-
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
|
|
800
748
|
}
|
|
801
749
|
|
|
802
750
|
emit_event() {
|
|
803
751
|
local event_type="$1"
|
|
804
752
|
shift
|
|
805
|
-
append_jsonl_object /
|
|
753
|
+
append_jsonl_object ${KASEKI_RESULTS_DIR}/progress.jsonl \
|
|
806
754
|
"timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
807
755
|
"component=kaseki-agent" \
|
|
808
756
|
"event_type=$event_type" \
|
|
@@ -815,7 +763,7 @@ emit_error_event() {
|
|
|
815
763
|
local detail="$2"
|
|
816
764
|
local recovery="${3:-continue}"
|
|
817
765
|
emit_event "error" "error_type=$error_type" "detail=$detail" "recovery_action=$recovery"
|
|
818
|
-
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
|
|
819
767
|
}
|
|
820
768
|
|
|
821
769
|
write_metadata() {
|
|
@@ -833,7 +781,7 @@ write_metadata() {
|
|
|
833
781
|
stages_json="[\"unknown\"]"
|
|
834
782
|
fi
|
|
835
783
|
|
|
836
|
-
cat > /
|
|
784
|
+
cat > ${KASEKI_RESULTS_DIR}/metadata.json <<META
|
|
837
785
|
{
|
|
838
786
|
"instance": $(printf '%s' "$INSTANCE_NAME" | json_encode),
|
|
839
787
|
"repo_url": $(printf '%s' "$REPO_URL" | json_encode),
|
|
@@ -954,7 +902,7 @@ write_metadata() {
|
|
|
954
902
|
"stages": $stages_json
|
|
955
903
|
}
|
|
956
904
|
META
|
|
957
|
-
printf '%s\n' "$exit_code" > /
|
|
905
|
+
printf '%s\n' "$exit_code" > ${KASEKI_RESULTS_DIR}/exit_code
|
|
958
906
|
}
|
|
959
907
|
|
|
960
908
|
set_current_stage() {
|
|
@@ -1009,7 +957,7 @@ build_stages_array() {
|
|
|
1009
957
|
|
|
1010
958
|
write_result_summary() {
|
|
1011
959
|
local changed_files changed_files_markdown validation_status pr_status github_skip_reasons_summary goal_check_status
|
|
1012
|
-
changed_files="$(cat /
|
|
960
|
+
changed_files="$(cat ${KASEKI_RESULTS_DIR}/changed-files.txt 2>/dev/null || true)"
|
|
1013
961
|
if [ -n "$changed_files" ]; then
|
|
1014
962
|
changed_files_markdown="$(printf '%s\n' "$changed_files" | sed 's/^/ - /')"
|
|
1015
963
|
else
|
|
@@ -1062,7 +1010,7 @@ write_result_summary() {
|
|
|
1062
1010
|
goal_check_status="not reached"
|
|
1063
1011
|
fi
|
|
1064
1012
|
|
|
1065
|
-
cat > /
|
|
1013
|
+
cat > ${KASEKI_RESULTS_DIR}/result-summary.md <<SUMMARY
|
|
1066
1014
|
# Kaseki Result: $INSTANCE_NAME
|
|
1067
1015
|
|
|
1068
1016
|
- Status: $(if [ "$STATUS" -eq 0 ]; then printf 'passed'; else printf 'failed'; fi)
|
|
@@ -1087,7 +1035,7 @@ $(if [ -n "$VALIDATION_ALLOWLIST_FAILURE_REASON" ]; then printf ' - Allowlist r
|
|
|
1087
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)
|
|
1088
1036
|
- Test failure analysis: $TEST_FAILURE_CLASSIFICATION_STATUS
|
|
1089
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)
|
|
1090
|
-
$(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)
|
|
1091
1039
|
- Quality checks: $QUALITY_EXIT
|
|
1092
1040
|
- Secret scan: $SECRET_SCAN_EXIT
|
|
1093
1041
|
- GitHub PR: $pr_status
|
|
@@ -1129,12 +1077,12 @@ SUMMARY
|
|
|
1129
1077
|
write_failure_json() {
|
|
1130
1078
|
local exit_code="$1"
|
|
1131
1079
|
local stderr_tail
|
|
1132
|
-
stderr_tail="$(tail -20 /
|
|
1080
|
+
stderr_tail="$(tail -20 ${KASEKI_RESULTS_DIR}/stderr.log 2>/dev/null || true)"
|
|
1133
1081
|
if [ "$exit_code" -eq 0 ]; then
|
|
1134
|
-
: > /
|
|
1082
|
+
: > ${KASEKI_RESULTS_DIR}/failure.json
|
|
1135
1083
|
return 0
|
|
1136
1084
|
fi
|
|
1137
|
-
cat > /
|
|
1085
|
+
cat > ${KASEKI_RESULTS_DIR}/failure.json <<FAILURE
|
|
1138
1086
|
{
|
|
1139
1087
|
"instance": $(printf '%s' "$INSTANCE_NAME" | json_encode),
|
|
1140
1088
|
"exit_code": $exit_code,
|
|
@@ -1152,7 +1100,7 @@ write_failure_json() {
|
|
|
1152
1100
|
"goal_check_met": $GOAL_CHECK_MET,
|
|
1153
1101
|
"stage": $(printf '%s' "$CURRENT_STAGE" | json_encode),
|
|
1154
1102
|
"stderr_tail": $(printf '%s' "$stderr_tail" | json_encode),
|
|
1155
|
-
"artifacts_dir": "
|
|
1103
|
+
"artifacts_dir": "${KASEKI_RESULTS_DIR}",
|
|
1156
1104
|
"metadata": "metadata.json",
|
|
1157
1105
|
"stderr": "stderr.log",
|
|
1158
1106
|
"stdout": "stdout.log",
|
|
@@ -1164,28 +1112,28 @@ FAILURE
|
|
|
1164
1112
|
|
|
1165
1113
|
collect_git_artifacts() {
|
|
1166
1114
|
DIFF_NONEMPTY=false
|
|
1167
|
-
if [ -d /
|
|
1115
|
+
if [ -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
1168
1116
|
while IFS= read -r untracked_file || [ -n "$untracked_file" ]; do
|
|
1169
1117
|
[ -z "$untracked_file" ] && continue
|
|
1170
|
-
git -C /
|
|
1171
|
-
done < <(git -C /
|
|
1172
|
-
git -C /
|
|
1173
|
-
git -C /
|
|
1174
|
-
git -C /
|
|
1175
|
-
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
|
|
1176
1124
|
DIFF_NONEMPTY=true
|
|
1177
1125
|
fi
|
|
1178
1126
|
else
|
|
1179
|
-
: > /
|
|
1180
|
-
: > /
|
|
1181
|
-
: > /
|
|
1127
|
+
: > ${KASEKI_RESULTS_DIR}/git.status
|
|
1128
|
+
: > ${KASEKI_RESULTS_DIR}/git.diff
|
|
1129
|
+
: > ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
1182
1130
|
fi
|
|
1183
1131
|
}
|
|
1184
1132
|
|
|
1185
1133
|
run_static_test_impact_check() {
|
|
1186
|
-
local changed_files_file="/
|
|
1187
|
-
local diff_file="/
|
|
1188
|
-
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}"
|
|
1189
1137
|
local indicator_regex='(parse|parser|regex|regexp|stage|event|format|serialize|name)'
|
|
1190
1138
|
local production_matches diff_matches warning_detail
|
|
1191
1139
|
|
|
@@ -1227,7 +1175,7 @@ run_static_test_impact_check() {
|
|
|
1227
1175
|
"warning_type=test_impact_without_tests" \
|
|
1228
1176
|
"artifact=$artifact" \
|
|
1229
1177
|
"detail=$warning_detail"
|
|
1230
|
-
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
|
|
1231
1179
|
return 0
|
|
1232
1180
|
}
|
|
1233
1181
|
|
|
@@ -1240,70 +1188,89 @@ run_expectation_mismatch_detector() {
|
|
|
1240
1188
|
fi
|
|
1241
1189
|
|
|
1242
1190
|
: > "$EXPECTATION_MISMATCH_WARNINGS_ARTIFACT"
|
|
1243
|
-
if [ ! -s /
|
|
1244
|
-
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
|
|
1245
1193
|
return 0
|
|
1246
1194
|
fi
|
|
1247
1195
|
if [ ! -f "$detector_script" ]; then
|
|
1248
|
-
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
|
|
1249
1197
|
return 0
|
|
1250
1198
|
fi
|
|
1251
1199
|
|
|
1252
1200
|
if ! node "$detector_script" \
|
|
1253
|
-
--repo /
|
|
1254
|
-
--diff /
|
|
1201
|
+
--repo ${KASEKI_WORKSPACE_DIR}/repo \
|
|
1202
|
+
--diff ${KASEKI_RESULTS_DIR}/git.diff \
|
|
1255
1203
|
--output "$EXPECTATION_MISMATCH_WARNINGS_ARTIFACT" \
|
|
1256
|
-
--progress /
|
|
1257
|
-
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
|
|
1206
|
+
fi
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
resolve_allowlist_helper() {
|
|
1210
|
+
local script_dir="$1"
|
|
1211
|
+
local script_relative_helper="$script_dir/scripts/allowlist-helper.sh"
|
|
1212
|
+
local fallback_helper="${KASEKI_ALLOWLIST_HELPER_FALLBACK:-/app/scripts/allowlist-helper.sh}"
|
|
1213
|
+
|
|
1214
|
+
if [ -r "$script_relative_helper" ]; then
|
|
1215
|
+
printf '%s\n' "$script_relative_helper"
|
|
1216
|
+
return 0
|
|
1258
1217
|
fi
|
|
1218
|
+
|
|
1219
|
+
if [ -r "$fallback_helper" ]; then
|
|
1220
|
+
printf '%s\n' "$fallback_helper"
|
|
1221
|
+
return 0
|
|
1222
|
+
fi
|
|
1223
|
+
|
|
1224
|
+
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' \
|
|
1225
|
+
"$script_relative_helper" \
|
|
1226
|
+
"$fallback_helper" >&2
|
|
1227
|
+
return 66
|
|
1259
1228
|
}
|
|
1260
1229
|
|
|
1261
1230
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
1262
|
-
ALLOWLIST_HELPER="$SCRIPT_DIR
|
|
1263
|
-
|
|
1264
|
-
|
|
1231
|
+
ALLOWLIST_HELPER="$(resolve_allowlist_helper "$SCRIPT_DIR")"
|
|
1232
|
+
allowlist_helper_status=$?
|
|
1233
|
+
if [ "$allowlist_helper_status" -ne 0 ]; then
|
|
1234
|
+
exit "$allowlist_helper_status"
|
|
1235
|
+
fi
|
|
1236
|
+
SCOUTING_ALLOWLIST_HELPER="$SCRIPT_DIR/scripts/scouting-allowlist.js"
|
|
1237
|
+
if [ ! -r "$SCOUTING_ALLOWLIST_HELPER" ] && [ -r /app/scripts/scouting-allowlist.js ]; then
|
|
1238
|
+
SCOUTING_ALLOWLIST_HELPER="/app/scripts/scouting-allowlist.js"
|
|
1265
1239
|
fi
|
|
1266
1240
|
# shellcheck source=scripts/allowlist-helper.sh
|
|
1267
|
-
. "$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
|
+
|
|
1252
|
+
if [ "${KASEKI_AGENT_HELPER_RESOLUTION_CHECK:-0}" = "1" ]; then
|
|
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
|
+
}
|
|
1257
|
+
printf 'allowlist_helper=%s\n' "$ALLOWLIST_HELPER"
|
|
1258
|
+
exit 0
|
|
1259
|
+
fi
|
|
1268
1260
|
|
|
1269
1261
|
derive_allowlist_from_scouting() {
|
|
1270
|
-
local scouting_artifact
|
|
1262
|
+
local scouting_artifact
|
|
1271
1263
|
scouting_artifact="${1:?missing scouting artifact path}"
|
|
1272
|
-
|
|
1264
|
+
|
|
1273
1265
|
if [ ! -f "$scouting_artifact" ]; then
|
|
1274
1266
|
printf 'derive_allowlist_from_scouting: scouting artifact not found: %s\n' "$scouting_artifact" >&2
|
|
1275
1267
|
return 1
|
|
1276
1268
|
fi
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
agent_patterns="$(node -e "
|
|
1280
|
-
try {
|
|
1281
|
-
const fs = require('node:fs');
|
|
1282
|
-
const artifact = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
|
|
1283
|
-
if (artifact && artifact.suggested_allowlist && Array.isArray(artifact.suggested_allowlist.agent_patterns)) {
|
|
1284
|
-
console.log(artifact.suggested_allowlist.agent_patterns.join(' '));
|
|
1285
|
-
}
|
|
1286
|
-
} catch (e) {
|
|
1287
|
-
console.error('Error parsing scouting artifact:', e.message);
|
|
1288
|
-
}
|
|
1289
|
-
" "$scouting_artifact" 2>/dev/null)"
|
|
1290
|
-
|
|
1291
|
-
validation_patterns="$(node -e "
|
|
1292
|
-
try {
|
|
1293
|
-
const fs = require('node:fs');
|
|
1294
|
-
const artifact = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
|
|
1295
|
-
if (artifact && artifact.suggested_allowlist && Array.isArray(artifact.suggested_allowlist.validation_patterns)) {
|
|
1296
|
-
console.log(artifact.suggested_allowlist.validation_patterns.join(' '));
|
|
1297
|
-
}
|
|
1298
|
-
} catch (e) {
|
|
1299
|
-
console.error('Error parsing scouting artifact:', e.message);
|
|
1300
|
-
}
|
|
1301
|
-
" "$scouting_artifact" 2>/dev/null)"
|
|
1302
|
-
|
|
1303
|
-
printf '%s\n' "$agent_patterns"
|
|
1304
|
-
printf '%s\n' "$validation_patterns"
|
|
1269
|
+
|
|
1270
|
+
node "$SCOUTING_ALLOWLIST_HELPER" derive "$scouting_artifact"
|
|
1305
1271
|
}
|
|
1306
1272
|
|
|
1273
|
+
|
|
1307
1274
|
validate_allowlist_patterns() {
|
|
1308
1275
|
local patterns_str test_regex
|
|
1309
1276
|
patterns_str="${1:-}"
|
|
@@ -1346,7 +1313,7 @@ run_scouting_allowlist_coverage() {
|
|
|
1346
1313
|
local scouting_artifact agent_patterns validation_patterns
|
|
1347
1314
|
scouting_artifact="${1:?missing scouting artifact path}"
|
|
1348
1315
|
|
|
1349
|
-
if [ ! -f "$scouting_artifact" ] || [ ! -f /
|
|
1316
|
+
if [ ! -f "$scouting_artifact" ] || [ ! -f ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
1350
1317
|
return 0
|
|
1351
1318
|
fi
|
|
1352
1319
|
|
|
@@ -1361,7 +1328,7 @@ run_scouting_allowlist_coverage() {
|
|
|
1361
1328
|
validation_warnings=""
|
|
1362
1329
|
|
|
1363
1330
|
if [ -n "$agent_patterns" ] && command -v dry-run-allowlist.sh >/dev/null 2>&1; then
|
|
1364
|
-
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)"
|
|
1365
1332
|
[ -z "$agent_coverage" ] && agent_coverage="0"
|
|
1366
1333
|
|
|
1367
1334
|
# Check for problematic coverage
|
|
@@ -1373,7 +1340,7 @@ run_scouting_allowlist_coverage() {
|
|
|
1373
1340
|
fi
|
|
1374
1341
|
|
|
1375
1342
|
if [ -n "$validation_patterns" ] && command -v dry-run-allowlist.sh >/dev/null 2>&1; then
|
|
1376
|
-
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)"
|
|
1377
1344
|
[ -z "$validation_coverage" ] && validation_coverage="0"
|
|
1378
1345
|
|
|
1379
1346
|
if [ "$validation_coverage" -lt 30 ]; then
|
|
@@ -1407,12 +1374,12 @@ run_scouting_allowlist_coverage() {
|
|
|
1407
1374
|
if [ -n "$validation_warnings" ]; then
|
|
1408
1375
|
printf ' ⚠ validation_phase warning: %s\n' "$validation_warnings"
|
|
1409
1376
|
fi
|
|
1410
|
-
} | tee -a /
|
|
1377
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/scouting-report.md >> ${KASEKI_RESULTS_DIR}/quality.log
|
|
1411
1378
|
fi
|
|
1412
1379
|
}
|
|
1413
1380
|
|
|
1414
1381
|
restore_disallowed_changes() {
|
|
1415
|
-
if [ "$KASEKI_RESTORE_DISALLOWED_CHANGES" != "1" ] || [ ! -d /
|
|
1382
|
+
if [ "$KASEKI_RESTORE_DISALLOWED_CHANGES" != "1" ] || [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
1416
1383
|
return 0
|
|
1417
1384
|
fi
|
|
1418
1385
|
|
|
@@ -1425,7 +1392,7 @@ restore_disallowed_changes() {
|
|
|
1425
1392
|
coverage=0
|
|
1426
1393
|
|
|
1427
1394
|
# Initialize restoration tracking file
|
|
1428
|
-
: > /
|
|
1395
|
+
: > ${KASEKI_RESULTS_DIR}/restoration.jsonl
|
|
1429
1396
|
|
|
1430
1397
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
1431
1398
|
[ -z "$changed_file" ] && continue
|
|
@@ -1435,21 +1402,21 @@ restore_disallowed_changes() {
|
|
|
1435
1402
|
{
|
|
1436
1403
|
printf '{"timestamp":"%s","event":"file_evaluated","file":"%s","status":"kept","reason":"matched_allowlist"}\n' \
|
|
1437
1404
|
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$(printf '%s' "$changed_file" | sed 's/"/\\"/g')"
|
|
1438
|
-
} >> /
|
|
1405
|
+
} >> ${KASEKI_RESULTS_DIR}/restoration.jsonl
|
|
1439
1406
|
continue
|
|
1440
1407
|
fi
|
|
1441
1408
|
# File did not match allowlist - restore it
|
|
1442
1409
|
restored_count=$((restored_count + 1))
|
|
1443
|
-
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
|
|
1444
1411
|
emit_event "quality_gate_rule_evaluated" "rule=allowlist_restore" "passed=true" "file=$changed_file"
|
|
1445
1412
|
{
|
|
1446
1413
|
printf '{"timestamp":"%s","event":"file_restored","file":"%s","status":"restored","reason":"not_in_allowlist"}\n' \
|
|
1447
1414
|
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$(printf '%s' "$changed_file" | sed 's/"/\\"/g')"
|
|
1448
|
-
} >> /
|
|
1449
|
-
git -C /
|
|
1450
|
-
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
|
|
1451
1418
|
restored_any=1
|
|
1452
|
-
done < /
|
|
1419
|
+
done < ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
1453
1420
|
|
|
1454
1421
|
# Emit restoration summary to quality.log with actionable guidance
|
|
1455
1422
|
if [ $((restored_count + kept_count)) -gt 0 ]; then
|
|
@@ -1460,12 +1427,12 @@ restore_disallowed_changes() {
|
|
|
1460
1427
|
printf '\n[allowlist summary] Restored: %d files; Kept: %d files (coverage: %d%%)\n' "$restored_count" "$kept_count" "$coverage"
|
|
1461
1428
|
if [ "$restored_count" -gt 0 ] && [ "$coverage" -lt 50 ]; then
|
|
1462
1429
|
printf '[allowlist note] Low coverage detected. To improve:\n'
|
|
1463
|
-
printf ' 1. Run: ./scripts/suggest-allowlist.sh
|
|
1430
|
+
printf ' 1. Run: ./scripts/suggest-allowlist.sh ${KASEKI_RESULTS_DIR} (or /agents/kaseki-results/<instance>)\n'
|
|
1464
1431
|
printf ' 2. Review suggested patterns in allowlist-suggestions.md\n'
|
|
1465
1432
|
printf ' 3. Update KASEKI_CHANGED_FILES_ALLOWLIST and re-run\n'
|
|
1466
1433
|
printf 'See docs/QUALITY_GATES.md for more guidance.\n'
|
|
1467
1434
|
fi
|
|
1468
|
-
} | tee -a /
|
|
1435
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
1469
1436
|
emit_event "allowlist_restoration_complete" "restored=$restored_count" "kept=$kept_count" "coverage=$coverage"
|
|
1470
1437
|
fi
|
|
1471
1438
|
|
|
@@ -1475,7 +1442,7 @@ restore_disallowed_changes() {
|
|
|
1475
1442
|
}
|
|
1476
1443
|
|
|
1477
1444
|
generate_restoration_report() {
|
|
1478
|
-
if [ ! -f /
|
|
1445
|
+
if [ ! -f ${KASEKI_RESULTS_DIR}/restoration.jsonl ]; then
|
|
1479
1446
|
printf '[debug] restoration report: skipping - restoration.jsonl not found\n' >&2
|
|
1480
1447
|
return 0
|
|
1481
1448
|
fi
|
|
@@ -1484,7 +1451,7 @@ generate_restoration_report() {
|
|
|
1484
1451
|
|
|
1485
1452
|
# Safely extract counts from restoration.jsonl with validation
|
|
1486
1453
|
printf '[debug] restoration report: extracting counts from restoration.jsonl\n' >&2
|
|
1487
|
-
restored_count=$(grep -c '"status":"restored"' /
|
|
1454
|
+
restored_count=$(grep -c '"status":"restored"' ${KASEKI_RESULTS_DIR}/restoration.jsonl 2>/dev/null || true)
|
|
1488
1455
|
restored_count=${restored_count:-0}
|
|
1489
1456
|
printf '[debug] restoration report: restored_count="%s"\n' "$restored_count" >&2
|
|
1490
1457
|
if ! validate_numeric "restored_count" "$restored_count"; then
|
|
@@ -1492,7 +1459,7 @@ generate_restoration_report() {
|
|
|
1492
1459
|
return 1
|
|
1493
1460
|
fi
|
|
1494
1461
|
|
|
1495
|
-
kept_count=$(grep -c '"status":"kept"' /
|
|
1462
|
+
kept_count=$(grep -c '"status":"kept"' ${KASEKI_RESULTS_DIR}/restoration.jsonl 2>/dev/null || true)
|
|
1496
1463
|
kept_count=${kept_count:-0}
|
|
1497
1464
|
printf '[debug] restoration report: kept_count="%s"\n' "$kept_count" >&2
|
|
1498
1465
|
if ! validate_numeric "kept_count" "$kept_count"; then
|
|
@@ -1530,12 +1497,12 @@ generate_restoration_report() {
|
|
|
1530
1497
|
if [ "$restored_count" -gt 0 ]; then
|
|
1531
1498
|
printf '## Restored Files\n\n'
|
|
1532
1499
|
printf 'These files were modified by the agent but restored because they fall outside the allowlist:\n\n'
|
|
1533
|
-
grep '"status":"restored"' /
|
|
1500
|
+
grep '"status":"restored"' ${KASEKI_RESULTS_DIR}/restoration.jsonl | \
|
|
1534
1501
|
sed "s/.*\"file\":\"\([^\"]*\)\".*/- \`\1\`/" | \
|
|
1535
|
-
sort | uniq >> /
|
|
1536
|
-
if [ -f /
|
|
1537
|
-
cat /
|
|
1538
|
-
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
|
|
1539
1506
|
fi
|
|
1540
1507
|
printf '\n'
|
|
1541
1508
|
fi
|
|
@@ -1543,12 +1510,12 @@ generate_restoration_report() {
|
|
|
1543
1510
|
if [ "$kept_count" -gt 0 ]; then
|
|
1544
1511
|
printf '## Kept Files (Allowlist Matches)\n\n'
|
|
1545
1512
|
printf 'These files were in the allowlist and were kept:\n\n'
|
|
1546
|
-
grep '"status":"kept"' /
|
|
1513
|
+
grep '"status":"kept"' ${KASEKI_RESULTS_DIR}/restoration.jsonl | \
|
|
1547
1514
|
sed "s/.*\"file\":\"\([^\"]*\)\".*/- \`\1\`/" | \
|
|
1548
|
-
sort | uniq >> /
|
|
1549
|
-
if [ -f /
|
|
1550
|
-
cat /
|
|
1551
|
-
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
|
|
1552
1519
|
fi
|
|
1553
1520
|
printf '\n'
|
|
1554
1521
|
fi
|
|
@@ -1566,14 +1533,14 @@ generate_restoration_report() {
|
|
|
1566
1533
|
printf 'KASEKI_CHANGED_FILES_ALLOWLIST="<your-pattern>" ./run-kaseki.sh\n'
|
|
1567
1534
|
printf '```\n\n'
|
|
1568
1535
|
printf "For help on allowlist patterns, see \`docs/QUALITY_GATES.md\`.\n"
|
|
1569
|
-
} > /
|
|
1536
|
+
} > ${KASEKI_RESULTS_DIR}/restoration-report.md
|
|
1570
1537
|
}
|
|
1571
1538
|
|
|
1572
1539
|
check_validation_allowlist() {
|
|
1573
1540
|
if [ -z "$KASEKI_VALIDATION_ALLOWLIST" ]; then
|
|
1574
1541
|
return 0
|
|
1575
1542
|
fi
|
|
1576
|
-
if [ ! -d /
|
|
1543
|
+
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
1577
1544
|
return 0
|
|
1578
1545
|
fi
|
|
1579
1546
|
|
|
@@ -1582,9 +1549,9 @@ check_validation_allowlist() {
|
|
|
1582
1549
|
allowlist_regex="$(build_allowlist_regex "$KASEKI_VALIDATION_ALLOWLIST")"
|
|
1583
1550
|
[ -z "$allowlist_regex" ] && return 0
|
|
1584
1551
|
validation_violation_count=0
|
|
1585
|
-
validation_before_state_file="/
|
|
1586
|
-
validation_after_state_file="/
|
|
1587
|
-
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"
|
|
1588
1555
|
: > "$validation_changed_file"
|
|
1589
1556
|
|
|
1590
1557
|
if [ -f "$validation_before_state_file" ] && [ -f "$validation_after_state_file" ]; then
|
|
@@ -1599,14 +1566,14 @@ check_validation_allowlist() {
|
|
|
1599
1566
|
}
|
|
1600
1567
|
}
|
|
1601
1568
|
' "$validation_before_state_file" "$validation_after_state_file" | LC_ALL=C sort -u > "$validation_changed_file"
|
|
1602
|
-
elif [ -f /
|
|
1603
|
-
cp /
|
|
1569
|
+
elif [ -f ${KASEKI_RESULTS_DIR}/changed-files.txt ]; then
|
|
1570
|
+
cp ${KASEKI_RESULTS_DIR}/changed-files.txt "$validation_changed_file"
|
|
1604
1571
|
fi
|
|
1605
1572
|
|
|
1606
1573
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
1607
1574
|
[ -z "$changed_file" ] && continue
|
|
1608
1575
|
if ! printf '%s\n' "$changed_file" | grep -Eq "^(${allowlist_regex})$"; then
|
|
1609
|
-
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
|
|
1610
1577
|
validation_violation_count=$((validation_violation_count + 1))
|
|
1611
1578
|
emit_event "quality_gate_rule_evaluated" "rule=validation_allowlist" "passed=false" "file=$changed_file"
|
|
1612
1579
|
else
|
|
@@ -1618,14 +1585,14 @@ check_validation_allowlist() {
|
|
|
1618
1585
|
QUALITY_EXIT=7
|
|
1619
1586
|
VALIDATION_ALLOWLIST_FAILURE_REASON="validation_allowlist_check: $validation_violation_count file(s) changed during validation outside KASEKI_VALIDATION_ALLOWLIST"
|
|
1620
1587
|
QUALITY_FAILURE_REASON="$VALIDATION_ALLOWLIST_FAILURE_REASON"
|
|
1621
|
-
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
|
|
1622
1589
|
return 1
|
|
1623
1590
|
fi
|
|
1624
1591
|
return 0
|
|
1625
1592
|
}
|
|
1626
1593
|
|
|
1627
1594
|
check_secret_scan_allowlist() {
|
|
1628
|
-
local allowlist_file="/
|
|
1595
|
+
local allowlist_file="${KASEKI_WORKSPACE_DIR}/repo/.kaseki-secret-allowlist"
|
|
1629
1596
|
|
|
1630
1597
|
# If no allowlist file exists, all matches are failures (real leaks)
|
|
1631
1598
|
if [ ! -f "$allowlist_file" ]; then
|
|
@@ -1638,7 +1605,7 @@ check_secret_scan_allowlist() {
|
|
|
1638
1605
|
|
|
1639
1606
|
# Read the log into a temp variable to avoid SC2094 (read-write in same pipeline)
|
|
1640
1607
|
local temp_log
|
|
1641
|
-
temp_log=$(cat /
|
|
1608
|
+
temp_log=$(cat ${KASEKI_RESULTS_DIR}/secret-scan.log)
|
|
1642
1609
|
|
|
1643
1610
|
while IFS= read -r match_line || [ -n "$match_line" ]; do
|
|
1644
1611
|
[ -z "$match_line" ] && continue
|
|
@@ -1652,8 +1619,8 @@ check_secret_scan_allowlist() {
|
|
|
1652
1619
|
|
|
1653
1620
|
[ -z "$pattern" ] && continue
|
|
1654
1621
|
|
|
1655
|
-
# Normalize file path: remove leading /
|
|
1656
|
-
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/}"
|
|
1657
1624
|
file_path="${file_path#repo/}"
|
|
1658
1625
|
file_path="${file_path#./}"
|
|
1659
1626
|
|
|
@@ -1678,7 +1645,7 @@ check_secret_scan_allowlist() {
|
|
|
1678
1645
|
for match in "${secret_matches[@]}"; do
|
|
1679
1646
|
printf '%s\n' "$match"
|
|
1680
1647
|
done
|
|
1681
|
-
} > /
|
|
1648
|
+
} > ${KASEKI_RESULTS_DIR}/secret-scan.log
|
|
1682
1649
|
|
|
1683
1650
|
# Exit code 6 only if there are unallowlisted matches
|
|
1684
1651
|
if [ "$unallowlisted_count" -gt 0 ]; then
|
|
@@ -1712,9 +1679,9 @@ finish() {
|
|
|
1712
1679
|
printf '[unexpected-failure] Exit code: %d\n' "$code"
|
|
1713
1680
|
printf '[unexpected-failure] Last command: %s\n' "$LAST_COMMAND"
|
|
1714
1681
|
printf '[unexpected-failure] Current stage: %s\n' "$CURRENT_STAGE"
|
|
1715
|
-
if [ -f /
|
|
1682
|
+
if [ -f ${KASEKI_RESULTS_DIR}/progress.log ]; then
|
|
1716
1683
|
printf '[unexpected-failure] Last 5 progress entries:\n'
|
|
1717
|
-
tail -5 /
|
|
1684
|
+
tail -5 ${KASEKI_RESULTS_DIR}/progress.log | sed 's/^/ /'
|
|
1718
1685
|
fi
|
|
1719
1686
|
} | tee -a "$LAST_COMMAND_LOG" >&2
|
|
1720
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"
|
|
@@ -1723,16 +1690,16 @@ finish() {
|
|
|
1723
1690
|
maybe_call_finish_helper collect_git_artifacts
|
|
1724
1691
|
|
|
1725
1692
|
# Analyze test failures and compare baseline vs. working results
|
|
1726
|
-
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
|
|
1727
1694
|
set_current_stage "test failure analysis"
|
|
1728
1695
|
if analyze_test_failures_baseline; then
|
|
1729
1696
|
TEST_FAILURE_CLASSIFICATION_STATUS="completed"
|
|
1730
1697
|
# Try to extract newly_introduced_failures_count from JSON output (if jq available)
|
|
1731
|
-
if [ -f /
|
|
1732
|
-
NEWLY_INTRODUCED_FAILURES_COUNT=$(jq -r '.summary.total_newly_introduced // 0' /
|
|
1733
|
-
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
|
|
1734
1701
|
# Fallback: try to extract with grep/sed if jq not available
|
|
1735
|
-
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')
|
|
1736
1703
|
fi
|
|
1737
1704
|
else
|
|
1738
1705
|
TEST_FAILURE_CLASSIFICATION_STATUS="failed"
|
|
@@ -1746,8 +1713,8 @@ finish() {
|
|
|
1746
1713
|
fi
|
|
1747
1714
|
|
|
1748
1715
|
# Debug output for restoration report generation
|
|
1749
|
-
if [ -f /
|
|
1750
|
-
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
|
|
1751
1718
|
else
|
|
1752
1719
|
printf '[debug] restoration.jsonl does not exist\n' >&2
|
|
1753
1720
|
fi
|
|
@@ -1765,12 +1732,12 @@ finish() {
|
|
|
1765
1732
|
|
|
1766
1733
|
# Calculate and record maturity score
|
|
1767
1734
|
if [ -x /app/scripts/kaseki-maturity-score.sh ]; then
|
|
1768
|
-
/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
|
|
1769
1736
|
fi
|
|
1770
1737
|
|
|
1771
1738
|
# Calculate and record performance metrics
|
|
1772
|
-
if [ -x /app/scripts/kaseki-performance-metrics.sh ] && [ -f /
|
|
1773
|
-
/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
|
|
1774
1741
|
fi
|
|
1775
1742
|
|
|
1776
1743
|
maybe_call_finish_helper write_result_summary
|
|
@@ -1778,7 +1745,7 @@ finish() {
|
|
|
1778
1745
|
# Generate inspect-report.md for inspect mode on success
|
|
1779
1746
|
if [ "$KASEKI_TASK_MODE" = "inspect" ] && [ "$STATUS" -eq 0 ]; then
|
|
1780
1747
|
if [ -x /app/scripts/generate-inspect-report.js ]; then
|
|
1781
|
-
node /app/scripts/generate-inspect-report.js
|
|
1748
|
+
node /app/scripts/generate-inspect-report.js ${KASEKI_RESULTS_DIR} 2>/dev/null || true
|
|
1782
1749
|
fi
|
|
1783
1750
|
fi
|
|
1784
1751
|
|
|
@@ -1823,7 +1790,7 @@ run_step_dry() {
|
|
|
1823
1790
|
printf '\n==> %s (DRY-RUN: simulated)\n' "$label"
|
|
1824
1791
|
emit_progress "$label" "started (dry-run)"
|
|
1825
1792
|
# Show what commands would be run without executing them
|
|
1826
|
-
printf '%s\n' "$@" >> /
|
|
1793
|
+
printf '%s\n' "$@" >> ${KASEKI_RESULTS_DIR}/validation.log
|
|
1827
1794
|
step_end="$(date +%s)"
|
|
1828
1795
|
emit_progress "$label" "finished (dry-run, simulated exit 0)"
|
|
1829
1796
|
record_stage_timing "$label" "0" "$((step_end - step_start))" "dry-run"
|
|
@@ -1858,9 +1825,9 @@ is_valid_git_mirror() {
|
|
|
1858
1825
|
}
|
|
1859
1826
|
|
|
1860
1827
|
run_direct_clone() {
|
|
1861
|
-
rm -rf /
|
|
1828
|
+
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1862
1829
|
GIT_CLONE_STRATEGY="direct_shallow"
|
|
1863
|
-
git clone --depth 1 --branch "$GIT_REF" "$REPO_URL" /
|
|
1830
|
+
git clone --depth 1 --branch "$GIT_REF" "$REPO_URL" ${KASEKI_WORKSPACE_DIR}/repo
|
|
1864
1831
|
}
|
|
1865
1832
|
|
|
1866
1833
|
clone_with_git_cache() {
|
|
@@ -1937,25 +1904,25 @@ clone_with_git_cache() {
|
|
|
1937
1904
|
fi
|
|
1938
1905
|
flock -u 9 || true
|
|
1939
1906
|
|
|
1940
|
-
rm -rf /
|
|
1907
|
+
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1941
1908
|
GIT_CLONE_STRATEGY="reference_shallow"
|
|
1942
|
-
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
|
|
1943
1910
|
clone_rc=$?
|
|
1944
1911
|
if [ "$clone_rc" -eq 0 ]; then
|
|
1945
1912
|
return 0
|
|
1946
1913
|
fi
|
|
1947
1914
|
|
|
1948
|
-
rm -rf /
|
|
1915
|
+
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1949
1916
|
GIT_CLONE_STRATEGY="mirror_local"
|
|
1950
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"
|
|
1951
|
-
git clone --branch "$GIT_REF" "$mirror" /
|
|
1918
|
+
git clone --branch "$GIT_REF" "$mirror" ${KASEKI_WORKSPACE_DIR}/repo
|
|
1952
1919
|
clone_rc=$?
|
|
1953
|
-
if [ "$clone_rc" -eq 0 ] && git -C /
|
|
1954
|
-
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
|
|
1955
1922
|
return 0
|
|
1956
1923
|
fi
|
|
1957
1924
|
|
|
1958
|
-
rm -rf /
|
|
1925
|
+
rm -rf ${KASEKI_WORKSPACE_DIR}/repo
|
|
1959
1926
|
GIT_CACHE_STATUS="mirror_clone_failed"
|
|
1960
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"
|
|
1961
1928
|
run_direct_clone
|
|
@@ -2232,7 +2199,7 @@ record_skipped_npm_script_command() {
|
|
|
2232
2199
|
local command="$1"
|
|
2233
2200
|
local script_name="$2"
|
|
2234
2201
|
local duration_seconds="$3"
|
|
2235
|
-
local log_file="${4
|
|
2202
|
+
local log_file="${4:-${KASEKI_RESULTS_DIR}/validation.log}"
|
|
2236
2203
|
local timings_file="${5:-$VALIDATION_TIMINGS_FILE}"
|
|
2237
2204
|
local skip_label="${6:-skipped}"
|
|
2238
2205
|
local classification="${7:-}"
|
|
@@ -2266,7 +2233,7 @@ classify_auto_lint_cleanup_command_exit() {
|
|
|
2266
2233
|
}
|
|
2267
2234
|
|
|
2268
2235
|
record_skipped_validation_command() {
|
|
2269
|
-
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"
|
|
2270
2237
|
}
|
|
2271
2238
|
|
|
2272
2239
|
has_typescript_project() {
|
|
@@ -2335,9 +2302,9 @@ run_typescript_precheck() {
|
|
|
2335
2302
|
if ! has_npm_build_command "$KASEKI_TS_CHECK_COMMAND"; then
|
|
2336
2303
|
local missing_script
|
|
2337
2304
|
missing_script="$(npm_run_script_name "$KASEKI_TS_CHECK_COMMAND")" || missing_script="$KASEKI_TS_CHECK_COMMAND"
|
|
2338
|
-
printf '\n==> TypeScript pre-check\n' | tee -a /
|
|
2339
|
-
printf 'Command: %s\n' "$KASEKI_TS_CHECK_COMMAND" | tee -a /
|
|
2340
|
-
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
|
|
2341
2308
|
emit_error_event "typescript_precheck_skipped_missing_script" "TypeScript check skipped: npm script '$missing_script' not defined" "continue"
|
|
2342
2309
|
emit_progress "typescript precheck" "skipped (npm script '$missing_script' not found)"
|
|
2343
2310
|
record_stage_timing "typescript precheck" 0 0 "skipped_missing_script"
|
|
@@ -2352,8 +2319,8 @@ run_typescript_precheck() {
|
|
|
2352
2319
|
{
|
|
2353
2320
|
printf '\n==> TypeScript pre-check\n'
|
|
2354
2321
|
printf 'Command: %s\n' "$KASEKI_TS_CHECK_COMMAND"
|
|
2355
|
-
eval "cd /
|
|
2356
|
-
} 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
|
|
2357
2324
|
ts_check_exit="${PIPESTATUS[0]}"
|
|
2358
2325
|
|
|
2359
2326
|
ts_check_end="$(date +%s)"
|
|
@@ -2377,7 +2344,7 @@ run_typescript_precheck() {
|
|
|
2377
2344
|
append_validation_failure_tail() {
|
|
2378
2345
|
local raw_log="$1"
|
|
2379
2346
|
local visible_log="$2"
|
|
2380
|
-
local quality_log="${3
|
|
2347
|
+
local quality_log="${3:-${KASEKI_RESULTS_DIR}/quality.log}"
|
|
2381
2348
|
|
|
2382
2349
|
if ! [ -s "$raw_log" ]; then
|
|
2383
2350
|
return 0
|
|
@@ -2426,14 +2393,14 @@ run_trailing_whitespace_cleanup_for_changed_tracked_text_files() {
|
|
|
2426
2393
|
collect_changed_file_set() {
|
|
2427
2394
|
local output_file="$1"
|
|
2428
2395
|
: > "$output_file"
|
|
2429
|
-
if [ ! -d /
|
|
2396
|
+
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
2430
2397
|
return 0
|
|
2431
2398
|
fi
|
|
2432
2399
|
|
|
2433
2400
|
{
|
|
2434
|
-
git -C /
|
|
2435
|
-
git -C /
|
|
2436
|
-
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
|
|
2437
2404
|
} | sed '/^$/d' | LC_ALL=C sort -u > "$output_file"
|
|
2438
2405
|
}
|
|
2439
2406
|
|
|
@@ -2441,7 +2408,7 @@ collect_changed_file_state() {
|
|
|
2441
2408
|
local output_file="$1"
|
|
2442
2409
|
local changed_files_file path staged_hash unstaged_hash content_hash state
|
|
2443
2410
|
: > "$output_file"
|
|
2444
|
-
if [ ! -d /
|
|
2411
|
+
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
2445
2412
|
return 0
|
|
2446
2413
|
fi
|
|
2447
2414
|
|
|
@@ -2450,14 +2417,14 @@ collect_changed_file_state() {
|
|
|
2450
2417
|
|
|
2451
2418
|
while IFS= read -r path || [ -n "$path" ]; do
|
|
2452
2419
|
[ -z "$path" ] && continue
|
|
2453
|
-
if git -C /
|
|
2454
|
-
staged_hash="$(git -C /
|
|
2455
|
-
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}')"
|
|
2456
2423
|
state="tracked:staged=${staged_hash}:unstaged=${unstaged_hash}"
|
|
2457
|
-
elif [ -f "/
|
|
2458
|
-
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}')"
|
|
2459
2426
|
state="untracked:file=${content_hash}"
|
|
2460
|
-
elif [ -d "/
|
|
2427
|
+
elif [ -d "${KASEKI_WORKSPACE_DIR}/repo/$path" ]; then
|
|
2461
2428
|
state="untracked:directory"
|
|
2462
2429
|
else
|
|
2463
2430
|
state="untracked:missing"
|
|
@@ -2475,25 +2442,25 @@ restore_cleanup_disallowed_changes() {
|
|
|
2475
2442
|
|
|
2476
2443
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
2477
2444
|
[ -z "$changed_file" ] && continue
|
|
2478
|
-
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
|
|
2479
2446
|
emit_event "auto_lint_cleanup_file_restored" "file=$changed_file" "reason=not_in_cleanup_allowlist"
|
|
2480
|
-
git -C /
|
|
2481
|
-
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
|
|
2482
2449
|
done < "$disallowed_file"
|
|
2483
2450
|
}
|
|
2484
2451
|
|
|
2485
2452
|
check_auto_lint_cleanup_allowlist() {
|
|
2486
2453
|
local before_file="$1"
|
|
2487
2454
|
local after_file="$2"
|
|
2488
|
-
local cleanup_created_file="/
|
|
2489
|
-
local disallowed_file="/
|
|
2490
|
-
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"
|
|
2491
2458
|
local allowlist_patterns allowlist_regex changed_file disallowed_count unrestored_count
|
|
2492
2459
|
|
|
2493
2460
|
: > "$cleanup_created_file"
|
|
2494
2461
|
: > "$disallowed_file"
|
|
2495
2462
|
: > "$post_restore_file"
|
|
2496
|
-
if [ ! -d /
|
|
2463
|
+
if [ ! -d ${KASEKI_WORKSPACE_DIR}/repo/.git ]; then
|
|
2497
2464
|
return 0
|
|
2498
2465
|
fi
|
|
2499
2466
|
|
|
@@ -2508,7 +2475,7 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2508
2475
|
if [ -n "$allowlist_regex" ] && printf '%s\n' "$changed_file" | grep -Eq "^(${allowlist_regex})$"; then
|
|
2509
2476
|
emit_event "quality_gate_rule_evaluated" "rule=auto_lint_cleanup_allowlist" "passed=true" "file=$changed_file"
|
|
2510
2477
|
else
|
|
2511
|
-
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
|
|
2512
2479
|
printf '%s\n' "$changed_file" >> "$disallowed_file"
|
|
2513
2480
|
emit_event "quality_gate_rule_evaluated" "rule=auto_lint_cleanup_allowlist" "passed=false" "file=$changed_file"
|
|
2514
2481
|
fi
|
|
@@ -2525,12 +2492,12 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2525
2492
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
2526
2493
|
[ -z "$changed_file" ] && continue
|
|
2527
2494
|
if grep -Fxq -- "$changed_file" "$post_restore_file"; then
|
|
2528
|
-
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
|
|
2529
2496
|
unrestored_count=$((unrestored_count + 1))
|
|
2530
2497
|
fi
|
|
2531
2498
|
done < "$disallowed_file"
|
|
2532
2499
|
if [ "$unrestored_count" -eq 0 ]; then
|
|
2533
|
-
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
|
|
2534
2501
|
emit_event "auto_lint_cleanup_allowlist_restoration_complete" "restored=$disallowed_count" "unrestored=0"
|
|
2535
2502
|
collect_git_artifacts
|
|
2536
2503
|
return 0
|
|
@@ -2543,7 +2510,7 @@ check_auto_lint_cleanup_allowlist() {
|
|
|
2543
2510
|
AUTO_LINT_CLEANUP_FAILURE_CLASSIFICATION="cleanup_allowlist_failed"
|
|
2544
2511
|
QUALITY_EXIT=7
|
|
2545
2512
|
QUALITY_FAILURE_REASON="auto_lint_cleanup_allowlist: $disallowed_count cleanup-created file(s) outside KASEKI_CHANGED_FILES_ALLOWLIST/KASEKI_VALIDATION_ALLOWLIST"
|
|
2546
|
-
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
|
|
2547
2514
|
emit_error_event "auto_lint_cleanup_allowlist_failed" "$QUALITY_FAILURE_REASON" "continue"
|
|
2548
2515
|
return 1
|
|
2549
2516
|
}
|
|
@@ -2603,12 +2570,12 @@ run_auto_lint_cleanup() {
|
|
|
2603
2570
|
return 0
|
|
2604
2571
|
fi
|
|
2605
2572
|
|
|
2606
|
-
if ! [ -d /
|
|
2573
|
+
if ! [ -d ${KASEKI_WORKSPACE_DIR}/repo ]; then
|
|
2607
2574
|
AUTO_LINT_CLEANUP_EXIT=1
|
|
2608
2575
|
AUTO_LINT_CLEANUP_RESULT="failed"
|
|
2609
2576
|
AUTO_LINT_CLEANUP_CLASSIFICATION="directory_missing"
|
|
2610
2577
|
AUTO_LINT_CLEANUP_FAILURE_CLASSIFICATION="directory_missing"
|
|
2611
|
-
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"
|
|
2612
2579
|
printf 'workspace_missing\t%s\t0\tclassification=directory_missing\n' "$AUTO_LINT_CLEANUP_EXIT" >> "$AUTO_LINT_CLEANUP_TIMINGS_FILE"
|
|
2613
2580
|
record_stage_timing "$stage_label" "$AUTO_LINT_CLEANUP_EXIT" "$(($(date +%s) - stage_start))" "directory_missing classification=directory_missing"
|
|
2614
2581
|
emit_event "auto_lint_cleanup_finished" "exit_code=$AUTO_LINT_CLEANUP_EXIT" "result=failed" "classification=directory_missing" "reason=directory_missing"
|
|
@@ -2616,8 +2583,8 @@ run_auto_lint_cleanup() {
|
|
|
2616
2583
|
return 0
|
|
2617
2584
|
fi
|
|
2618
2585
|
|
|
2619
|
-
cleanup_before_file="/
|
|
2620
|
-
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"
|
|
2621
2588
|
collect_changed_file_set "$cleanup_before_file"
|
|
2622
2589
|
|
|
2623
2590
|
set +e
|
|
@@ -2707,7 +2674,7 @@ baseline_validation_cache_key() {
|
|
|
2707
2674
|
}
|
|
2708
2675
|
|
|
2709
2676
|
baseline_validation_cache_dir() {
|
|
2710
|
-
local cache_root="${KASEKI_BASELINE_CACHE_ROOT
|
|
2677
|
+
local cache_root="${KASEKI_BASELINE_CACHE_ROOT:-${KASEKI_CACHE_DIR}/kaseki-baseline}"
|
|
2711
2678
|
local cache_key
|
|
2712
2679
|
cache_key="$(baseline_validation_cache_key)"
|
|
2713
2680
|
printf '%s/%s' "$cache_root" "$cache_key"
|
|
@@ -2741,19 +2708,19 @@ restore_baseline_validation_from_cache() {
|
|
|
2741
2708
|
fi
|
|
2742
2709
|
|
|
2743
2710
|
# Restore cached files to results directory
|
|
2744
|
-
mkdir -p
|
|
2711
|
+
mkdir -p ${KASEKI_RESULTS_DIR}
|
|
2745
2712
|
|
|
2746
|
-
if ! cp "$cache_dir/validation.log" /
|
|
2713
|
+
if ! cp "$cache_dir/validation.log" ${KASEKI_RESULTS_DIR}/validation-baseline.log 2>/dev/null; then
|
|
2747
2714
|
return 1
|
|
2748
2715
|
fi
|
|
2749
|
-
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
|
|
2750
2717
|
return 1
|
|
2751
2718
|
fi
|
|
2752
|
-
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
|
|
2753
2720
|
return 1
|
|
2754
2721
|
fi
|
|
2755
2722
|
if [ -f "$cache_dir/validation-env.log" ]; then
|
|
2756
|
-
cp "$cache_dir/validation-env.log" /
|
|
2723
|
+
cp "$cache_dir/validation-env.log" ${KASEKI_RESULTS_DIR}/validation-baseline-env.log 2>/dev/null || true
|
|
2757
2724
|
fi
|
|
2758
2725
|
|
|
2759
2726
|
return 0
|
|
@@ -2770,27 +2737,27 @@ save_baseline_validation_to_cache() {
|
|
|
2770
2737
|
mkdir -p "$cache_dir" || return 1
|
|
2771
2738
|
|
|
2772
2739
|
# Save validation results to cache
|
|
2773
|
-
if [ -f /
|
|
2774
|
-
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
|
|
2775
2742
|
fi
|
|
2776
2743
|
|
|
2777
|
-
if [ -f /
|
|
2778
|
-
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
|
|
2779
2746
|
fi
|
|
2780
2747
|
|
|
2781
|
-
if [ -f /
|
|
2782
|
-
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
|
|
2783
2750
|
fi
|
|
2784
2751
|
|
|
2785
|
-
if [ -f /
|
|
2786
|
-
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
|
|
2787
2754
|
fi
|
|
2788
2755
|
|
|
2789
2756
|
return 0
|
|
2790
2757
|
}
|
|
2791
2758
|
|
|
2792
2759
|
checkout_baseline_repo() {
|
|
2793
|
-
local baseline_dir="
|
|
2760
|
+
local baseline_dir="${KASEKI_WORKSPACE_BASELINE_DIR}"
|
|
2794
2761
|
|
|
2795
2762
|
# Clean up any existing baseline
|
|
2796
2763
|
rm -rf "$baseline_dir" 2>/dev/null || true
|
|
@@ -2809,20 +2776,20 @@ checkout_baseline_repo() {
|
|
|
2809
2776
|
emit_progress "baseline preparation" "installing baseline dependencies"
|
|
2810
2777
|
if ! cd "$baseline_dir" && npm ci --prefer-offline 2>>"$KASEKI_LOG_DIR/baseline-npm-ci.log"; then
|
|
2811
2778
|
emit_error_event "baseline_deps_failed" "Failed to install baseline dependencies" "continue"
|
|
2812
|
-
cd /
|
|
2779
|
+
cd ${KASEKI_WORKSPACE_DIR}/repo
|
|
2813
2780
|
return 1
|
|
2814
2781
|
fi
|
|
2815
|
-
cd /
|
|
2782
|
+
cd ${KASEKI_WORKSPACE_DIR}/repo
|
|
2816
2783
|
fi
|
|
2817
2784
|
|
|
2818
2785
|
return 0
|
|
2819
2786
|
}
|
|
2820
2787
|
|
|
2821
2788
|
run_baseline_validation() {
|
|
2822
|
-
local baseline_dir="
|
|
2823
|
-
local baseline_log="/
|
|
2824
|
-
local baseline_raw_log="/
|
|
2825
|
-
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"
|
|
2826
2793
|
local baseline_exit_var="BASELINE_VALIDATION_EXIT"
|
|
2827
2794
|
local baseline_detail_var="BASELINE_VALIDATION_FAILED_COMMAND_DETAIL"
|
|
2828
2795
|
local baseline_reason_var="BASELINE_VALIDATION_FAILURE_REASON"
|
|
@@ -2844,7 +2811,7 @@ run_baseline_validation() {
|
|
|
2844
2811
|
"$baseline_log" \
|
|
2845
2812
|
"$baseline_raw_log" \
|
|
2846
2813
|
"$baseline_timings" \
|
|
2847
|
-
"/
|
|
2814
|
+
"${KASEKI_RESULTS_DIR}/validation-baseline-env.log" \
|
|
2848
2815
|
"baseline_validation_failed" \
|
|
2849
2816
|
"$baseline_exit_var" \
|
|
2850
2817
|
"$baseline_detail_var" \
|
|
@@ -2864,10 +2831,10 @@ run_baseline_validation() {
|
|
|
2864
2831
|
}
|
|
2865
2832
|
|
|
2866
2833
|
analyze_test_failures_baseline() {
|
|
2867
|
-
local baseline_log="/
|
|
2868
|
-
local working_log="/
|
|
2869
|
-
local output_file="/
|
|
2870
|
-
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}"
|
|
2871
2838
|
|
|
2872
2839
|
if [ ! -f "$baseline_log" ] || [ ! -f "$working_log" ]; then
|
|
2873
2840
|
emit_progress "test failure analysis" "skipped (baseline or working log missing)"
|
|
@@ -2908,11 +2875,11 @@ analyze_test_failures_baseline() {
|
|
|
2908
2875
|
}
|
|
2909
2876
|
|
|
2910
2877
|
analyze_validation_failure_causality() {
|
|
2911
|
-
local baseline_log="/
|
|
2912
|
-
local post_change_log="/
|
|
2913
|
-
local git_diff="/
|
|
2914
|
-
local changed_files="/
|
|
2915
|
-
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"
|
|
2916
2883
|
|
|
2917
2884
|
# Skip if no baseline (first run)
|
|
2918
2885
|
if [ ! -f "$baseline_log" ]; then
|
|
@@ -3058,13 +3025,13 @@ run_validation_commands() {
|
|
|
3058
3025
|
record_stage_timing "$stage_label" 0 0 "skipped_by_config"
|
|
3059
3026
|
else
|
|
3060
3027
|
# Checkpoint: Verify working directory exists before validation.
|
|
3061
|
-
if ! [ -d /
|
|
3062
|
-
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"
|
|
3063
3030
|
printf 'Current pwd: %s\n' "$(pwd 2>&1 || echo '<pwd failed>')" | tee -a "$log_file"
|
|
3064
3031
|
printf 'Filesystem state:\n' | tee -a "$log_file"
|
|
3065
3032
|
find /workspace -maxdepth 3 -type f 2>&1 | head -100 | tee -a "$log_file"
|
|
3066
3033
|
validation_exit_ref=1
|
|
3067
|
-
validation_detail_ref="Working directory /
|
|
3034
|
+
validation_detail_ref="Working directory ${KASEKI_WORKSPACE_DIR}/repo missing before $stage_label"
|
|
3068
3035
|
validation_reason_ref="$failure_reason_prefix: workspace_missing"
|
|
3069
3036
|
record_stage_timing "$stage_label" "$validation_exit_ref" "$(($(date +%s) - stage_start))" "directory_missing"
|
|
3070
3037
|
else
|
|
@@ -3090,7 +3057,7 @@ run_validation_commands() {
|
|
|
3090
3057
|
printf '[validation command] working_directory=%s\n' "$(pwd 2>&1 || echo '<pwd failed>')"
|
|
3091
3058
|
printf '[validation command] node_version=%s\n' "$(node --version 2>&1 || echo '<node not found>')"
|
|
3092
3059
|
printf '[validation command] npm_version=%s\n' "$(npm --version 2>&1 || echo '<npm not found>')"
|
|
3093
|
-
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>')"
|
|
3094
3061
|
} | tee -a "$env_log"
|
|
3095
3062
|
# Use pipefail to catch errors in any stage of the pipe.
|
|
3096
3063
|
pipefail_was_enabled=0
|
|
@@ -3152,7 +3119,7 @@ run_validation_commands() {
|
|
|
3152
3119
|
{
|
|
3153
3120
|
printf '\n[DIAGNOSTICS] Validation pipeline stderr from filter/tee (last 50 lines):\n'
|
|
3154
3121
|
printf '%s\n' "$FILTER_STDERR_TAIL"
|
|
3155
|
-
} | tee -a "$log_file" /
|
|
3122
|
+
} | tee -a "$log_file" ${KASEKI_RESULTS_DIR}/quality.log
|
|
3156
3123
|
{
|
|
3157
3124
|
printf '\n[validation pipeline stderr tail]\n'
|
|
3158
3125
|
printf '%s\n' "$FILTER_STDERR_TAIL"
|
|
@@ -3180,7 +3147,7 @@ run_validation_commands() {
|
|
|
3180
3147
|
else
|
|
3181
3148
|
printf ' (No stderr captured from filter/tee)\n'
|
|
3182
3149
|
fi
|
|
3183
|
-
} | tee -a "$log_file" /
|
|
3150
|
+
} | tee -a "$log_file" ${KASEKI_RESULTS_DIR}/quality.log "$FILTER_DIAGNOSTICS_LOG"
|
|
3184
3151
|
fi
|
|
3185
3152
|
|
|
3186
3153
|
if [ "$validation_infra_failure" = "true" ] && [ "$validation_exit_ref" -eq 0 ]; then
|
|
@@ -3204,13 +3171,13 @@ run_validation_commands() {
|
|
|
3204
3171
|
printf '\n[DIAGNOSTICS] Validation command failed with directory access error:\n'
|
|
3205
3172
|
printf 'Working directory status:\n'
|
|
3206
3173
|
printf ' Current pwd: %s\n' "$(pwd 2>&1 || echo '<pwd failed>')"
|
|
3207
|
-
printf ' /
|
|
3208
|
-
if [ -L /
|
|
3209
|
-
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>')"
|
|
3210
3177
|
fi
|
|
3211
3178
|
printf 'Last 20 lines of validation log:\n'
|
|
3212
3179
|
tail -20 "$log_file"
|
|
3213
|
-
} | tee -a /
|
|
3180
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/quality.log
|
|
3214
3181
|
fi
|
|
3215
3182
|
# Fail-fast: if enabled, stop validation loop at first failure.
|
|
3216
3183
|
if [ "$KASEKI_VALIDATION_FAIL_FAST" -eq 1 ]; then
|
|
@@ -3291,7 +3258,7 @@ write_repo_memory_summary() {
|
|
|
3291
3258
|
return 0
|
|
3292
3259
|
fi
|
|
3293
3260
|
local updated_at
|
|
3294
|
-
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')"
|
|
3295
3262
|
updated_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
3296
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' || {
|
|
3297
3264
|
const fs = require('fs');
|
|
@@ -3471,9 +3438,9 @@ is_transient_goal_setting_failure() {
|
|
|
3471
3438
|
local stderr_content="$2"
|
|
3472
3439
|
|
|
3473
3440
|
# First, check if we have an explicit validation reason code from our helper
|
|
3474
|
-
if [ -f /
|
|
3441
|
+
if [ -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt ]; then
|
|
3475
3442
|
local reason_code
|
|
3476
|
-
reason_code=$(cat /
|
|
3443
|
+
reason_code=$(cat ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || echo "")
|
|
3477
3444
|
case "$reason_code" in
|
|
3478
3445
|
valid)
|
|
3479
3446
|
return 1
|
|
@@ -3652,7 +3619,7 @@ validate_goal_setting_artifact() {
|
|
|
3652
3619
|
local candidate_artifact="$1"
|
|
3653
3620
|
local final_artifact="$2"
|
|
3654
3621
|
local reason_file="$3"
|
|
3655
|
-
local results_dir="${KASEKI_RESULTS_DIR
|
|
3622
|
+
local results_dir="${KASEKI_RESULTS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
3656
3623
|
|
|
3657
3624
|
if ! [ -f "$candidate_artifact" ]; then
|
|
3658
3625
|
{
|
|
@@ -3692,7 +3659,7 @@ validate_goal_setting_artifact() {
|
|
|
3692
3659
|
validate_goal_setting_artifact_with_node() {
|
|
3693
3660
|
local candidate_artifact="$1"
|
|
3694
3661
|
local reason_file="$2"
|
|
3695
|
-
local results_dir="${KASEKI_RESULTS_DIR
|
|
3662
|
+
local results_dir="${KASEKI_RESULTS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
3696
3663
|
|
|
3697
3664
|
local validation_output
|
|
3698
3665
|
validation_output=$(node -e "
|
|
@@ -3877,13 +3844,13 @@ run_goal_setting_agent() {
|
|
|
3877
3844
|
set_current_stage "pi goal-setting agent"
|
|
3878
3845
|
|
|
3879
3846
|
if [ "$KASEKI_GOAL_SETTING" = "0" ]; then
|
|
3880
|
-
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
|
|
3881
3848
|
record_stage_timing "pi goal-setting agent" 0 0 "skipped_by_config"
|
|
3882
3849
|
return 0
|
|
3883
3850
|
fi
|
|
3884
3851
|
|
|
3885
3852
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
3886
|
-
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
|
|
3887
3854
|
record_stage_timing "pi goal-setting agent" 0 0 "dry_run=true"
|
|
3888
3855
|
return 0
|
|
3889
3856
|
fi
|
|
@@ -3895,23 +3862,23 @@ run_goal_setting_agent() {
|
|
|
3895
3862
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
3896
3863
|
timeout --signal=SIGTERM "$KASEKI_GOAL_SETTING_TIMEOUT_SECONDS" \
|
|
3897
3864
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_GOAL_SETTING_MODEL" "$goal_setting_prompt" \
|
|
3898
|
-
2> >(tee -a /
|
|
3865
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log >&2) \
|
|
3899
3866
|
| tee "$GOAL_SETTING_RAW_EVENTS" \
|
|
3900
|
-
| kaseki-pi-progress-stream /
|
|
3867
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
3901
3868
|
GOAL_SETTING_EXIT="${PIPESTATUS[0]}"
|
|
3902
3869
|
GOAL_SETTING_DURATION_SECONDS=$(($(date +%s) - goal_setting_start))
|
|
3903
3870
|
unset goal_setting_prompt
|
|
3904
3871
|
set +e
|
|
3905
3872
|
|
|
3906
|
-
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
|
|
3907
3874
|
GOAL_SETTING_EXIT=86
|
|
3908
|
-
goal_setting_validation_summary="$(cat /
|
|
3909
|
-
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"
|
|
3910
3877
|
fi
|
|
3911
3878
|
|
|
3912
3879
|
rm -f "$GOAL_SETTING_CANDIDATE_ARTIFACT"
|
|
3913
|
-
kaseki-pi-event-filter "$GOAL_SETTING_RAW_EVENTS" /
|
|
3914
|
-
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)"
|
|
3915
3882
|
|
|
3916
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"
|
|
3917
3884
|
|
|
@@ -3921,7 +3888,7 @@ run_goal_setting_agent() {
|
|
|
3921
3888
|
fi
|
|
3922
3889
|
|
|
3923
3890
|
emit_progress "pi goal-setting agent" "wrote goal-setting artifact"
|
|
3924
|
-
rm -f /
|
|
3891
|
+
rm -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || true
|
|
3925
3892
|
|
|
3926
3893
|
return 0
|
|
3927
3894
|
}
|
|
@@ -3956,7 +3923,7 @@ write_goal_setting_metrics() {
|
|
|
3956
3923
|
model: '${GOAL_SETTING_ACTUAL_MODEL:-unknown}',
|
|
3957
3924
|
timeout_seconds: ${KASEKI_GOAL_SETTING_TIMEOUT_SECONDS:-300}
|
|
3958
3925
|
};
|
|
3959
|
-
fs.writeFileSync('/
|
|
3926
|
+
fs.writeFileSync('${KASEKI_RESULTS_DIR}/goal-setting-metrics.json', JSON.stringify(metrics, null, 2) + '\n');
|
|
3960
3927
|
" 2>/dev/null || {
|
|
3961
3928
|
# Fallback to jq or printf if node fails
|
|
3962
3929
|
{
|
|
@@ -3972,7 +3939,7 @@ write_goal_setting_metrics() {
|
|
|
3972
3939
|
printf ' "model": "%s",\n' "${GOAL_SETTING_ACTUAL_MODEL:-unknown}"
|
|
3973
3940
|
printf ' "timeout_seconds": %d\n' "${KASEKI_GOAL_SETTING_TIMEOUT_SECONDS:-300}"
|
|
3974
3941
|
printf '}\n'
|
|
3975
|
-
} > /
|
|
3942
|
+
} > ${KASEKI_RESULTS_DIR}/goal-setting-metrics.json
|
|
3976
3943
|
}
|
|
3977
3944
|
}
|
|
3978
3945
|
|
|
@@ -3981,9 +3948,9 @@ classify_goal_setting_error() {
|
|
|
3981
3948
|
local stderr_content="$2"
|
|
3982
3949
|
|
|
3983
3950
|
# Check validation reason file first (most authoritative)
|
|
3984
|
-
if [ -f /
|
|
3951
|
+
if [ -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt ]; then
|
|
3985
3952
|
local reason_code
|
|
3986
|
-
reason_code=$(cat /
|
|
3953
|
+
reason_code=$(cat ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || echo "")
|
|
3987
3954
|
case "$reason_code" in
|
|
3988
3955
|
schema_mismatch)
|
|
3989
3956
|
echo "GOAL_SETTING_SCHEMA_MISMATCH"
|
|
@@ -4062,7 +4029,7 @@ run_goal_setting_agent_with_retry() {
|
|
|
4062
4029
|
set -e
|
|
4063
4030
|
|
|
4064
4031
|
# Append stderr to results for logging
|
|
4065
|
-
cat "$goal_setting_stderr_capture" >> /
|
|
4032
|
+
cat "$goal_setting_stderr_capture" >> ${KASEKI_RESULTS_DIR}/goal-setting-stderr.log 2>/dev/null || true
|
|
4066
4033
|
goal_setting_last_stderr="$(cat "$goal_setting_stderr_capture" 2>/dev/null || true)"
|
|
4067
4034
|
rm -f "$goal_setting_stderr_capture"
|
|
4068
4035
|
|
|
@@ -4094,7 +4061,7 @@ run_goal_setting_agent_with_retry() {
|
|
|
4094
4061
|
attempt=$((attempt + 1))
|
|
4095
4062
|
# Reset goal-setting artifacts for retry
|
|
4096
4063
|
rm -f "$GOAL_SETTING_ARTIFACT" "$GOAL_SETTING_RAW_EVENTS" 2>/dev/null || true
|
|
4097
|
-
rm -f /
|
|
4064
|
+
rm -f ${KASEKI_RESULTS_DIR}/goal-setting-validation-reason.txt 2>/dev/null || true
|
|
4098
4065
|
continue
|
|
4099
4066
|
fi
|
|
4100
4067
|
else
|
|
@@ -4128,9 +4095,9 @@ is_transient_scouting_failure() {
|
|
|
4128
4095
|
local stderr_content="$2"
|
|
4129
4096
|
|
|
4130
4097
|
# First, check if we have an explicit validation reason code from our helper
|
|
4131
|
-
if [ -f /
|
|
4098
|
+
if [ -f ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt ]; then
|
|
4132
4099
|
local reason_code
|
|
4133
|
-
reason_code=$(cat /
|
|
4100
|
+
reason_code=$(cat ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt 2>/dev/null || echo "")
|
|
4134
4101
|
case "$reason_code" in
|
|
4135
4102
|
valid)
|
|
4136
4103
|
# This shouldn't happen when exit_code=86, but just in case
|
|
@@ -4265,48 +4232,48 @@ run_scouting_agent() {
|
|
|
4265
4232
|
printf '\n==> pi scouting agent\n'
|
|
4266
4233
|
set_current_stage "pi scouting agent"
|
|
4267
4234
|
if [ "$KASEKI_SCOUTING" = "0" ]; then
|
|
4268
|
-
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
|
|
4269
4236
|
record_stage_timing "pi scouting agent" 0 0 "skipped_by_config"
|
|
4270
4237
|
return 0
|
|
4271
4238
|
fi
|
|
4272
4239
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
4273
|
-
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
|
|
4274
4241
|
record_stage_timing "pi scouting agent" 0 0 "dry_run=true"
|
|
4275
4242
|
return 0
|
|
4276
4243
|
fi
|
|
4277
4244
|
|
|
4278
4245
|
scouting_prompt="$(build_scouting_prompt)"
|
|
4279
4246
|
scouting_start="$(date +%s)"
|
|
4280
|
-
scout_dirty_before="$(git status --porcelain 2>> /
|
|
4281
|
-
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
|
|
4282
4249
|
set +e
|
|
4283
4250
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
4284
4251
|
timeout --signal=SIGTERM "$KASEKI_SCOUTING_TIMEOUT_SECONDS" \
|
|
4285
4252
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_SCOUTING_MODEL" "$scouting_prompt" \
|
|
4286
|
-
2> >(tee -a /
|
|
4253
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log >&2) \
|
|
4287
4254
|
| tee "$SCOUTING_RAW_EVENTS" \
|
|
4288
|
-
| kaseki-pi-progress-stream /
|
|
4255
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
4289
4256
|
SCOUTING_EXIT="${PIPESTATUS[0]}"
|
|
4290
4257
|
SCOUTING_DURATION_SECONDS=$(($(date +%s) - scouting_start))
|
|
4291
4258
|
unset scouting_prompt
|
|
4292
4259
|
set +e
|
|
4293
|
-
chmod -R u+w /
|
|
4260
|
+
chmod -R u+w ${KASEKI_WORKSPACE_DIR}/repo 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true
|
|
4294
4261
|
|
|
4295
|
-
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
|
|
4296
4263
|
SCOUTING_EXIT=86
|
|
4297
|
-
scouting_validation_summary="$(cat /
|
|
4298
|
-
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"
|
|
4299
4266
|
fi
|
|
4300
|
-
scout_dirty_after="$(git status --porcelain 2>> /
|
|
4267
|
+
scout_dirty_after="$(git status --porcelain 2>> ${KASEKI_RESULTS_DIR}/scouting-stderr.log || true)"
|
|
4301
4268
|
if [ "$SCOUTING_EXIT" -eq 0 ] && [ "$scout_dirty_before" != "$scout_dirty_after" ]; then
|
|
4302
4269
|
SCOUTING_EXIT=86
|
|
4303
4270
|
emit_error_event "pi_scouting_workspace_modified" "Read-only scouting changed repository state before coding" "exit"
|
|
4304
4271
|
fi
|
|
4305
4272
|
rm -f "$SCOUTING_CANDIDATE_ARTIFACT"
|
|
4306
|
-
git reset --hard -q HEAD 2>> /
|
|
4307
|
-
git clean -fd -q 2>> /
|
|
4308
|
-
kaseki-pi-event-filter "$SCOUTING_RAW_EVENTS" /
|
|
4309
|
-
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)"
|
|
4310
4277
|
record_stage_timing "pi scouting agent" "$SCOUTING_EXIT" "$SCOUTING_DURATION_SECONDS" "artifact=$SCOUTING_ARTIFACT timeout_seconds=$KASEKI_SCOUTING_TIMEOUT_SECONDS"
|
|
4311
4278
|
if [ "$SCOUTING_EXIT" -ne 0 ]; then
|
|
4312
4279
|
STATUS="$SCOUTING_EXIT"
|
|
@@ -4316,7 +4283,7 @@ run_scouting_agent() {
|
|
|
4316
4283
|
fi
|
|
4317
4284
|
emit_progress "pi scouting agent" "wrote scouting artifact"
|
|
4318
4285
|
# Clean up validation reason file on success
|
|
4319
|
-
rm -f /
|
|
4286
|
+
rm -f ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt 2>/dev/null || true
|
|
4320
4287
|
return 0
|
|
4321
4288
|
}
|
|
4322
4289
|
|
|
@@ -4344,7 +4311,7 @@ run_scouting_agent_with_retry() {
|
|
|
4344
4311
|
set -e
|
|
4345
4312
|
|
|
4346
4313
|
# Append stderr to results for logging
|
|
4347
|
-
cat "$scouting_stderr_capture" >> /
|
|
4314
|
+
cat "$scouting_stderr_capture" >> ${KASEKI_RESULTS_DIR}/scouting-stderr.log 2>/dev/null || true
|
|
4348
4315
|
scouting_last_stderr="$(cat "$scouting_stderr_capture" 2>/dev/null || true)"
|
|
4349
4316
|
rm -f "$scouting_stderr_capture"
|
|
4350
4317
|
|
|
@@ -4363,7 +4330,7 @@ run_scouting_agent_with_retry() {
|
|
|
4363
4330
|
# Reset scouting artifacts for retry
|
|
4364
4331
|
rm -f "$SCOUTING_ARTIFACT" "$SCOUTING_RAW_EVENTS" 2>/dev/null || true
|
|
4365
4332
|
# Clean up validation reason file from previous attempt
|
|
4366
|
-
rm -f /
|
|
4333
|
+
rm -f ${KASEKI_RESULTS_DIR}/scouting-validation-reason.txt 2>/dev/null || true
|
|
4367
4334
|
continue
|
|
4368
4335
|
fi
|
|
4369
4336
|
else
|
|
@@ -4387,13 +4354,13 @@ run_scouting_agent_with_retry() {
|
|
|
4387
4354
|
|
|
4388
4355
|
snapshot_attempt_artifacts() {
|
|
4389
4356
|
local attempt_dir
|
|
4390
|
-
attempt_dir="/
|
|
4357
|
+
attempt_dir="${KASEKI_RESULTS_DIR}/attempt-$1"
|
|
4391
4358
|
mkdir -p "$attempt_dir" 2>/dev/null || return 0
|
|
4392
4359
|
for artifact in \
|
|
4393
4360
|
pi-events.jsonl pi-summary.json pi-stderr.log git.diff git.status changed-files.txt \
|
|
4394
4361
|
quality.log validation.log validation-raw.log validation-timings.tsv goal-check.json; do
|
|
4395
|
-
if [ -e "
|
|
4396
|
-
cp "
|
|
4362
|
+
if [ -e "${KASEKI_RESULTS_DIR}/$artifact" ]; then
|
|
4363
|
+
cp "${KASEKI_RESULTS_DIR}/$artifact" "$attempt_dir/$artifact" 2>/dev/null || true
|
|
4397
4364
|
fi
|
|
4398
4365
|
done
|
|
4399
4366
|
}
|
|
@@ -4401,7 +4368,7 @@ snapshot_attempt_artifacts() {
|
|
|
4401
4368
|
collect_goal_check_feedback() {
|
|
4402
4369
|
local instance_name="$1"
|
|
4403
4370
|
local goal_setting_path="$GOAL_SETTING_ARTIFACT"
|
|
4404
|
-
local results_dir="${KASEKI_RESULTS_DIR
|
|
4371
|
+
local results_dir="${KASEKI_RESULTS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
4405
4372
|
local goal_check_path="$results_dir/goal-check.json"
|
|
4406
4373
|
local metadata_path="$results_dir/metadata.json"
|
|
4407
4374
|
local feedback_file="$results_dir/goal-feedback.jsonl"
|
|
@@ -4417,9 +4384,9 @@ collect_goal_check_feedback() {
|
|
|
4417
4384
|
|
|
4418
4385
|
collect_run_evaluation_feedback() {
|
|
4419
4386
|
local instance_name="$1"
|
|
4420
|
-
local run_evaluation_path="/
|
|
4421
|
-
local metadata_path="/
|
|
4422
|
-
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"
|
|
4423
4390
|
|
|
4424
4391
|
# Only collect if run-evaluation succeeded and artifacts exist
|
|
4425
4392
|
if [ ! -f "$run_evaluation_path" ] || [ "$RUN_EVALUATION_EXIT" -ne 0 ]; then
|
|
@@ -4433,14 +4400,14 @@ collect_run_evaluation_feedback() {
|
|
|
4433
4400
|
|
|
4434
4401
|
build_goal_check_prompt() {
|
|
4435
4402
|
local validation_tail progress_tail goal_setting_context validation_context test_impact_context causality_context
|
|
4436
|
-
validation_tail="$(tail -80 /
|
|
4403
|
+
validation_tail="$(tail -80 ${KASEKI_RESULTS_DIR}/validation.log 2>/dev/null || true)"
|
|
4437
4404
|
if [ -n "$(printf '%s' "$validation_tail" | tr -d '[:space:]')" ]; then
|
|
4438
4405
|
validation_context="Validation log tail (last 80 lines):
|
|
4439
4406
|
$validation_tail"
|
|
4440
4407
|
else
|
|
4441
|
-
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."
|
|
4442
4409
|
fi
|
|
4443
|
-
progress_tail="$(tail -80 /
|
|
4410
|
+
progress_tail="$(tail -80 ${KASEKI_RESULTS_DIR}/progress.log 2>/dev/null || true)"
|
|
4444
4411
|
if [ -s "$TEST_IMPACT_WARNINGS_ARTIFACT" ]; then
|
|
4445
4412
|
test_impact_context="Static test-impact warnings artifact ($TEST_IMPACT_WARNINGS_ARTIFACT):
|
|
4446
4413
|
$(cat "$TEST_IMPACT_WARNINGS_ARTIFACT" 2>/dev/null)
|
|
@@ -4466,7 +4433,7 @@ $(head -n 200 "$GOAL_SETTING_ARTIFACT" 2>/dev/null)
|
|
|
4466
4433
|
fi
|
|
4467
4434
|
|
|
4468
4435
|
# Include causality assessment if available (helps interpret validation failures)
|
|
4469
|
-
if [ -f /
|
|
4436
|
+
if [ -f ${KASEKI_RESULTS_DIR}/validation-causality-analysis.json ]; then
|
|
4470
4437
|
# shellcheck disable=SC2016
|
|
4471
4438
|
causality_context="VALIDATION FAILURE CAUSALITY ASSESSMENT:
|
|
4472
4439
|
|
|
@@ -4526,11 +4493,11 @@ Determine if the agent successfully met the requirements specified in the goal-s
|
|
|
4526
4493
|
|
|
4527
4494
|
**Agent Artifacts** (use to verify requirements were met):
|
|
4528
4495
|
- Scouting report: $SCOUTING_ARTIFACT
|
|
4529
|
-
- Changed files: /
|
|
4530
|
-
- Git diff: /
|
|
4531
|
-
- 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
|
|
4532
4499
|
- Static test-impact warnings (non-blocking): $TEST_IMPACT_WARNINGS_ARTIFACT
|
|
4533
|
-
- Coding-agent events: /
|
|
4500
|
+
- Coding-agent events: ${KASEKI_RESULTS_DIR}/pi-summary.json and ${KASEKI_RESULTS_DIR}/pi-events.jsonl
|
|
4534
4501
|
|
|
4535
4502
|
## Evaluation Framework: SMART Criteria Check
|
|
4536
4503
|
|
|
@@ -4542,6 +4509,14 @@ Determine if the agent successfully met the requirements specified in the goal-s
|
|
|
4542
4509
|
|
|
4543
4510
|
For each dimension, provide evidence by citing specific file locations, test names, or validation results.
|
|
4544
4511
|
|
|
4512
|
+
## Success Criteria Assessment Contract
|
|
4513
|
+
|
|
4514
|
+
Use this contract when reading the goal-setting artifact:
|
|
4515
|
+
|
|
4516
|
+
- GOAL_CHECK_CONTRACT_PER_CRITERION_SMART: Assess each success criterion or acceptance criterion independently against all five SMART dimensions (Specific, Measurable, Achievable, Relevant, Time-bound), not just the overall goal.
|
|
4517
|
+
- GOAL_CHECK_CONTRACT_EVIDENCE_REQUIRED: For every met or unmet criterion assessment, cite concrete evidence from the diff, changed files, tests, validation results, or other listed artifacts.
|
|
4518
|
+
- GOAL_CHECK_CONTRACT_MEASURABLE_ACCEPTANCE_CRITERIA: Treat measurable acceptance criteria as observable pass/fail conditions; flag vague goals or intent statements as insufficient unless the implementation evidence maps them to concrete, verifiable outcomes.
|
|
4519
|
+
|
|
4545
4520
|
## Evidence Requirements
|
|
4546
4521
|
|
|
4547
4522
|
Evidence must be SPECIFIC and VERIFIABLE. Reference concrete artifacts:
|
|
@@ -4581,7 +4556,7 @@ Example: "Null handling is done (parseRole returns 'Unnamed Role'), but test cov
|
|
|
4581
4556
|
- Do not print, inspect, or expose environment variables, secrets, credentials, API keys, or mounted secret files.
|
|
4582
4557
|
- Decide whether the goal requirements were realized. Do not evaluate code style, architecture, or elegance.
|
|
4583
4558
|
- If anti-patterns were specified in goal-setting (do_not_modify, do_not_break), verify they were respected.
|
|
4584
|
-
- 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.
|
|
4585
4560
|
|
|
4586
4561
|
## Required JSON artifact
|
|
4587
4562
|
|
|
@@ -4632,12 +4607,12 @@ run_goal_check() {
|
|
|
4632
4607
|
printf '\n==> goal check\n'
|
|
4633
4608
|
set_current_stage "goal check"
|
|
4634
4609
|
if [ "$KASEKI_GOAL_CHECK" != "1" ]; then
|
|
4635
|
-
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
|
|
4636
4611
|
record_stage_timing "goal check" 0 0 "skipped_by_config attempt=$attempt"
|
|
4637
4612
|
return 0
|
|
4638
4613
|
fi
|
|
4639
4614
|
if [ ! -s "$SCOUTING_ARTIFACT" ]; then
|
|
4640
|
-
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
|
|
4641
4616
|
record_stage_timing "goal check" 0 0 "skipped_no_scouting attempt=$attempt"
|
|
4642
4617
|
return 0
|
|
4643
4618
|
fi
|
|
@@ -4648,15 +4623,15 @@ run_goal_check() {
|
|
|
4648
4623
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
4649
4624
|
timeout --signal=SIGTERM "$KASEKI_GOAL_CHECK_TIMEOUT_SECONDS" \
|
|
4650
4625
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_GOAL_CHECK_MODEL" "$goal_prompt" \
|
|
4651
|
-
2> >(tee -a /
|
|
4626
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/goal-check-stderr.log >&2) \
|
|
4652
4627
|
| tee "$GOAL_CHECK_RAW_EVENTS" \
|
|
4653
|
-
| kaseki-pi-progress-stream /
|
|
4628
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
4654
4629
|
GOAL_CHECK_EXIT="${PIPESTATUS[0]}"
|
|
4655
4630
|
unset goal_prompt
|
|
4656
4631
|
GOAL_CHECK_DURATION_SECONDS=$((GOAL_CHECK_DURATION_SECONDS + $(date +%s) - goal_start))
|
|
4657
4632
|
set +e
|
|
4658
4633
|
|
|
4659
|
-
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
|
|
4660
4635
|
|
|
4661
4636
|
if [ "$GOAL_CHECK_EXIT" -eq 0 ] && [ ! -f "$GOAL_CHECK_CANDIDATE_ARTIFACT" ]; then
|
|
4662
4637
|
# Recover from goal-check agents that printed the verdict in assistant text instead of writing the artifact.
|
|
@@ -4754,38 +4729,38 @@ if (valid.size === 1) {
|
|
|
4754
4729
|
const recovered = [...valid.values()][0];
|
|
4755
4730
|
fs.writeFileSync(candidatePath, JSON.stringify(recovered, null, 2) + "\n");
|
|
4756
4731
|
const note = { timestamp: new Date().toISOString(), attempt, event: "goal_check_artifact_recovered_from_assistant_text", artifact: candidatePath, raw_events: rawPath, filtered_events: filteredPath };
|
|
4757
|
-
fs.appendFileSync("/
|
|
4732
|
+
fs.appendFileSync(process.env.KASEKI_RESULTS_DIR + "/goal-check-stderr.log", JSON.stringify(note) + "\n");
|
|
4758
4733
|
}
|
|
4759
|
-
' "$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
|
|
4760
4735
|
fi
|
|
4761
4736
|
|
|
4762
|
-
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
|
|
4763
4738
|
GOAL_CHECK_EXIT=86
|
|
4764
|
-
goal_check_validation_reason="$(cat /
|
|
4765
|
-
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')"
|
|
4766
4741
|
case "$goal_check_validation_reason" in
|
|
4767
4742
|
missing_file)
|
|
4768
4743
|
GOAL_CHECK_FAILURE_REASON="goal_check_artifact_missing"
|
|
4769
|
-
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"
|
|
4770
4745
|
;;
|
|
4771
4746
|
malformed_json)
|
|
4772
4747
|
GOAL_CHECK_FAILURE_REASON="goal_check_artifact_malformed"
|
|
4773
|
-
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"
|
|
4774
4749
|
;;
|
|
4775
4750
|
*)
|
|
4776
4751
|
GOAL_CHECK_FAILURE_REASON="goal_check_artifact_invalid"
|
|
4777
|
-
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"
|
|
4778
4753
|
;;
|
|
4779
4754
|
esac
|
|
4780
4755
|
fi
|
|
4781
4756
|
rm -f "$GOAL_CHECK_CANDIDATE_ARTIFACT"
|
|
4782
|
-
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)"
|
|
4783
4758
|
|
|
4784
4759
|
if [ "$GOAL_CHECK_EXIT" -eq 0 ]; then
|
|
4785
|
-
verdict_met="$(node -e 'const v=require(
|
|
4786
|
-
retry_prompt="$(node -e 'const v=require(
|
|
4787
|
-
verdict_summary="$(node -e 'const v=require(
|
|
4788
|
-
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)"
|
|
4789
4764
|
if [ "$verdict_met" = "true" ]; then
|
|
4790
4765
|
GOAL_CHECK_MET=true
|
|
4791
4766
|
GOAL_CHECK_RETRY_PROMPT=""
|
|
@@ -4808,12 +4783,12 @@ if (valid.size === 1) {
|
|
|
4808
4783
|
|
|
4809
4784
|
build_run_evaluation_prompt() {
|
|
4810
4785
|
local validation_tail progress_tail stage_timings dependency_cache restoration_report draft_pr_body metadata_text goal_setting_context test_impact_context
|
|
4811
|
-
validation_tail="$(tail -80 /
|
|
4812
|
-
progress_tail="$(tail -80 /
|
|
4813
|
-
stage_timings="$(tail -80 /
|
|
4814
|
-
dependency_cache="$(tail -80 /
|
|
4815
|
-
restoration_report="$(tail -80 /
|
|
4816
|
-
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)"
|
|
4817
4792
|
draft_pr_body="$(build_pr_body)"
|
|
4818
4793
|
if [ -s "$TEST_IMPACT_WARNINGS_ARTIFACT" ]; then
|
|
4819
4794
|
test_impact_context="Static test-impact warnings artifact ($TEST_IMPACT_WARNINGS_ARTIFACT):
|
|
@@ -4859,15 +4834,15 @@ This is NOT another goal-check. The goal-check evaluator already determined if t
|
|
|
4859
4834
|
- Quality metrics, SMART criteria, anti-patterns
|
|
4860
4835
|
|
|
4861
4836
|
**Agent Artifacts** (verify goal was realized):
|
|
4862
|
-
- Goal-check verdict: /
|
|
4863
|
-
- Scouting report: /
|
|
4864
|
-
- Changed files: /
|
|
4865
|
-
- Git diff and status: /
|
|
4866
|
-
- 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
|
|
4867
4842
|
- Static test-impact warnings (non-blocking): $TEST_IMPACT_WARNINGS_ARTIFACT
|
|
4868
|
-
- Stage timings: /
|
|
4869
|
-
- Progress log: /
|
|
4870
|
-
- 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
|
|
4871
4846
|
|
|
4872
4847
|
## Evaluation Framework
|
|
4873
4848
|
|
|
@@ -5081,12 +5056,12 @@ run_run_evaluation() {
|
|
|
5081
5056
|
printf '\n==> run evaluation\n'
|
|
5082
5057
|
set_current_stage "run evaluation"
|
|
5083
5058
|
if [ "$KASEKI_RUN_EVALUATION" != "1" ]; then
|
|
5084
|
-
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
|
|
5085
5060
|
record_stage_timing "run evaluation" 0 0 "skipped_by_config"
|
|
5086
5061
|
return 0
|
|
5087
5062
|
fi
|
|
5088
5063
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
5089
|
-
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
|
|
5090
5065
|
record_stage_timing "run evaluation" 0 0 "dry_run=true"
|
|
5091
5066
|
return 0
|
|
5092
5067
|
fi
|
|
@@ -5095,19 +5070,19 @@ run_run_evaluation() {
|
|
|
5095
5070
|
write_metadata "$STATUS"
|
|
5096
5071
|
evaluation_prompt="$(build_run_evaluation_prompt)"
|
|
5097
5072
|
evaluation_start="$(date +%s)"
|
|
5098
|
-
eval_dirty_before="$(git status --porcelain 2>> /
|
|
5099
|
-
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
|
|
5100
5075
|
set +e
|
|
5101
5076
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
5102
5077
|
timeout --signal=SIGTERM "$KASEKI_RUN_EVALUATION_TIMEOUT_SECONDS" \
|
|
5103
5078
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_RUN_EVALUATION_MODEL" "$evaluation_prompt" \
|
|
5104
|
-
2> >(tee -a /
|
|
5079
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log >&2) \
|
|
5105
5080
|
| tee "$RUN_EVALUATION_RAW_EVENTS" \
|
|
5106
|
-
| kaseki-pi-progress-stream /
|
|
5081
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
5107
5082
|
RUN_EVALUATION_EXIT="${PIPESTATUS[0]}"
|
|
5108
5083
|
unset evaluation_prompt
|
|
5109
5084
|
RUN_EVALUATION_DURATION_SECONDS=$((RUN_EVALUATION_DURATION_SECONDS + $(date +%s) - evaluation_start))
|
|
5110
|
-
chmod -R u+w /
|
|
5085
|
+
chmod -R u+w ${KASEKI_WORKSPACE_DIR}/repo 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true
|
|
5111
5086
|
set +e
|
|
5112
5087
|
|
|
5113
5088
|
if [ "$RUN_EVALUATION_EXIT" -eq 0 ] && ! node -e '
|
|
@@ -5137,15 +5112,15 @@ artifact.timestamp = new Date().toISOString();
|
|
|
5137
5112
|
artifact.model = model;
|
|
5138
5113
|
artifact.actual_model = actualModel;
|
|
5139
5114
|
fs.writeFileSync(output, JSON.stringify(artifact, null, 2) + "\n");
|
|
5140
|
-
' "$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
|
|
5141
5116
|
RUN_EVALUATION_EXIT=86
|
|
5142
5117
|
emit_error_event "run_evaluation_artifact_invalid" "Run-evaluation Pi did not write a schema-valid JSON artifact" "continue"
|
|
5143
5118
|
fi
|
|
5144
5119
|
rm -f "$RUN_EVALUATION_CANDIDATE_ARTIFACT"
|
|
5145
|
-
kaseki-pi-event-filter "$RUN_EVALUATION_RAW_EVENTS" /
|
|
5146
|
-
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)"
|
|
5147
5122
|
if [ -s "$RUN_EVALUATION_ARTIFACT" ]; then
|
|
5148
|
-
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
|
|
5149
5124
|
const fs = require('fs');
|
|
5150
5125
|
const [file, actualModel] = process.argv.slice(2);
|
|
5151
5126
|
const artifact = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
@@ -5154,12 +5129,12 @@ fs.writeFileSync(file, JSON.stringify(artifact, null, 2) + '\n');
|
|
|
5154
5129
|
NODE
|
|
5155
5130
|
fi
|
|
5156
5131
|
|
|
5157
|
-
eval_dirty_after="$(git status --porcelain 2>> /
|
|
5132
|
+
eval_dirty_after="$(git status --porcelain 2>> ${KASEKI_RESULTS_DIR}/run-evaluation-stderr.log || true)"
|
|
5158
5133
|
if [ "$eval_dirty_before" != "$eval_dirty_after" ]; then
|
|
5159
5134
|
RUN_EVALUATION_EXIT=86
|
|
5160
5135
|
emit_error_event "run_evaluation_workspace_modified" "Read-only run evaluation changed repository state; restoring workspace" "continue"
|
|
5161
|
-
git reset --hard -q HEAD 2>> /
|
|
5162
|
-
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
|
|
5163
5138
|
fi
|
|
5164
5139
|
|
|
5165
5140
|
if [ "$RUN_EVALUATION_EXIT" -ne 0 ] || [ ! -s "$RUN_EVALUATION_ARTIFACT" ]; then
|
|
@@ -5256,19 +5231,19 @@ META
|
|
|
5256
5231
|
log_github_private_key_metadata() {
|
|
5257
5232
|
local key_file="$1"
|
|
5258
5233
|
local health_log="$2"
|
|
5259
|
-
local metadata_file="/
|
|
5234
|
+
local metadata_file="${KASEKI_RESULTS_DIR}/github-app-private-key-metadata.json"
|
|
5260
5235
|
github_private_key_metadata_json "$key_file" > "$metadata_file"
|
|
5261
5236
|
printf '[health-check] GitHub App private key metadata: %s\n' "$(tr -d '\n' < "$metadata_file")" | tee -a "$health_log"
|
|
5262
5237
|
}
|
|
5263
5238
|
|
|
5264
5239
|
|
|
5265
5240
|
github_askpass_runtime_dir() {
|
|
5266
|
-
printf '%s\n' "${KASEKI_GITHUB_ASKPASS_DIR
|
|
5241
|
+
printf '%s\n' "${KASEKI_GITHUB_ASKPASS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
5267
5242
|
}
|
|
5268
5243
|
|
|
5269
5244
|
create_github_askpass_helper() {
|
|
5270
5245
|
local log_file log_prefix askpass_dir askpass_file username_smoke_output password_smoke_output
|
|
5271
|
-
log_file="${1
|
|
5246
|
+
log_file="${1:-${KASEKI_RESULTS_DIR}/git-push.log}"
|
|
5272
5247
|
log_prefix="${2:-[github-askpass]}"
|
|
5273
5248
|
GITHUB_ASKPASS_FILE=""
|
|
5274
5249
|
|
|
@@ -5346,7 +5321,7 @@ EOF_ASKPASS
|
|
|
5346
5321
|
check_github_operations_health() {
|
|
5347
5322
|
# Preflight health check for github operations before pi agent runs
|
|
5348
5323
|
# Tests: GitHub App secrets, git config, Node.js token generation capability
|
|
5349
|
-
local health_log="${KASEKI_HEALTH_LOG
|
|
5324
|
+
local health_log="${KASEKI_HEALTH_LOG:-${KASEKI_RESULTS_DIR}/github-health-check.log}"
|
|
5350
5325
|
github_preflight_fail() {
|
|
5351
5326
|
local classification="$1"
|
|
5352
5327
|
local remediation="$2"
|
|
@@ -5600,7 +5575,7 @@ validate_github_api_response() {
|
|
|
5600
5575
|
local http_status response log_file error_type error_message json_valid
|
|
5601
5576
|
http_status="$1"
|
|
5602
5577
|
response="$2"
|
|
5603
|
-
log_file="${3
|
|
5578
|
+
log_file="${3:-${KASEKI_RESULTS_DIR}/git-push.log}"
|
|
5604
5579
|
|
|
5605
5580
|
# Try to parse error info from response
|
|
5606
5581
|
error_type="unknown"
|
|
@@ -5708,7 +5683,7 @@ apply_github_pr_labels() {
|
|
|
5708
5683
|
repo="$2"
|
|
5709
5684
|
issue_number="$3"
|
|
5710
5685
|
token="$4"
|
|
5711
|
-
log_file="${5
|
|
5686
|
+
log_file="${5:-${KASEKI_RESULTS_DIR}/git-push.log}"
|
|
5712
5687
|
|
|
5713
5688
|
if [ -z "$owner" ] || [ -z "$repo" ] || [ -z "$issue_number" ] || [ -z "$token" ]; then
|
|
5714
5689
|
printf 'Warning: skipping PR label application because owner, repo, issue number, or token is missing\n' | tee -a "$log_file" >&2
|
|
@@ -5762,7 +5737,7 @@ request_owner_review() {
|
|
|
5762
5737
|
local pr_response token log_file owner_login owner_type pr_number repo owner
|
|
5763
5738
|
pr_response="$1"
|
|
5764
5739
|
token="$2"
|
|
5765
|
-
log_file="${3
|
|
5740
|
+
log_file="${3:-${KASEKI_RESULTS_DIR}/git-push.log}"
|
|
5766
5741
|
|
|
5767
5742
|
if [ -z "$pr_response" ] || [ -z "$token" ]; then
|
|
5768
5743
|
printf 'Warning: skipping owner review request because PR response or token is missing\n' | tee -a "$log_file" >&2
|
|
@@ -5827,7 +5802,7 @@ request_owner_review() {
|
|
|
5827
5802
|
|
|
5828
5803
|
# Request owner review with retry logic
|
|
5829
5804
|
local retry_count=0 max_retries=2 request_success=0 backoff_delay=2
|
|
5830
|
-
local review_request_log="/
|
|
5805
|
+
local review_request_log="${KASEKI_RESULTS_DIR}/owner-review-request.log"
|
|
5831
5806
|
: > "$review_request_log"
|
|
5832
5807
|
|
|
5833
5808
|
while [ $retry_count -le "$max_retries" ]; do
|
|
@@ -6020,7 +5995,7 @@ derive_pr_title() {
|
|
|
6020
5995
|
|
|
6021
5996
|
candidate="$(printf '%s' "${TASK_PROMPT:-}" | sanitize_pr_metadata_text)"
|
|
6022
5997
|
prompt_for_prefix="$candidate"
|
|
6023
|
-
if [ -s /
|
|
5998
|
+
if [ -s ${KASEKI_RESULTS_DIR}/result-summary.md ]; then
|
|
6024
5999
|
summary_candidate="$(
|
|
6025
6000
|
awk '
|
|
6026
6001
|
/^##[[:space:]]+Summary[[:space:]]*$/ { in_summary=1; next }
|
|
@@ -6031,13 +6006,13 @@ derive_pr_title() {
|
|
|
6031
6006
|
sub(/^[[:space:]]*[0-9]+[.)][[:space:]]+/, "", line)
|
|
6032
6007
|
if (line !~ /^[[:space:]]*$/) { print line; exit }
|
|
6033
6008
|
}
|
|
6034
|
-
' /
|
|
6009
|
+
' ${KASEKI_RESULTS_DIR}/result-summary.md 2>/dev/null | sanitize_pr_metadata_text
|
|
6035
6010
|
)"
|
|
6036
6011
|
fi
|
|
6037
6012
|
if [ -n "$summary_candidate" ]; then
|
|
6038
6013
|
candidate="$summary_candidate"
|
|
6039
|
-
elif [ -z "$candidate" ] && [ -s /
|
|
6040
|
-
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)"
|
|
6041
6016
|
fi
|
|
6042
6017
|
|
|
6043
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:]]+$//')"
|
|
@@ -6047,8 +6022,8 @@ derive_pr_title() {
|
|
|
6047
6022
|
candidate="$stripped"
|
|
6048
6023
|
fi
|
|
6049
6024
|
|
|
6050
|
-
if [ -s /
|
|
6051
|
-
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)"
|
|
6052
6027
|
else
|
|
6053
6028
|
changed_files=""
|
|
6054
6029
|
fi
|
|
@@ -6119,7 +6094,7 @@ format_pr_command_results() {
|
|
|
6119
6094
|
}
|
|
6120
6095
|
|
|
6121
6096
|
format_pr_changed_files() {
|
|
6122
|
-
local changed_files_file="/
|
|
6097
|
+
local changed_files_file="${KASEKI_RESULTS_DIR}/changed-files.txt"
|
|
6123
6098
|
local details_threshold=8
|
|
6124
6099
|
if [ ! -s "$changed_files_file" ]; then
|
|
6125
6100
|
printf '0 files changed.\n'
|
|
@@ -6209,8 +6184,8 @@ build_pr_agent_review() {
|
|
|
6209
6184
|
case "$validation_pass_flag" in
|
|
6210
6185
|
''|*[!0-9-]*) validation_pass_flag=0 ;;
|
|
6211
6186
|
esac
|
|
6212
|
-
local goal_file="/
|
|
6213
|
-
local scouting_file="/
|
|
6187
|
+
local goal_file="${KASEKI_RESULTS_DIR}/goal-check.json"
|
|
6188
|
+
local scouting_file="${KASEKI_RESULTS_DIR}/scouting.json"
|
|
6214
6189
|
local goal_summary evidence missing validation_notes risks
|
|
6215
6190
|
|
|
6216
6191
|
goal_summary=""
|
|
@@ -6259,7 +6234,7 @@ NODE
|
|
|
6259
6234
|
}
|
|
6260
6235
|
|
|
6261
6236
|
build_pr_agent_evaluation() {
|
|
6262
|
-
local evaluation_file="/
|
|
6237
|
+
local evaluation_file="${KASEKI_RESULTS_DIR}/run-evaluation.json"
|
|
6263
6238
|
if [ ! -s "$evaluation_file" ]; then
|
|
6264
6239
|
return 0
|
|
6265
6240
|
fi
|
|
@@ -6357,8 +6332,8 @@ NODE
|
|
|
6357
6332
|
}
|
|
6358
6333
|
|
|
6359
6334
|
build_pr_improvements_summary() {
|
|
6360
|
-
local changed_files_file="/
|
|
6361
|
-
local diff_file="/
|
|
6335
|
+
local changed_files_file="${KASEKI_RESULTS_DIR}/changed-files.txt"
|
|
6336
|
+
local diff_file="${KASEKI_RESULTS_DIR}/git.diff"
|
|
6362
6337
|
local total=0 source_count=0 test_count=0 docs_count=0 config_count=0 other_count=0
|
|
6363
6338
|
local path lower additions deletions summary_rows=0 summary_source=""
|
|
6364
6339
|
local artifact raw_line line safe_line summary_capture=0 content json_text
|
|
@@ -6378,10 +6353,10 @@ build_pr_improvements_summary() {
|
|
|
6378
6353
|
done < "$changed_files_file"
|
|
6379
6354
|
fi
|
|
6380
6355
|
|
|
6381
|
-
if [ -s /
|
|
6382
|
-
summary_source="/
|
|
6356
|
+
if [ -s ${KASEKI_RESULTS_DIR}/result-summary.md ]; then
|
|
6357
|
+
summary_source="${KASEKI_RESULTS_DIR}/result-summary.md"
|
|
6383
6358
|
else
|
|
6384
|
-
for artifact in /
|
|
6359
|
+
for artifact in ${KASEKI_RESULTS_DIR}/analysis.md ${KASEKI_RESULTS_DIR}/pi-summary.json; do
|
|
6385
6360
|
if [ -s "$artifact" ]; then
|
|
6386
6361
|
summary_source="$artifact"
|
|
6387
6362
|
break
|
|
@@ -6441,7 +6416,7 @@ EOF_JSON_SUMMARY
|
|
|
6441
6416
|
continue
|
|
6442
6417
|
;;
|
|
6443
6418
|
esac
|
|
6444
|
-
if [ "$summary_capture" -eq 0 ] && [ "$summary_source" = "/
|
|
6419
|
+
if [ "$summary_capture" -eq 0 ] && [ "$summary_source" = "${KASEKI_RESULTS_DIR}/result-summary.md" ]; then
|
|
6445
6420
|
continue
|
|
6446
6421
|
fi
|
|
6447
6422
|
line="$(printf '%s' "$raw_line" | sanitize_pr_metadata_text)"
|
|
@@ -6567,7 +6542,7 @@ $(build_pr_improvements_summary)
|
|
|
6567
6542
|
## Agent review
|
|
6568
6543
|
$(build_pr_agent_review "$all_validation_statuses_pass")
|
|
6569
6544
|
|
|
6570
|
-
$(if [ -s /
|
|
6545
|
+
$(if [ -s ${KASEKI_RESULTS_DIR}/run-evaluation.json ]; then printf '## Agent evaluation\n%s\n\n' "$(build_pr_agent_evaluation)"; fi)
|
|
6571
6546
|
## Validation
|
|
6572
6547
|
### Validation statuses
|
|
6573
6548
|
- Pre-agent validation: $pre_validation_status
|
|
@@ -6616,11 +6591,11 @@ run_github_operations() {
|
|
|
6616
6591
|
owner="$GITHUB_REPO_OWNER"
|
|
6617
6592
|
repo="$GITHUB_REPO_NAME"
|
|
6618
6593
|
else
|
|
6619
|
-
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
|
|
6620
6595
|
return 7
|
|
6621
6596
|
fi
|
|
6622
6597
|
|
|
6623
|
-
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
|
|
6624
6599
|
GITHUB_OPERATION_PHASE="setup"
|
|
6625
6600
|
|
|
6626
6601
|
# Set git user for commits
|
|
@@ -6629,7 +6604,7 @@ run_github_operations() {
|
|
|
6629
6604
|
|
|
6630
6605
|
# Generate GitHub App installation token
|
|
6631
6606
|
GITHUB_OPERATION_PHASE="token_generation"
|
|
6632
|
-
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
|
|
6633
6608
|
local github_app_token_helper="${KASEKI_GITHUB_APP_TOKEN_HELPER:-/usr/local/bin/github-app-token}"
|
|
6634
6609
|
local token_stdout_tmp token_stderr_tmp token_exit_code token_stderr token_parse_result token_error token_http_status
|
|
6635
6610
|
token_stdout_tmp="$(mktemp /tmp/github-app-token-stdout.XXXXXX)" || { printf 'Failed to create token stdout temp file\n' >&2; return 7; }
|
|
@@ -6650,7 +6625,7 @@ run_github_operations() {
|
|
|
6650
6625
|
if [ "$token_parse_result" != "$token_error" ]; then
|
|
6651
6626
|
token_http_status="${token_parse_result#*$'\t'}"
|
|
6652
6627
|
fi
|
|
6653
|
-
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
|
|
6654
6629
|
GITHUB_API_ERROR_TYPE="github_app_token_error"
|
|
6655
6630
|
GITHUB_API_ERROR_MESSAGE="$token_error"
|
|
6656
6631
|
GITHUB_API_HTTP_STATUS="$token_http_status"
|
|
@@ -6660,83 +6635,83 @@ run_github_operations() {
|
|
|
6660
6635
|
fi
|
|
6661
6636
|
|
|
6662
6637
|
# Use helper to extract token from JSON response
|
|
6663
|
-
if ! run_node_subprocess token "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); process.stdout.write(d.token || '')" "$token_data" /
|
|
6664
|
-
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
|
|
6665
6640
|
GITHUB_PUSH_EXIT=7
|
|
6666
6641
|
return 7
|
|
6667
6642
|
fi
|
|
6668
6643
|
|
|
6669
6644
|
if [ -z "$token" ]; then
|
|
6670
|
-
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
|
|
6671
6646
|
GITHUB_PUSH_EXIT=7
|
|
6672
6647
|
return 7
|
|
6673
6648
|
fi
|
|
6674
6649
|
|
|
6675
|
-
printf 'Token generated successfully\n' | tee -a /
|
|
6650
|
+
printf 'Token generated successfully\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6676
6651
|
|
|
6677
6652
|
# Create and push feature branch
|
|
6678
6653
|
GITHUB_OPERATION_PHASE="branch_creation"
|
|
6679
6654
|
feature_branch="kaseki/$INSTANCE_NAME"
|
|
6680
|
-
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
|
|
6681
6656
|
git checkout -b "$feature_branch" || {
|
|
6682
|
-
printf 'Failed to create branch\n' | tee -a /
|
|
6657
|
+
printf 'Failed to create branch\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log >&2
|
|
6683
6658
|
GITHUB_PUSH_EXIT=7
|
|
6684
6659
|
return 7
|
|
6685
6660
|
}
|
|
6686
6661
|
|
|
6687
6662
|
# Commit changes (git should already have changes from pi agent)
|
|
6688
6663
|
GITHUB_OPERATION_PHASE="commit"
|
|
6689
|
-
printf 'Committing changes...\n' | tee -a /
|
|
6690
|
-
if [ ! -s /
|
|
6691
|
-
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
|
|
6692
6667
|
GITHUB_PUSH_EXIT=7
|
|
6693
6668
|
return 7
|
|
6694
6669
|
fi
|
|
6695
6670
|
while IFS= read -r changed_file || [ -n "$changed_file" ]; do
|
|
6696
6671
|
[ -z "$changed_file" ] && continue
|
|
6697
6672
|
git add -- "$changed_file" || {
|
|
6698
|
-
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
|
|
6699
6674
|
GITHUB_PUSH_EXIT=7
|
|
6700
6675
|
return 7
|
|
6701
6676
|
}
|
|
6702
|
-
done < /
|
|
6677
|
+
done < ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
6703
6678
|
if ! git commit -m "Kaseki: $INSTANCE_NAME"; then
|
|
6704
|
-
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
|
|
6705
6680
|
GITHUB_PUSH_EXIT=7
|
|
6706
6681
|
return 7
|
|
6707
6682
|
fi
|
|
6708
6683
|
|
|
6709
6684
|
# Push branch
|
|
6710
6685
|
GITHUB_OPERATION_PHASE="push"
|
|
6711
|
-
printf 'Pushing branch to GitHub...\n' | tee -a /
|
|
6686
|
+
printf 'Pushing branch to GitHub...\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6712
6687
|
local askpass_file
|
|
6713
|
-
if ! create_github_askpass_helper /
|
|
6688
|
+
if ! create_github_askpass_helper ${KASEKI_RESULTS_DIR}/git-push.log 'GitHub credential helper'; then
|
|
6714
6689
|
return 8
|
|
6715
6690
|
fi
|
|
6716
6691
|
askpass_file="$GITHUB_ASKPASS_FILE"
|
|
6717
6692
|
|
|
6718
6693
|
KASEKI_GITHUB_TOKEN="$token" GIT_ASKPASS="$askpass_file" GIT_TERMINAL_PROMPT=0 \
|
|
6719
|
-
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
|
|
6720
6695
|
git_push_exit="${PIPESTATUS[0]:-1}"
|
|
6721
6696
|
if [ "$git_push_exit" -eq 0 ]; then
|
|
6722
|
-
printf 'Branch pushed successfully\n' | tee -a /
|
|
6697
|
+
printf 'Branch pushed successfully\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6723
6698
|
else
|
|
6724
6699
|
rm -f "$askpass_file"
|
|
6725
|
-
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
|
|
6726
6701
|
GITHUB_PUSH_EXIT="$git_push_exit"
|
|
6727
6702
|
return "$git_push_exit"
|
|
6728
6703
|
fi
|
|
6729
6704
|
rm -f "$askpass_file"
|
|
6730
6705
|
|
|
6731
6706
|
if [ "$KASEKI_PUBLISH_MODE" = "branch" ]; then
|
|
6732
|
-
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
|
|
6733
6708
|
GITHUB_PR_EXIT=0
|
|
6734
6709
|
GITHUB_OPERATION_PHASE="completed"
|
|
6735
6710
|
unset token
|
|
6736
6711
|
return 0
|
|
6737
6712
|
fi
|
|
6738
6713
|
if ! is_pr_creation_mode; then
|
|
6739
|
-
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
|
|
6740
6715
|
GITHUB_PR_EXIT=0
|
|
6741
6716
|
GITHUB_OPERATION_PHASE="completed"
|
|
6742
6717
|
unset token
|
|
@@ -6746,7 +6721,7 @@ run_github_operations() {
|
|
|
6746
6721
|
# Create pull request. Both pr and draft_pr push a branch and create a PR;
|
|
6747
6722
|
# only draft_pr marks the GitHub Pulls API request as draft.
|
|
6748
6723
|
GITHUB_OPERATION_PHASE="pr_creation"
|
|
6749
|
-
printf 'Creating pull request...\n' | tee -a /
|
|
6724
|
+
printf 'Creating pull request...\n' | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
6750
6725
|
emit_progress "github operations" "pr_creation_starting"
|
|
6751
6726
|
local pr_title pr_body pr_response pr_url pr_number pr_http_status pr_draft_json
|
|
6752
6727
|
pr_title="$(derive_pr_title)"
|
|
@@ -6770,7 +6745,7 @@ run_github_operations() {
|
|
|
6770
6745
|
- Generated at (UTC): $fallback_timestamp
|
|
6771
6746
|
EOF
|
|
6772
6747
|
)
|
|
6773
|
-
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
|
|
6774
6749
|
fi
|
|
6775
6750
|
if is_pr_draft_mode; then
|
|
6776
6751
|
pr_draft_json=true
|
|
@@ -6784,7 +6759,7 @@ EOF
|
|
|
6784
6759
|
|
|
6785
6760
|
while [ $retry_count -le "$max_retries" ]; do
|
|
6786
6761
|
if [ $retry_count -gt 0 ]; then
|
|
6787
|
-
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
|
|
6788
6763
|
emit_progress "github operations" "pr_creation_attempt $((retry_count + 1))/$max_retries"
|
|
6789
6764
|
sleep "$backoff_delay"
|
|
6790
6765
|
# Exponential backoff: 2s, 4s, 8s
|
|
@@ -6794,31 +6769,31 @@ EOF
|
|
|
6794
6769
|
|
|
6795
6770
|
# Capture both response and HTTP status code
|
|
6796
6771
|
local pr_response_file temp_status_file
|
|
6797
|
-
pr_response_file="$(mktemp /tmp/kaseki-pr-response.XXXXXX)" || { printf 'Failed to create temp file for PR response\n' | tee -a /
|
|
6798
|
-
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; }
|
|
6799
6774
|
|
|
6800
6775
|
if [ $retry_count -eq 0 ] && [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6801
|
-
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
|
|
6802
6777
|
fi
|
|
6803
6778
|
|
|
6804
6779
|
# Encode PR title and body as JSON strings
|
|
6805
6780
|
local pr_title_json pr_body_json
|
|
6806
6781
|
pr_title_json='""'
|
|
6807
6782
|
pr_body_json='""'
|
|
6808
|
-
if ! run_node_subprocess pr_title_json "console.log(JSON.stringify(require('fs').readFileSync(0, 'utf8')))" "$pr_title" /
|
|
6809
|
-
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
|
|
6810
6785
|
GITHUB_PR_EXIT=8
|
|
6811
6786
|
return 8
|
|
6812
6787
|
fi
|
|
6813
|
-
if ! run_node_subprocess pr_body_json "console.log(JSON.stringify(require('fs').readFileSync(0, 'utf8')))" "$pr_body" /
|
|
6814
|
-
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
|
|
6815
6790
|
GITHUB_PR_EXIT=8
|
|
6816
6791
|
return 8
|
|
6817
6792
|
fi
|
|
6818
6793
|
|
|
6819
6794
|
# Validate both variables are non-empty before using in curl
|
|
6820
6795
|
if [ -z "$pr_title_json" ] || [ -z "$pr_body_json" ]; then
|
|
6821
|
-
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
|
|
6822
6797
|
GITHUB_PR_EXIT=8
|
|
6823
6798
|
return 8
|
|
6824
6799
|
fi
|
|
@@ -6843,7 +6818,7 @@ EOF
|
|
|
6843
6818
|
|
|
6844
6819
|
if [ $curl_exit -ne 0 ]; then
|
|
6845
6820
|
# curl command itself failed (network error, timeout, etc.)
|
|
6846
|
-
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
|
|
6847
6822
|
GITHUB_API_HTTP_STATUS="0"
|
|
6848
6823
|
if is_github_pr_error_retryable "0" "curl_error" && [ "$retry_count" -lt "$((max_retries - 1))" ]; then
|
|
6849
6824
|
retry_count=$((retry_count + 1))
|
|
@@ -6861,43 +6836,43 @@ EOF
|
|
|
6861
6836
|
fi
|
|
6862
6837
|
|
|
6863
6838
|
if [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6864
|
-
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
|
|
6865
6840
|
fi
|
|
6866
6841
|
|
|
6867
6842
|
# Validate the API response
|
|
6868
|
-
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
|
|
6869
6844
|
# API returned success (201); now extract the URL and issue number using helper
|
|
6870
|
-
if ! run_node_subprocess pr_url "const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); process.stdout.write(d.html_url || '')" "$pr_response" /
|
|
6871
|
-
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
|
|
6872
6847
|
emit_error_event "github_pr_response_malformed" "Failed to parse PR API response to extract html_url" "exit"
|
|
6873
6848
|
GITHUB_PR_EXIT=9
|
|
6874
6849
|
pr_url=""
|
|
6875
6850
|
fi
|
|
6876
|
-
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" /
|
|
6877
|
-
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
|
|
6878
6853
|
pr_number=""
|
|
6879
6854
|
fi
|
|
6880
6855
|
|
|
6881
6856
|
if [ -n "$pr_url" ]; then
|
|
6882
6857
|
GITHUB_PR_URL="$pr_url"
|
|
6883
6858
|
GITHUB_PR_EXIT=0
|
|
6884
|
-
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
|
|
6885
6860
|
if [ -n "$pr_number" ]; then
|
|
6886
|
-
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
|
|
6887
6862
|
# Request repository owner as reviewer for personal repos
|
|
6888
|
-
request_owner_review "$pr_response" "$token" /
|
|
6863
|
+
request_owner_review "$pr_response" "$token" ${KASEKI_RESULTS_DIR}/git-push.log || true
|
|
6889
6864
|
else
|
|
6890
|
-
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
|
|
6891
6866
|
fi
|
|
6892
6867
|
pr_created=1
|
|
6893
6868
|
rm -f "$pr_response_file"
|
|
6894
6869
|
break
|
|
6895
6870
|
else
|
|
6896
6871
|
# HTTP 201 but no html_url in response - malformed response
|
|
6897
|
-
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
|
|
6898
6873
|
emit_error_event "github_pr_response_malformed" "GitHub PR API returned 201 but response missing html_url field" "exit"
|
|
6899
6874
|
if [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6900
|
-
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
|
|
6901
6876
|
fi
|
|
6902
6877
|
GITHUB_PR_EXIT=9
|
|
6903
6878
|
pr_created=0
|
|
@@ -6907,17 +6882,17 @@ EOF
|
|
|
6907
6882
|
else
|
|
6908
6883
|
# API returned an error
|
|
6909
6884
|
if is_github_pr_error_retryable "$pr_http_status" "$GITHUB_API_ERROR_TYPE" && [ "$retry_count" -lt "$((max_retries - 1))" ]; then
|
|
6910
|
-
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
|
|
6911
6886
|
retry_count=$((retry_count + 1))
|
|
6912
6887
|
rm -f "$pr_response_file"
|
|
6913
6888
|
continue
|
|
6914
6889
|
else
|
|
6915
6890
|
# Permanent error, give up
|
|
6916
|
-
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
|
|
6917
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"
|
|
6918
6893
|
if [ "${KASEKI_DEBUG:-0}" = "1" ]; then
|
|
6919
|
-
printf 'Debug: API error type: %s, HTTP status: %s\n' "$GITHUB_API_ERROR_TYPE" "$GITHUB_API_HTTP_STATUS" | tee -a /
|
|
6920
|
-
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
|
|
6921
6896
|
fi
|
|
6922
6897
|
GITHUB_PR_EXIT=9
|
|
6923
6898
|
pr_created=0
|
|
@@ -6950,7 +6925,7 @@ if [ "$GITHUB_APP_ENABLED" = "1" ]; then
|
|
|
6950
6925
|
printf 'ERROR: GitHub operations preflight health check failed\n' >&2
|
|
6951
6926
|
printf 'GitHub App is enabled but configuration or dependencies are missing.\n' >&2
|
|
6952
6927
|
printf 'Proceeding with kaseki run, but GitHub operations will be skipped or fail.\n' >&2
|
|
6953
|
-
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"
|
|
6954
6929
|
fi
|
|
6955
6930
|
fi
|
|
6956
6931
|
|
|
@@ -6974,7 +6949,7 @@ unset OPENROUTER_API_KEY secret_content
|
|
|
6974
6949
|
if [ -z "$openrouter_api_key" ]; then
|
|
6975
6950
|
set_current_stage "agent setup"
|
|
6976
6951
|
openrouter_api_key_file="${OPENROUTER_API_KEY_FILE:-/agents/secrets/openrouter_api_key}"
|
|
6977
|
-
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
|
|
6978
6953
|
: > "$RAW_EVENTS"
|
|
6979
6954
|
PI_EXIT=2
|
|
6980
6955
|
STATUS=2
|
|
@@ -6985,7 +6960,7 @@ fi
|
|
|
6985
6960
|
if ! run_clone_repository; then
|
|
6986
6961
|
exit 0
|
|
6987
6962
|
fi
|
|
6988
|
-
cd /
|
|
6963
|
+
cd ${KASEKI_WORKSPACE_DIR}/repo || { STATUS=1; FAILED_COMMAND="enter repository"; exit "$STATUS"; }
|
|
6989
6964
|
|
|
6990
6965
|
prepare_dependencies() {
|
|
6991
6966
|
if [ ! -f package.json ]; then
|
|
@@ -7215,7 +7190,7 @@ if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ] && [ "$KASEKI_PRE_AGENT_VALID
|
|
|
7215
7190
|
emit_progress "baseline validation cache" "failed to save (non-blocking)"
|
|
7216
7191
|
fi
|
|
7217
7192
|
# Cleanup baseline workspace to save space
|
|
7218
|
-
rm -rf
|
|
7193
|
+
rm -rf ${KASEKI_WORKSPACE_BASELINE_DIR} 2>/dev/null || true
|
|
7219
7194
|
else
|
|
7220
7195
|
BASELINE_CACHE_STATUS="checkout_failed"
|
|
7221
7196
|
emit_error_event "baseline_checkout_failed" "Failed to setup baseline for test failure comparison; continuing without baseline" "continue"
|
|
@@ -7232,13 +7207,13 @@ if [ "$KASEKI_PRE_AGENT_VALIDATION" = "0" ]; then
|
|
|
7232
7207
|
printf '\n==> pre-agent validation\n'
|
|
7233
7208
|
set_current_stage "pre-agent validation"
|
|
7234
7209
|
emit_progress "pre-agent validation" "skipped by KASEKI_PRE_AGENT_VALIDATION=0"
|
|
7235
|
-
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
|
|
7236
7211
|
record_stage_timing "pre-agent validation" 0 0 "skipped_by_config"
|
|
7237
7212
|
else
|
|
7238
7213
|
run_validation_commands \
|
|
7239
7214
|
"pre-agent validation" \
|
|
7240
7215
|
"$KASEKI_PRE_AGENT_VALIDATION_COMMANDS" \
|
|
7241
|
-
/
|
|
7216
|
+
${KASEKI_RESULTS_DIR}/pre-validation.log \
|
|
7242
7217
|
"$PRE_VALIDATION_RAW_LOG" \
|
|
7243
7218
|
"$PRE_VALIDATION_TIMINGS_FILE" \
|
|
7244
7219
|
"$PRE_VALIDATION_ENV_LOG" \
|
|
@@ -7267,7 +7242,7 @@ set_current_stage "typescript precheck"
|
|
|
7267
7242
|
if ! run_typescript_precheck; then
|
|
7268
7243
|
if [ "$KASEKI_SCOUTING" = "1" ]; then
|
|
7269
7244
|
# If scouting is enabled (experimental path), continue anyway with warning
|
|
7270
|
-
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
|
|
7271
7246
|
else
|
|
7272
7247
|
# Without scouting, TypeScript failures are fatal
|
|
7273
7248
|
STATUS="$TS_PRE_CHECK_EXIT"
|
|
@@ -7283,16 +7258,16 @@ printf 'Pi version: %s\n' "$PI_VERSION"
|
|
|
7283
7258
|
# === Phase 1: Early Filesystem Diagnostics (Before Scouting) ===
|
|
7284
7259
|
# Detects read-only filesystem constraints that would cause silent scouting failures
|
|
7285
7260
|
check_filesystem_capabilities() {
|
|
7286
|
-
local results_dir="${KASEKI_RESULTS_DIR
|
|
7261
|
+
local results_dir="${KASEKI_RESULTS_DIR:-${KASEKI_RESULTS_DIR}}"
|
|
7287
7262
|
local filesystem_writable=true
|
|
7288
7263
|
local readonly_reason=""
|
|
7289
7264
|
|
|
7290
7265
|
emit_progress "filesystem capabilities check" "verifying write capabilities for artifacts"
|
|
7291
7266
|
|
|
7292
|
-
# Test /
|
|
7267
|
+
# Test ${KASEKI_RESULTS_DIR}/ writability
|
|
7293
7268
|
if [ ! -w "$results_dir" ]; then
|
|
7294
7269
|
filesystem_writable=false
|
|
7295
|
-
readonly_reason="
|
|
7270
|
+
readonly_reason="${KASEKI_RESULTS_DIR} is READ-ONLY (Docker mounted with :ro or container --read-only flag)"
|
|
7296
7271
|
emit_error_event "readonly_filesystem_detected" "$readonly_reason" "continue"
|
|
7297
7272
|
{
|
|
7298
7273
|
printf '\n[FILESYSTEM DIAGNOSTIC] READ-ONLY FILESYSTEM DETECTED\n'
|
|
@@ -7302,35 +7277,35 @@ check_filesystem_capabilities() {
|
|
|
7302
7277
|
printf ' - Container UID: %d\n' "$(id -u)"
|
|
7303
7278
|
printf ' - Expected reason: Docker mounted with :ro flag or container --read-only\n'
|
|
7304
7279
|
printf '\nImpact:\n'
|
|
7305
|
-
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'
|
|
7306
7281
|
printf ' - Validation logs and artifacts cannot be written\n'
|
|
7307
7282
|
printf ' - This causes exit code 86 (scouting validation failure)\n'
|
|
7308
|
-
printf '\nFix: Remount
|
|
7309
|
-
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'
|
|
7310
7285
|
printf 'Or remove --read-only flag from Docker run command\n'
|
|
7311
|
-
} | tee -a /
|
|
7286
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/scouting-stderr.log
|
|
7312
7287
|
else
|
|
7313
7288
|
# Test actual write capability
|
|
7314
7289
|
local test_file="$results_dir/.kaseki-fs-test-$$"
|
|
7315
7290
|
if ! touch "$test_file" 2>/dev/null; then
|
|
7316
7291
|
filesystem_writable=false
|
|
7317
|
-
readonly_reason="
|
|
7292
|
+
readonly_reason="${KASEKI_RESULTS_DIR} is not writable (touch failed despite appearing writable)"
|
|
7318
7293
|
emit_error_event "filesystem_write_test_failed" "$readonly_reason" "continue"
|
|
7319
7294
|
else
|
|
7320
7295
|
rm -f "$test_file" 2>/dev/null || true
|
|
7321
|
-
emit_progress "filesystem capabilities check" "✓
|
|
7296
|
+
emit_progress "filesystem capabilities check" "✓ ${KASEKI_RESULTS_DIR} is writable"
|
|
7322
7297
|
fi
|
|
7323
7298
|
fi
|
|
7324
7299
|
|
|
7325
7300
|
# Record in metadata for post-mortem analysis
|
|
7326
|
-
printf '%s\n' "$filesystem_writable" > /
|
|
7327
|
-
[ -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
|
|
7328
7303
|
|
|
7329
7304
|
if [ "$filesystem_writable" = "false" ]; then
|
|
7330
7305
|
if [ "$KASEKI_BASELINE_VALIDATION_ENABLED" = "1" ]; then
|
|
7331
7306
|
emit_progress "baseline validation preparation" "DISABLED due to read-only filesystem detected"
|
|
7332
7307
|
KASEKI_BASELINE_VALIDATION_ENABLED="0"
|
|
7333
|
-
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
|
|
7334
7309
|
fi
|
|
7335
7310
|
return 1
|
|
7336
7311
|
fi
|
|
@@ -7380,7 +7355,7 @@ if [ "$KASEKI_SCOUTING" = "1" ] && [ -f "$SCOUTING_ARTIFACT" ]; then
|
|
|
7380
7355
|
export KASEKI_VALIDATION_ALLOWLIST="$merged_validation_allowlist"
|
|
7381
7356
|
|
|
7382
7357
|
# Log merge decisions with structured JSON construction so pattern text is escaped safely.
|
|
7383
|
-
append_jsonl_object /
|
|
7358
|
+
append_jsonl_object ${KASEKI_RESULTS_DIR}/metadata.jsonl \
|
|
7384
7359
|
"timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
7385
7360
|
"event=allowlist_merge" \
|
|
7386
7361
|
"scouting_agent_patterns=$scouting_agent_patterns" \
|
|
@@ -7393,14 +7368,14 @@ if [ "$KASEKI_SCOUTING" = "1" ] && [ -f "$SCOUTING_ARTIFACT" ]; then
|
|
|
7393
7368
|
allowlist_merge_status="merged"
|
|
7394
7369
|
|
|
7395
7370
|
# Run coverage validation with dry-run
|
|
7396
|
-
if [ -s /
|
|
7397
|
-
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
|
|
7398
7373
|
fi
|
|
7399
7374
|
|
|
7400
7375
|
emit_progress "derive allowlist from scouting" "finished (status=$allowlist_merge_status)"
|
|
7401
7376
|
else
|
|
7402
7377
|
# Pattern validation failed - fail fast
|
|
7403
|
-
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
|
|
7404
7379
|
STATUS=86
|
|
7405
7380
|
FAILED_COMMAND="allowlist pattern validation"
|
|
7406
7381
|
emit_error_event "scouting_allowlist_invalid" "Derived allowlist patterns failed validation" "exit"
|
|
@@ -7408,7 +7383,7 @@ if [ "$KASEKI_SCOUTING" = "1" ] && [ -f "$SCOUTING_ARTIFACT" ]; then
|
|
|
7408
7383
|
fi
|
|
7409
7384
|
else
|
|
7410
7385
|
# Derivation failed - log and fail fast
|
|
7411
|
-
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
|
|
7412
7387
|
STATUS=86
|
|
7413
7388
|
FAILED_COMMAND="allowlist derivation from scouting"
|
|
7414
7389
|
emit_error_event "scouting_allowlist_derivation_failed" "Failed to derive allowlist from scouting artifact" "exit"
|
|
@@ -7446,7 +7421,7 @@ if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
|
7446
7421
|
printf ' Model: %s\n' "$KASEKI_MODEL"
|
|
7447
7422
|
printf ' Timeout: %s seconds\n' "$KASEKI_AGENT_TIMEOUT_SECONDS"
|
|
7448
7423
|
printf ' Task: %s\n' "$TASK_PROMPT"
|
|
7449
|
-
} | tee -a /
|
|
7424
|
+
} | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log
|
|
7450
7425
|
emit_progress "pi coding agent" "skipped (dry-run)"
|
|
7451
7426
|
record_stage_timing "pi coding agent" "0" "$PI_DURATION_SECONDS" "dry_run=true"
|
|
7452
7427
|
else
|
|
@@ -7458,9 +7433,9 @@ else
|
|
|
7458
7433
|
OPENROUTER_API_KEY="$openrouter_api_key" \
|
|
7459
7434
|
timeout --signal=SIGTERM "$KASEKI_AGENT_TIMEOUT_SECONDS" \
|
|
7460
7435
|
pi --mode json --no-session --provider "$KASEKI_PROVIDER" --model "$KASEKI_MODEL" "$agent_prompt" \
|
|
7461
|
-
2> >(tee -a /
|
|
7436
|
+
2> >(tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log >&2) \
|
|
7462
7437
|
| tee "$RAW_EVENTS" \
|
|
7463
|
-
| kaseki-pi-progress-stream /
|
|
7438
|
+
| kaseki-pi-progress-stream ${KASEKI_RESULTS_DIR}/progress.jsonl ${KASEKI_RESULTS_DIR}/progress.log
|
|
7464
7439
|
PI_EXIT="${PIPESTATUS[0]}"
|
|
7465
7440
|
unset agent_prompt
|
|
7466
7441
|
PI_DURATION_SECONDS=$(($(date +%s) - PI_START_EPOCH))
|
|
@@ -7469,7 +7444,7 @@ else
|
|
|
7469
7444
|
record_stage_timing "pi coding agent" "$PI_EXIT" "$PI_DURATION_SECONDS" "timeout_seconds=$KASEKI_AGENT_TIMEOUT_SECONDS"
|
|
7470
7445
|
|
|
7471
7446
|
if [ "$KASEKI_DEBUG_RAW_EVENTS" = "1" ]; then
|
|
7472
|
-
cp "$RAW_EVENTS" /
|
|
7447
|
+
cp "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.raw.jsonl
|
|
7473
7448
|
fi
|
|
7474
7449
|
|
|
7475
7450
|
PI_EXTRACTION_DEPS_OK=1
|
|
@@ -7480,7 +7455,7 @@ else
|
|
|
7480
7455
|
missing_executables+=("$required_exec")
|
|
7481
7456
|
fi
|
|
7482
7457
|
done
|
|
7483
|
-
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
|
|
7484
7459
|
if [ ! -f "$helper_file" ]; then
|
|
7485
7460
|
missing_helpers+=("$helper_file")
|
|
7486
7461
|
fi
|
|
@@ -7493,34 +7468,34 @@ else
|
|
|
7493
7468
|
[ -z "$missing_helpers_joined" ] && missing_helpers_joined="none"
|
|
7494
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")
|
|
7495
7470
|
printf '%s
|
|
7496
|
-
' "$extraction_error" | tee -a /
|
|
7471
|
+
' "$extraction_error" | tee -a ${KASEKI_RESULTS_DIR}/pi-stderr.log ${KASEKI_RESULTS_DIR}/quality.log >&2
|
|
7497
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"
|
|
7498
7473
|
if [ "$STATUS" -eq 0 ]; then
|
|
7499
7474
|
STATUS=87
|
|
7500
7475
|
FAILED_COMMAND="pi artifact extraction dependency validation"
|
|
7501
7476
|
fi
|
|
7502
|
-
cp "$RAW_EVENTS" /
|
|
7477
|
+
cp "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.raw.jsonl 2>/dev/null || true
|
|
7503
7478
|
fi
|
|
7504
7479
|
|
|
7505
7480
|
FILTER_EXIT=0
|
|
7506
7481
|
if [ "$PI_EXTRACTION_DEPS_OK" -eq 1 ]; then
|
|
7507
7482
|
set +e
|
|
7508
|
-
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
|
|
7509
7484
|
FILTER_EXIT=$?
|
|
7510
7485
|
set +e
|
|
7511
7486
|
fi
|
|
7512
7487
|
if [ "$FILTER_EXIT" -ne 0 ]; then
|
|
7513
|
-
printf 'pi-event-filter failed with exit %s; raw events preserved as fallback artifact\n' "$FILTER_EXIT" | tee -a /
|
|
7514
|
-
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
|
|
7515
7490
|
emit_error_event "pi_event_filter_failed" "kaseki-pi-event-filter exited with code $FILTER_EXIT" "continue"
|
|
7516
7491
|
if [ "$STATUS" -eq 0 ]; then
|
|
7517
7492
|
STATUS="$FILTER_EXIT"
|
|
7518
7493
|
FAILED_COMMAND="kaseki-pi-event-filter"
|
|
7519
7494
|
fi
|
|
7520
|
-
cp "$RAW_EVENTS" /
|
|
7495
|
+
cp "$RAW_EVENTS" ${KASEKI_RESULTS_DIR}/pi-events.raw.jsonl 2>/dev/null || true
|
|
7521
7496
|
fi
|
|
7522
|
-
if [ -s "$RAW_EVENTS" ] && { [ ! -s /
|
|
7523
|
-
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
|
|
7524
7499
|
emit_error_event "pi_event_export_incomplete" "RAW_EVENTS has data but exported artifacts are empty or missing" "continue"
|
|
7525
7500
|
if [ "$STATUS" -eq 0 ]; then
|
|
7526
7501
|
STATUS=86
|
|
@@ -7529,16 +7504,16 @@ else
|
|
|
7529
7504
|
fi
|
|
7530
7505
|
|
|
7531
7506
|
# Process hashline_edit events (non-fatal phase; failures don't block pipeline)
|
|
7532
|
-
if [ "$KASEKI_HASHLINE_EDITS" != "0" ] && [ -s /
|
|
7507
|
+
if [ "$KASEKI_HASHLINE_EDITS" != "0" ] && [ -s ${KASEKI_RESULTS_DIR}/pi-events.jsonl ]; then
|
|
7533
7508
|
emit_progress "hashline validation" "started"
|
|
7534
7509
|
HASHLINE_EXIT=0
|
|
7535
7510
|
set +e
|
|
7536
|
-
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
|
|
7537
7512
|
HASHLINE_EXIT=$?
|
|
7538
7513
|
set +e
|
|
7539
7514
|
|
|
7540
7515
|
if [ "$HASHLINE_EXIT" -ne 0 ]; then
|
|
7541
|
-
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
|
|
7542
7517
|
emit_event "warning" "warning_type=hashline_validation_failed" "detail=hashline_edit processing exited with code $HASHLINE_EXIT"
|
|
7543
7518
|
else
|
|
7544
7519
|
emit_progress "hashline validation" "completed"
|
|
@@ -7569,7 +7544,7 @@ else
|
|
|
7569
7544
|
}
|
|
7570
7545
|
var m='';
|
|
7571
7546
|
try{
|
|
7572
|
-
var summary=require('/
|
|
7547
|
+
var summary=require('${KASEKI_RESULTS_DIR}/pi-summary.json');
|
|
7573
7548
|
m=clean(summary.selected_model)||clean(summary.model)||fromSummaryModels(summary);
|
|
7574
7549
|
}catch{}
|
|
7575
7550
|
if(!m){
|
|
@@ -7595,7 +7570,7 @@ fi
|
|
|
7595
7570
|
|
|
7596
7571
|
if [ "$KASEKI_DRY_RUN" != "1" ]; then
|
|
7597
7572
|
if [ "$PI_EXIT" -eq 124 ]; then
|
|
7598
|
-
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
|
|
7599
7574
|
if [ "$STATUS" -eq 0 ]; then
|
|
7600
7575
|
STATUS=124
|
|
7601
7576
|
FAILED_COMMAND="pi coding agent timeout"
|
|
@@ -7634,11 +7609,11 @@ printf '\n==> quality checks\n'
|
|
|
7634
7609
|
set_current_stage "quality checks"
|
|
7635
7610
|
emit_progress "quality checks" "started"
|
|
7636
7611
|
stage_start="$(date +%s)"
|
|
7637
|
-
diff_size="$(wc -c < /
|
|
7612
|
+
diff_size="$(wc -c < ${KASEKI_RESULTS_DIR}/git.diff | tr -d ' ')"
|
|
7638
7613
|
if [ "$diff_size" -gt "$KASEKI_MAX_DIFF_BYTES" ]; then
|
|
7639
7614
|
QUALITY_EXIT=4
|
|
7640
7615
|
QUALITY_FAILURE_REASON="max_diff_bytes: $diff_size bytes exceeds limit of $KASEKI_MAX_DIFF_BYTES bytes"
|
|
7641
|
-
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
|
|
7642
7617
|
emit_event "quality_gate_rule_evaluated" "rule=max_diff_bytes" "passed=false" "actual=$diff_size" "limit=$KASEKI_MAX_DIFF_BYTES"
|
|
7643
7618
|
else
|
|
7644
7619
|
emit_event "quality_gate_rule_evaluated" "rule=max_diff_bytes" "passed=true" "actual=$diff_size" "limit=$KASEKI_MAX_DIFF_BYTES"
|
|
@@ -7653,17 +7628,17 @@ if [ -n "$allowlist_regex" ]; then
|
|
|
7653
7628
|
if ! printf '%s\n' "$changed_file" | grep -Eq "^(${allowlist_regex})$"; then
|
|
7654
7629
|
QUALITY_EXIT=5
|
|
7655
7630
|
QUALITY_FAILURE_REASON="allowlist_check: file '$changed_file' not in allowlist"
|
|
7656
|
-
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
|
|
7657
7632
|
emit_event "quality_gate_rule_evaluated" "rule=allowlist_check" "passed=false" "file=$changed_file"
|
|
7658
7633
|
else
|
|
7659
7634
|
emit_event "quality_gate_rule_evaluated" "rule=allowlist_check" "passed=true" "file=$changed_file"
|
|
7660
7635
|
fi
|
|
7661
|
-
done < /
|
|
7636
|
+
done < ${KASEKI_RESULTS_DIR}/changed-files.txt
|
|
7662
7637
|
fi
|
|
7663
7638
|
|
|
7664
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
|
|
7665
7640
|
format_command="npm run format:check"
|
|
7666
|
-
printf '%s\n' "$format_command" >> /
|
|
7641
|
+
printf '%s\n' "$format_command" >> ${KASEKI_RESULTS_DIR}/format-check-command.txt
|
|
7667
7642
|
fi
|
|
7668
7643
|
record_stage_timing "quality checks" "$QUALITY_EXIT" "$(($(date +%s) - stage_start))" "diff_size_bytes=$diff_size"
|
|
7669
7644
|
|
|
@@ -7672,7 +7647,7 @@ run_expectation_mismatch_detector
|
|
|
7672
7647
|
|
|
7673
7648
|
pre_validation_goal_check_diff_hash=""
|
|
7674
7649
|
if [ "$STATUS" -eq 0 ] && [ "$PI_EXIT" -eq 0 ] && [ "$QUALITY_EXIT" -eq 0 ]; then
|
|
7675
|
-
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}')"
|
|
7676
7651
|
run_goal_check "$coding_attempt"
|
|
7677
7652
|
collect_goal_check_feedback "$INSTANCE_NAME"
|
|
7678
7653
|
snapshot_attempt_artifacts "$coding_attempt"
|
|
@@ -7704,18 +7679,18 @@ log_validation_environment() {
|
|
|
7704
7679
|
printf '[validation environment] PATH=%s\n' "$PATH"
|
|
7705
7680
|
printf '[validation environment] NODE_OPTIONS=%s\n' "${NODE_OPTIONS:-<not set>}"
|
|
7706
7681
|
printf '[validation environment] NODE_PATH=%s\n' "${NODE_PATH:-<not set>}"
|
|
7707
|
-
printf '[validation environment] disk_space_available=%s\n' "$(df -h
|
|
7708
|
-
printf '[validation environment] disk_space_used=%s\n' "$(du -sh
|
|
7709
|
-
} | 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"
|
|
7710
7685
|
}
|
|
7711
7686
|
log_validation_environment
|
|
7712
|
-
collect_changed_file_state /
|
|
7687
|
+
collect_changed_file_state ${KASEKI_RESULTS_DIR}/validation-before-state.txt
|
|
7713
7688
|
|
|
7714
7689
|
if [ "$KASEKI_DRY_RUN" = "1" ] || [ -z "$KASEKI_VALIDATION_COMMANDS" ] || [ "$KASEKI_VALIDATION_COMMANDS" = "none" ]; then
|
|
7715
7690
|
run_validation_commands \
|
|
7716
7691
|
"validation" \
|
|
7717
7692
|
"$KASEKI_VALIDATION_COMMANDS" \
|
|
7718
|
-
/
|
|
7693
|
+
${KASEKI_RESULTS_DIR}/validation.log \
|
|
7719
7694
|
"$VALIDATION_RAW_LOG" \
|
|
7720
7695
|
"$VALIDATION_TIMINGS_FILE" \
|
|
7721
7696
|
"$VALIDATION_ENV_LOG" \
|
|
@@ -7724,7 +7699,7 @@ elif [ "$QUALITY_EXIT" -ne 0 ]; then
|
|
|
7724
7699
|
printf '\n==> validation\n'
|
|
7725
7700
|
set_current_stage "validation"
|
|
7726
7701
|
emit_progress "validation" "started"
|
|
7727
|
-
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
|
|
7728
7703
|
VALIDATION_EXIT="$QUALITY_EXIT"
|
|
7729
7704
|
if [ -z "$VALIDATION_FAILURE_REASON" ]; then
|
|
7730
7705
|
VALIDATION_FAILURE_REASON="quality_gate_failed: $QUALITY_FAILURE_REASON"
|
|
@@ -7735,14 +7710,14 @@ elif [ "$PI_EXIT" -ne 0 ] && [ "$KASEKI_VALIDATE_AFTER_AGENT_FAILURE" != "1" ];
|
|
|
7735
7710
|
printf '\n==> validation\n'
|
|
7736
7711
|
set_current_stage "validation"
|
|
7737
7712
|
emit_progress "validation" "started"
|
|
7738
|
-
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
|
|
7739
7714
|
record_stage_timing "validation" "$PI_EXIT" 0 "skipped_after_agent_failure"
|
|
7740
7715
|
emit_progress "validation" "finished with exit $VALIDATION_EXIT"
|
|
7741
7716
|
else
|
|
7742
7717
|
run_validation_commands \
|
|
7743
7718
|
"validation" \
|
|
7744
7719
|
"$KASEKI_VALIDATION_COMMANDS" \
|
|
7745
|
-
/
|
|
7720
|
+
${KASEKI_RESULTS_DIR}/validation.log \
|
|
7746
7721
|
"$VALIDATION_RAW_LOG" \
|
|
7747
7722
|
"$VALIDATION_TIMINGS_FILE" \
|
|
7748
7723
|
"$VALIDATION_ENV_LOG" \
|
|
@@ -7756,18 +7731,18 @@ fi
|
|
|
7756
7731
|
|
|
7757
7732
|
# Check validation-phase allowlist (if configured)
|
|
7758
7733
|
if [ "$VALIDATION_EXIT" -eq 0 ]; then
|
|
7759
|
-
collect_changed_file_state /
|
|
7734
|
+
collect_changed_file_state ${KASEKI_RESULTS_DIR}/validation-after-state.txt
|
|
7760
7735
|
collect_git_artifacts
|
|
7761
7736
|
if ! check_validation_allowlist; then
|
|
7762
7737
|
: # Exit code already set in check_validation_allowlist
|
|
7763
7738
|
fi
|
|
7764
7739
|
fi
|
|
7765
7740
|
|
|
7766
|
-
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}')"
|
|
7767
7742
|
if [ "$STATUS" -eq 0 ] && [ "$PI_EXIT" -eq 0 ] && [ "$QUALITY_EXIT" -eq 0 ] && [ "$VALIDATION_EXIT" -eq 0 ] && \
|
|
7768
7743
|
[ -n "$pre_validation_goal_check_diff_hash" ] && [ -n "$post_validation_goal_check_diff_hash" ] && \
|
|
7769
7744
|
[ "$post_validation_goal_check_diff_hash" != "$pre_validation_goal_check_diff_hash" ]; then
|
|
7770
|
-
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
|
|
7771
7746
|
emit_progress "goal check" "re-running after validation changed the final diff (attempt $coding_attempt)"
|
|
7772
7747
|
run_goal_check "$coding_attempt"
|
|
7773
7748
|
collect_goal_check_feedback "$INSTANCE_NAME"
|
|
@@ -7801,14 +7776,14 @@ printf '\n==> secret scan\n'
|
|
|
7801
7776
|
set_current_stage "secret scan"
|
|
7802
7777
|
emit_progress "secret scan" "started"
|
|
7803
7778
|
stage_start="$(date +%s)"
|
|
7804
|
-
: > /
|
|
7779
|
+
: > ${KASEKI_RESULTS_DIR}/secret-scan.log
|
|
7805
7780
|
if [ "$KASEKI_DRY_RUN" = "1" ]; then
|
|
7806
|
-
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
|
|
7807
7782
|
SECRET_SCAN_EXIT=0
|
|
7808
7783
|
record_stage_timing "secret scan" "0" "$(($(date +%s) - stage_start))" "dry_run=true"
|
|
7809
7784
|
else
|
|
7810
7785
|
# Run the initial scan
|
|
7811
|
-
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
|
|
7812
7787
|
# Matches found - check against allowlist
|
|
7813
7788
|
if check_secret_scan_allowlist; then
|
|
7814
7789
|
# All matches are allowlisted
|
|
@@ -7861,7 +7836,7 @@ printf '\n==> github operations\n'
|
|
|
7861
7836
|
set_current_stage "github operations"
|
|
7862
7837
|
emit_progress "github operations" "started"
|
|
7863
7838
|
stage_start="$(date +%s)"
|
|
7864
|
-
: > /
|
|
7839
|
+
: > ${KASEKI_RESULTS_DIR}/git-push.log
|
|
7865
7840
|
build_github_skip_reasons
|
|
7866
7841
|
if [ "${#GITHUB_SKIP_REASONS[@]}" -eq 0 ]; then
|
|
7867
7842
|
github_app_id_file="$(resolve_github_secret_file "GITHUB_APP_ID_FILE" "github_app_id")"
|
|
@@ -7880,7 +7855,7 @@ if [ "${#GITHUB_SKIP_REASONS[@]}" -eq 0 ]; then
|
|
|
7880
7855
|
else
|
|
7881
7856
|
GITHUB_SKIP_REASONS+=("github_app_secrets_missing")
|
|
7882
7857
|
GITHUB_OPERATION_PHASE="secrets"
|
|
7883
|
-
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
|
|
7884
7859
|
emit_progress "github operations" "skipped: $(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")"
|
|
7885
7860
|
GITHUB_PUSH_EXIT=7
|
|
7886
7861
|
fi
|
|
@@ -7892,7 +7867,7 @@ else
|
|
|
7892
7867
|
"$([ "$QUALITY_EXIT" -eq 0 ] && printf 'passed' || printf 'failed')" \
|
|
7893
7868
|
"$([ "$SECRET_SCAN_EXIT" -eq 0 ] && printf 'passed' || printf 'failed')" \
|
|
7894
7869
|
"$DIFF_NONEMPTY" \
|
|
7895
|
-
"$GITHUB_APP_ENABLED" | tee -a /
|
|
7870
|
+
"$GITHUB_APP_ENABLED" | tee -a ${KASEKI_RESULTS_DIR}/git-push.log
|
|
7896
7871
|
emit_progress "github operations" "skipped: $(IFS=,; printf '%s' "${GITHUB_SKIP_REASONS[*]}")"
|
|
7897
7872
|
fi
|
|
7898
7873
|
if [ "$GITHUB_APP_ENABLED" = "1" ]; then
|