#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" BIN="${WSTONE_MCP_BIN:-$ROOT_DIR/editor/build-native/whetstone_mcp_stable}" WORKSPACE="${WSTONE_WORKSPACE:-$ROOT_DIR}" LANGUAGE="${WSTONE_LANGUAGE:-cpp}" MAX_ITERS="${MAX_ITERS:-3}" STRICT_MODE="${STRICT_MODE:-1}" SPEC="${1:-}" if [[ -z "$SPEC" ]]; then echo "usage: $0 \"\"" exit 1 fi if ! command -v jq >/dev/null 2>&1; then echo "error: jq required" exit 1 fi OUT_DIR="${OUT_DIR:-$ROOT_DIR/logs/taskitem_runs/production_loop_$(date +%Y%m%d_%H%M%S)}" mkdir -p "$OUT_DIR" TRACE_FILE="$OUT_DIR/trace.jsonl" call_tool() { local tool_name="$1" local args_json="$2" local init_req tool_req responses tool_resp init_req='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"production-loop","version":"1.0"}}}' tool_req="$(jq -nc --arg t "$tool_name" --argjson a "$args_json" '{jsonrpc:"2.0",id:2,method:"tools/call",params:{name:$t,arguments:$a}}')" responses="$(printf '%s\n%s\n' "$init_req" "$tool_req" | "$BIN" --workspace "$WORKSPACE" --language "$LANGUAGE" 2>/dev/null || true)" tool_resp="$(printf '%s\n' "$responses" | tail -n1)" printf '%s' "$tool_resp" } extract_json() { local raw="$1" printf '%s' "$raw" | jq -r '.result.content[0].text // "{}"' | jq '.' } log_trace() { local phase="$1" local iter="$2" local payload="$3" jq -nc --arg phase "$phase" --arg iter "$iter" --argjson payload "$payload" \ '{phase:$phase, iteration:$iter, payload:$payload}' >> "$TRACE_FILE" } loop_spec="$SPEC" status="blocked" blocked_reason="max_iterations_exhausted" final_ready=0 for i in $(seq 1 "$MAX_ITERS"); do iter_id="iter_$(printf '%02d' "$i")" args="$(jq -nc --arg s "$loop_spec" '{spec:$s,preferImports:true}')" raw="$(call_tool whetstone_generate_code "$args")" printf '%s\n' "$raw" > "$OUT_DIR/${iter_id}_generate_raw.json" parsed="$(extract_json "$raw")" printf '%s\n' "$parsed" > "$OUT_DIR/${iter_id}_generate.json" log_trace "generate" "$iter_id" "$parsed" code="$(printf '%s' "$parsed" | jq -r '.generatedCode // ""')" if [[ -z "$code" ]]; then code="$(printf '%s' "$parsed" | jq -r '.note // ""')" fi printf '%s\n' "$code" > "$OUT_DIR/${iter_id}_generated_code.txt" strict_arg=() if [[ "$STRICT_MODE" == "1" ]]; then strict_arg+=(--strict) fi python3 "$ROOT_DIR/tools/mcp/evaluate_generated_code_gates.py" \ --code-file "$OUT_DIR/${iter_id}_generated_code.txt" \ --language "$LANGUAGE" \ "${strict_arg[@]}" \ --out "$OUT_DIR/${iter_id}_gates.json" >/tmp/production_loop_gate_${i}.json gates_payload="$(cat "$OUT_DIR/${iter_id}_gates.json")" log_trace "gates" "$iter_id" "$gates_payload" ready="$(jq -r '.gates.overall_ready' "$OUT_DIR/${iter_id}_gates.json")" if [[ "$ready" == "true" ]]; then status="green" blocked_reason="" final_ready=1 break fi # Deterministic C++ include repair attempt from diagnostics. if [[ "$LANGUAGE" == "cpp" ]]; then python3 "$ROOT_DIR/tools/mcp/apply_cpp_diagnostic_fixes.py" \ --code-file "$OUT_DIR/${iter_id}_generated_code.txt" \ --gates-json "$OUT_DIR/${iter_id}_gates.json" \ --out-code-file "$OUT_DIR/${iter_id}_generated_code_fixed.cpp" \ --out-report "$OUT_DIR/${iter_id}_fix_report.json" >/tmp/production_loop_fix_${i}.json if [[ "$(jq -r '.changed' "$OUT_DIR/${iter_id}_fix_report.json")" == "true" ]]; then mv "$OUT_DIR/${iter_id}_generated_code_fixed.cpp" "$OUT_DIR/${iter_id}_generated_code.txt" fixed_gate="$OUT_DIR/${iter_id}_gates_after_fix.json" python3 "$ROOT_DIR/tools/mcp/evaluate_generated_code_gates.py" \ --code-file "$OUT_DIR/${iter_id}_generated_code.txt" \ --language "$LANGUAGE" \ "${strict_arg[@]}" \ --out "$fixed_gate" >/tmp/production_loop_gate_fix_${i}.json log_trace "autofix" "$iter_id" "$(cat "$OUT_DIR/${iter_id}_fix_report.json")" log_trace "gates_after_fix" "$iter_id" "$(cat "$fixed_gate")" cp "$fixed_gate" "$OUT_DIR/${iter_id}_gates.json" ready="$(jq -r '.gates.overall_ready' "$OUT_DIR/${iter_id}_gates.json")" if [[ "$ready" == "true" ]]; then status="green" blocked_reason="" final_ready=1 break fi fi fi # Run same-language pipeline for diagnostics when compile/test fail. code="$(cat "$OUT_DIR/${iter_id}_generated_code.txt")" pipeline_args="$(jq -nc --arg src "$code" --arg lang "$LANGUAGE" '{source:$src,sourceLanguage:$lang,targetLanguage:$lang}')" pipeline_raw="$(call_tool whetstone_run_pipeline "$pipeline_args")" printf '%s\n' "$pipeline_raw" > "$OUT_DIR/${iter_id}_pipeline_raw.json" pipeline_parsed="$(extract_json "$pipeline_raw")" printf '%s\n' "$pipeline_parsed" > "$OUT_DIR/${iter_id}_pipeline.json" log_trace "pipeline_diagnostics" "$iter_id" "$pipeline_parsed" python3 "$ROOT_DIR/tools/mcp/remediation_router.py" \ --gates-json "$OUT_DIR/${iter_id}_gates.json" \ --out "$OUT_DIR/${iter_id}_route.json" >/tmp/production_loop_route_${i}.json route_payload="$(cat "$OUT_DIR/${iter_id}_route.json")" log_trace "route" "$iter_id" "$route_payload" blocked="$(jq -r '.blocked' "$OUT_DIR/${iter_id}_route.json")" if [[ "$blocked" == "true" ]]; then status="blocked" blocked_reason="$(jq -r '.blocked_reason' "$OUT_DIR/${iter_id}_route.json")" break fi hints="$(jq -r '[.actions[].hint] | unique | join("\n")' "$OUT_DIR/${iter_id}_route.json")" loop_spec="$loop_spec Remediation directives (iteration $i): $hints Requirements: - no TODO/FIXME/placeholder markers - concrete field and method types - compile-clean output for target language - queue operations must be behaviorally complete: enqueue/dequeue/peek/size/empty" done if [[ "$status" == "green" ]]; then blocked_reason="" fi jq -nc \ --arg out_dir "$OUT_DIR" \ --arg spec "$SPEC" \ --arg language "$LANGUAGE" \ --arg status "$status" \ --arg blocked_reason "$blocked_reason" \ --argjson strict_mode "$STRICT_MODE" \ --argjson max_iters "$MAX_ITERS" \ --argjson overall_ready "$final_ready" \ '{ out_dir:$out_dir, spec:$spec, language:$language, strict_mode:($strict_mode==1), max_iters:$max_iters, overall_ready:($overall_ready==1), status:$status, blocked_reason:$blocked_reason }' > "$OUT_DIR/00_summary.json" echo "Production completion loop output: $OUT_DIR" cat "$OUT_DIR/00_summary.json"