From c613e8e676604fd00dc36d19fb79ec7e6304109f Mon Sep 17 00:00:00 2001 From: Yeachan-Heo Date: Mon, 25 May 2026 04:36:30 +0000 Subject: [PATCH] feat: sweep --- .github/hooks/pre-push | 20 ++ .omx/cc2/board.json | 81 ++++++- .omx/cc2/board.md | 21 +- .omx/ultragoal/goals.json | 16 +- .omx/ultragoal/ledger.jsonl | 2 + ...dmap-pinpoints-693-695-verification-map.md | 47 ++++ rust/crates/claw-analog/src/lib.rs | 33 ++- rust/crates/runtime/src/trust_resolver.rs | 23 +- rust/crates/runtime/src/worker_boot.rs | 225 ++++++++++++++++++ 9 files changed, 441 insertions(+), 27 deletions(-) create mode 100755 .github/hooks/pre-push create mode 100644 docs/g013-roadmap-pinpoints-693-695-verification-map.md diff --git a/.github/hooks/pre-push b/.github/hooks/pre-push new file mode 100755 index 00000000..2f396744 --- /dev/null +++ b/.github/hooks/pre-push @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Claw Code local pre-push safety gate. +# +# Install with: +# git config core.hooksPath .github/hooks +# +# This intentionally mirrors the CI build gate so stale field/enum references are +# caught before pushing to main or PR branches. +set -euo pipefail + +repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" +cd "$repo_root" + +if [[ ! -f rust/Cargo.toml ]]; then + echo "pre-push: rust/Cargo.toml not found; skipping cargo workspace build" >&2 + exit 0 +fi + +echo "pre-push: cargo build --manifest-path rust/Cargo.toml --workspace" >&2 +cargo build --manifest-path rust/Cargo.toml --workspace diff --git a/.omx/cc2/board.json b/.omx/cc2/board.json index 3eafdd7c..4b33d6b7 100644 --- a/.omx/cc2/board.json +++ b/.omx/cc2/board.json @@ -3,11 +3,11 @@ "duplicate_roadmap_heading_lines": [], "roadmap_actions_mapped": 542, "roadmap_actions_total": 542, - "roadmap_headings_mapped": 124, - "roadmap_headings_total": 124, + "roadmap_headings_mapped": 127, + "roadmap_headings_total": 127, "unmapped_roadmap_heading_lines": [] }, - "generated_at": "2026-05-14T08:13:45+00:00", + "generated_at": "2026-05-25T04:30:33+00:00", "generation_policy": { "release_buckets": [ "2.x_intake", @@ -14823,6 +14823,69 @@ "status": "context", "title": "Parity source metadata: openai/codex", "verification_required": "none_context_only" + }, + { + "category": "boot", + "deferral_rationale": "", + "dependencies": [ + "stream_0_governance" + ], + "id": "CC2-RM-H0125-pinpoint-693-claw-analog-bootstrap-plan", + "lifecycle_status": "done_verify", + "owner_lane": "stream_1_worker_boot_session_control", + "release_bucket": "alpha_blocker", + "source_anchor": "ROADMAP.md:L7528", + "source_context": "Clawable Coding Harness Roadmap > Pinpoint follow-up intake", + "source_level": 2, + "source_line": 7528, + "source_ordinal": null, + "source_path": "ROADMAP.md", + "source_type": "roadmap_heading", + "status": "done_verify", + "title": "Pinpoint #693. `claw-analog` bootstrap-plan phase parser silently falls back to `\"unknown\"` \u2014 `lib.rs:1114` uses `.unwrap_or(\"unknown\")` for phase field; unrecognized phases emit opaque kind instead of typed error", + "verification_required": "targeted_regression_or_acceptance_test_required" + }, + { + "category": "branch_recovery", + "deferral_rationale": "", + "dependencies": [ + "stream_0_governance" + ], + "id": "CC2-RM-H0126-pinpoint-694-no-pre-push-cargo-build-gat", + "lifecycle_status": "done_verify", + "owner_lane": "stream_3_branch_test_recovery", + "release_bucket": "alpha_blocker", + "source_anchor": "ROADMAP.md:L7538", + "source_context": "Clawable Coding Harness Roadmap > Pinpoint follow-up intake", + "source_level": 2, + "source_line": 7538, + "source_ordinal": null, + "source_path": "ROADMAP.md", + "source_type": "roadmap_heading", + "status": "done_verify", + "title": "Pinpoint #694. No pre-push `cargo build` gate \u2014 stale field refs (`retry_after`, `Team` variant, `config_load_error_kind`) broke main build undetected until CI", + "verification_required": "git_fixture_or_recovery_recipe_test" + }, + { + "category": "boot", + "deferral_rationale": "", + "dependencies": [ + "stream_0_governance" + ], + "id": "CC2-RM-H0127-pinpoint-695-agent-starts-in-stale-wrong", + "lifecycle_status": "done_verify", + "owner_lane": "stream_1_worker_boot_session_control", + "release_bucket": "alpha_blocker", + "source_anchor": "ROADMAP.md:L7548", + "source_context": "Clawable Coding Harness Roadmap > Pinpoint follow-up intake", + "source_level": 2, + "source_line": 7548, + "source_ordinal": null, + "source_path": "ROADMAP.md", + "source_type": "roadmap_heading", + "status": "done_verify", + "title": "Pinpoint #695. Agent starts in stale/wrong worktree and burns a full turn before noticing \u2014 no pre-flight check for \"file exists on current branch\" or \"this .git is writable from sandbox\"", + "verification_required": "worker_boot_state_machine_or_cli_json_contract_test" } ], "schema_version": "cc2.board.v1", @@ -14839,7 +14902,7 @@ "root": "/Users/bellman/Documents/Workspace/claw-code/.omx/research" }, "roadmap": { - "heading_count": 124, + "heading_count": 127, "ordered_action_count": 542, "path": "ROADMAP.md", "sha256_prefix": "2aba3315e52f3079" @@ -14850,15 +14913,15 @@ "adoption_overlay": 357, "parity_overlay": 20, "stream_0_governance": 221, - "stream_1_worker_boot_session_control": 15, + "stream_1_worker_boot_session_control": 17, "stream_2_event_reporting_contracts": 73, - "stream_3_branch_test_recovery": 16, + "stream_3_branch_test_recovery": 17, "stream_4_claws_first_execution": 5, "stream_5_plugin_mcp_lifecycle": 22 }, "by_release_bucket": { "2.x_intake": 30, - "alpha_blocker": 240, + "alpha_blocker": 243, "beta_adoption": 417, "context": 15, "ga_ecosystem": 22, @@ -14870,13 +14933,13 @@ "latest_open_issue": 30, "parity_repo_context": 2, "roadmap_action": 542, - "roadmap_heading": 124 + "roadmap_heading": 127 }, "by_status": { "active": 73, "context": 15, "deferred_with_rationale": 9, - "done_verify": 313, + "done_verify": 316, "open": 285, "rejected_not_claw": 2, "stale_done": 31, diff --git a/.omx/cc2/board.md b/.omx/cc2/board.md index 08b407f3..4a89297a 100644 --- a/.omx/cc2/board.md +++ b/.omx/cc2/board.md @@ -1,6 +1,6 @@ # Claw Code 2.0 Canonical Board -Generated from board schema: `2026-05-14T08:13:45+00:00` +Generated from board schema: `2026-05-25T04:30:33+00:00` Schema version: `cc2.board.v1` Ultragoal mutation policy: `.omx/ultragoal` is leader-owned and was not modified by this rendering task. @@ -8,7 +8,7 @@ Ultragoal mutation policy: `.omx/ultragoal` is leader-owned and was not modified | Source | Frozen evidence | | --- | --- | -| Roadmap | `ROADMAP.md` sha256 prefix `2aba3315e52f3079`; 124 headings; 542 ordered actions | +| Roadmap | `ROADMAP.md` sha256 prefix `2aba3315e52f3079`; 127 headings; 542 ordered actions | | Approved plan | `.omx/plans/claw-code-2-0-adaptive-plan.md` sha256 prefix `e7ef6faf23bfc16b` | | Research bundle | root `/Users/bellman/Documents/Workspace/claw-code/.omx/research`; latest open issues 30; issue corpus 1000; codex/opencode clone metadata included | @@ -16,11 +16,11 @@ Ultragoal mutation policy: `.omx/ultragoal` is leader-owned and was not modified | Coverage gate | Mapped | Total | Status | | --- | --- | --- | --- | -| ROADMAP headings | 124 | 124 | PASS | +| ROADMAP headings | 127 | 127 | PASS | | ROADMAP ordered actions | 542 | 542 | PASS | | Duplicate heading lines | 0 | 0 | PASS | -Total canonical board items: **729** +Total canonical board items: **732** ## Lifecycle Enum Reference @@ -29,7 +29,7 @@ Total canonical board items: **729** | `active` | 73 | Current Claw Code 2.0 implementation surface that should remain visible on the board. | | `context` | 15 | Context-only heading or evidence anchor; not an implementation work item. | | `deferred_with_rationale` | 9 | Intentionally deferred; rationale must be present in the board item. | -| `done_verify` | 313 | Marked as done upstream but retained for verification against current CC2 behavior. | +| `done_verify` | 316 | Marked as done upstream but retained for verification against current CC2 behavior. | | `open` | 285 | Actionable unresolved work that needs implementation or acceptance evidence. | | `rejected_not_claw` | 2 | Excluded because it is not Claw Code product work. | | `stale_done` | 31 | Historically completed or merged work that may be stale and needs freshness checks before relying on it. | @@ -40,7 +40,7 @@ Total canonical board items: **729** | Bucket | Count | Meaning | | --- | --- | --- | | `2.x_intake` | 30 | Post-2.0 intake or follow-up candidate retained for sequencing. | -| `alpha_blocker` | 240 | Must be resolved before alpha-quality autonomous coding lanes are dependable. | +| `alpha_blocker` | 243 | Must be resolved before alpha-quality autonomous coding lanes are dependable. | | `beta_adoption` | 417 | Important for broader dogfood/adoption once alpha blockers are controlled. | | `context` | 15 | Non-actionable roadmap context. | | `ga_ecosystem` | 22 | Required for mature plugin/MCP/provider ecosystem behavior. | @@ -54,9 +54,9 @@ Total canonical board items: **729** | Adoption overlay — user-visible parity and release polish | 357 | 329 | `deferred_with_rationale` 3, `done_verify` 237, `open` 92, `rejected_not_claw` 2, `stale_done` 23 | | Parity overlay — opencode/codex comparison context | 20 | 16 | `context` 2, `deferred_with_rationale` 1, `done_verify` 5, `open` 11, `stale_done` 1 | | Stream 0 — Governance, intake, and cross-cutting roadmap triage | 221 | 198 | `active` 6, `context` 13, `deferred_with_rationale` 4, `done_verify` 45, `open` 147, `stale_done` 5, `superseded` 1 | -| Stream 1 — Worker boot and session control | 15 | 14 | `active` 8, `deferred_with_rationale` 1, `open` 6 | +| Stream 1 — Worker boot and session control | 17 | 16 | `active` 8, `deferred_with_rationale` 1, `done_verify` 2, `open` 6 | | Stream 2 — Event/reporting contracts | 73 | 73 | `active` 45, `done_verify` 20, `open` 8 | -| Stream 3 — Branch/test recovery | 16 | 14 | `active` 6, `done_verify` 1, `open` 7, `stale_done` 2 | +| Stream 3 — Branch/test recovery | 17 | 15 | `active` 6, `done_verify` 2, `open` 7, `stale_done` 2 | | Stream 4 — Claws-first task execution | 5 | 5 | `active` 4, `done_verify` 1 | | Stream 5 — Plugin/MCP lifecycle | 22 | 22 | `active` 4, `done_verify` 4, `open` 14 | @@ -68,7 +68,7 @@ Total canonical board items: **729** | `latest_open_issue` | 30 | | `parity_repo_context` | 2 | | `roadmap_action` | 542 | -| `roadmap_heading` | 124 | +| `roadmap_heading` | 127 | ## Board Items by Stream @@ -704,6 +704,8 @@ Total canonical board items: **729** | `CC2-RM-A0363-surface-inconsistency-cluster-of-3-after` | **Surface inconsistency (cluster of 3)**: after #143 Phase 1, the behavior matrix is: | `ROADMAP.md:L5515` / `roadmap_action` | `alpha_blocker` | `open` | `plugin_mcp_lifecycle_contract_test` | `stream_1_worker_boot_session_control` | — | | `CC2-RM-A0391-remove-the-error-prefix-from-format-unkn` | Remove the "error:" prefix from format_unknown_verb_option (already added by top-level handler) | `ROADMAP.md:L5916` / `roadmap_action` | `alpha_blocker` | `open` | `worker_boot_state_machine_or_cli_json_contract_test` | none | — | | `CC2-RM-A0512-system-prompt-output-format-json-exposes` | **`system-prompt --output-format json` exposes `"__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__"` as a literal element in the `sections` array — an internal split delimiter leaked into the public structured output** — dogfooded 2026-04-30 by Jobdori on `e939777f`. Running `claw system-prompt --output-format json` returns `{"kind":"system-prompt","message":"","sections":["You are an interactive agent...", "# System\n...", "# Doing tasks\n...", "# Executing actions with care\n...", "__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__", "# Environment context\n...", "# Project context\n...", "# Claude instructions\n...", "# Runtime config\n..."]}`. The `sections` array has 9 elements; element index 4 is the raw string `"__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__"`. This internal sentinel marks the boundary between the static and dynamic sections of the compiled system prompt, used during assembly to split the prompt at injection time. It appears in the public JSON output verbatim as a first-class section, indistinguishable from real sections by type alone. Automation that iterates `sections[]` must special-case this sentinel or it will process an internal implementation string as if it were a real system prompt section. **Required fix shape:** (a) strip `"__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__"` and any similar internal delimiters from the `sections` array before serializing to JSON; (b) if the static/dynamic boundary is semantically meaningful for callers, expose it as a structured metadata field such as `boundary_index:4` or as a `section_type:"static"\|"dynamic"` field on each section entry, not as a raw sentinel string in the array; (c) rename the `sections` type from `string[]` to `[{id, type, content}]` to enable this without breaking the boundary signal; (d) add regression coverage proving the `system-prompt --output-format json` output's `sections` array contains no elements whose value equals `"__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__"` or matches `/__[A-Z_]+__/`. **Why this matters:** internal sentinel strings in public JSON are a contract liability — they couple the wire format to internal implementation details. Any refactor that renames or removes the sentinel breaks callers that don't special-case it, and automation that doesn't know to filter it will miscount, misparse, or misrender the system prompt. Source: Jobdori live dogfood, `e939777f`, 2026-04-30. | `ROADMAP.md:L6333` / `roadmap_action` | `beta_adoption` | `open` | `worker_boot_state_machine_or_cli_json_contract_test` | none | — | +| `CC2-RM-H0125-pinpoint-693-claw-analog-bootstrap-plan` | Pinpoint #693. `claw-analog` bootstrap-plan phase parser silently falls back to `"unknown"` — `lib.rs:1114` uses `.unwrap_or("unknown")` for phase field; unrecognized phases emit opaque kind instead of typed error | `ROADMAP.md:L7528` / `roadmap_heading` | `alpha_blocker` | `done_verify` | `targeted_regression_or_acceptance_test_required` | `stream_0_governance` | — | +| `CC2-RM-H0127-pinpoint-695-agent-starts-in-stale-wrong` | Pinpoint #695. Agent starts in stale/wrong worktree and burns a full turn before noticing — no pre-flight check for "file exists on current branch" or "this .git is writable from sandbox" | `ROADMAP.md:L7548` / `roadmap_heading` | `alpha_blocker` | `done_verify` | `worker_boot_state_machine_or_cli_json_contract_test` | `stream_0_governance` | — | ### Stream 2 — Event/reporting contracts @@ -803,6 +805,7 @@ Total canonical board items: **729** | `CC2-RM-A0410-remediation-registry-a-function-remediat` | **Remediation registry:** A function `remediation_for(kind: &str, operation: &str) -> Remediation` that maps `(error_kind, operation_context)` pairs to stable remediation structs: | `ROADMAP.md:L6041` / `roadmap_action` | `alpha_blocker` | `open` | `targeted_regression_or_acceptance_test_required` | `stream_2_event_reporting_contracts` | — | | `CC2-RM-A0411-stable-hint-outputs-per-class-each-error` | **Stable hint outputs per class:** Each `error_kind` maps to exactly one remediation shape. No more prose splitting. | `ROADMAP.md:L6049` / `roadmap_action` | `alpha_blocker` | `open` | `targeted_regression_or_acceptance_test_required` | `stream_2_event_reporting_contracts` | — | | `CC2-RM-A0412-golden-fixture-tests-test-each-kind-oper` | **Golden fixture tests:** Test each `(kind, operation)` pair against expected remediation output as golden fixtures instead of the current `split_error_hint()` string hacks. | `ROADMAP.md:L6050` / `roadmap_action` | `alpha_blocker` | `open` | `targeted_regression_or_acceptance_test_required` | `stream_2_event_reporting_contracts` | — | +| `CC2-RM-H0126-pinpoint-694-no-pre-push-cargo-build-gat` | Pinpoint #694. No pre-push `cargo build` gate — stale field refs (`retry_after`, `Team` variant, `config_load_error_kind`) broke main build undetected until CI | `ROADMAP.md:L7538` / `roadmap_heading` | `alpha_blocker` | `done_verify` | `git_fixture_or_recovery_recipe_test` | `stream_0_governance` | — | ### Stream 4 — Claws-first task execution diff --git a/.omx/ultragoal/goals.json b/.omx/ultragoal/goals.json index 161d96d7..ac8d1c92 100644 --- a/.omx/ultragoal/goals.json +++ b/.omx/ultragoal/goals.json @@ -1,7 +1,7 @@ { "version": 1, "createdAt": "2026-05-14T07:53:46.061Z", - "updatedAt": "2026-05-15T04:38:54.887Z", + "updatedAt": "2026-05-25T04:18:52.711Z", "briefPath": ".omx/ultragoal/brief.md", "goalsPath": ".omx/ultragoal/goals.json", "ledgerPath": ".omx/ultragoal/ledger.jsonl", @@ -148,7 +148,19 @@ "updatedAt": "2026-05-15T04:38:54.887Z", "evidence": "G012-final-gate complete: team g012-final-gate-ultra-e61d2271 8/8 tasks complete; final gate log /tmp/g012-final-quality-gate-pass4.log; commit 04c2abb pushed; docs/pr-triage-g012-final-gate.json docs/pr-issue-resolution-gate.md docs/g012-final-release-readiness-report.md; .omx/ultragoal/goals.json and ledger.jsonl updated; aiSlopCleaner and codeReview evidence included in quality gate JSON.", "completedAt": "2026-05-15T04:38:54.887Z" + }, + { + "id": "G013-implement-roadmap-pinpoints-693-695", + "title": "Implement ROADMAP pinpoints #693-#695", + "objective": "Map and implement the newly appended ROADMAP.md pinpoints #693, #694, and #695 after reset to origin/main: typed claw-analog bootstrap phase errors, a local pre-push cargo build gate, and startup/worktree preflight diagnostics; update CC2 board/coverage and verify with targeted and workspace checks.", + "status": "in_progress", + "attempt": 1, + "createdAt": "2026-05-25T04:18:43.420Z", + "updatedAt": "2026-05-25T04:18:52.711Z", + "evidence": "Current-head verification after reset: python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json failed with unmapped ROADMAP headings [7528,7538,7548], corresponding to Pinpoints #693-#695.", + "startedAt": "2026-05-25T04:18:52.711Z" } ], - "codexObjective": "Complete the approved Claw Code 2.0 ultragoal delivery: implement all classified ROADMAP.md backlog work through execution-sized stream goals G001-G012, using .omx/ultragoal/ledger.jsonl as the durable audit trail and .omx/plans/claw-code-2-0-adaptive-plan.md as the source plan." + "codexObjective": "Complete the approved Claw Code 2.0 ultragoal delivery: implement all classified ROADMAP.md backlog work through execution-sized stream goals G001-G012, using .omx/ultragoal/ledger.jsonl as the durable audit trail and .omx/plans/claw-code-2-0-adaptive-plan.md as the source plan.", + "activeGoalId": "G013-implement-roadmap-pinpoints-693-695" } diff --git a/.omx/ultragoal/ledger.jsonl b/.omx/ultragoal/ledger.jsonl index 375e95ba..b3a4eaca 100644 --- a/.omx/ultragoal/ledger.jsonl +++ b/.omx/ultragoal/ledger.jsonl @@ -21,3 +21,5 @@ {"ts":"2026-05-15T02:21:31.360Z","event":"goal_started","goalId":"G011-ecosystem-ops-ux","status":"in_progress","message":"Attempt 1"} {"ts":"2026-05-15T02:55:26.988Z","event":"goal_completed","goalId":"G011-ecosystem-ops-ux","status":"complete","evidence":"G011-ecosystem-ops-ux complete: team g011-ecosystem-ops-ux-e61d2271 phase=complete with 7/7 tasks completed; final pushed HEAD 1ac8ce8; verification evidence in .omx/ultragoal/g011-final-quality-gate.log and .omx/ultragoal/quality-gate-G011-ecosystem-ops-ux.json; ultragoal artifacts tracked in .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl.","codexGoal":{"available":true,"objective":"Complete the approved Claw Code 2.0 ultragoal delivery: implement all classified ROADMAP.md backlog work through execution-sized stream goals G001-G012, using .omx/ultragoal/ledger.jsonl as the durable audit trail and .omx/plans/claw-code-2-0-adaptive-plan.md as the source plan.","status":"active","remainingTokens":null,"raw":{"goal":{"threadId":"019e2560-a38d-7282-bb33-58c944cdcbc9","objective":"Complete the approved Claw Code 2.0 ultragoal delivery: implement all classified ROADMAP.md backlog work through execution-sized stream goals G001-G012, using .omx/ultragoal/ledger.jsonl as the durable audit trail and .omx/plans/claw-code-2-0-adaptive-plan.md as the source plan.","status":"active","tokensUsed":5585887,"timeUsedSeconds":16657,"createdAt":1778745278,"updatedAt":1778813687},"remainingTokens":null,"completionBudgetReport":null}}} {"ts":"2026-05-15T04:38:54.887Z","event":"goal_completed","goalId":"G012-final-gate","status":"complete","evidence":"G012-final-gate complete: team g012-final-gate-ultra-e61d2271 8/8 tasks complete; final gate log /tmp/g012-final-quality-gate-pass4.log; commit 04c2abb pushed; docs/pr-triage-g012-final-gate.json docs/pr-issue-resolution-gate.md docs/g012-final-release-readiness-report.md; .omx/ultragoal/goals.json and ledger.jsonl updated; aiSlopCleaner and codeReview evidence included in quality gate JSON.","codexGoal":{"available":true,"objective":"Complete the approved Claw Code 2.0 ultragoal delivery: implement all classified ROADMAP.md backlog work through execution-sized stream goals G001-G012, using .omx/ultragoal/ledger.jsonl as the durable audit trail and .omx/plans/claw-code-2-0-adaptive-plan.md as the source plan.","status":"complete","remainingTokens":null,"raw":{"goal":{"threadId":"019e2560-a38d-7282-bb33-58c944cdcbc9","objective":"Complete the approved Claw Code 2.0 ultragoal delivery: implement all classified ROADMAP.md backlog work through execution-sized stream goals G001-G012, using .omx/ultragoal/ledger.jsonl as the durable audit trail and .omx/plans/claw-code-2-0-adaptive-plan.md as the source plan.","status":"complete","tokensUsed":5923242,"timeUsedSeconds":18763,"createdAt":1778745278,"updatedAt":1778819793},"remainingTokens":null,"completionBudgetReport":"Goal achieved. Report final budget usage to the user: time used: 18763 seconds."}},"qualityGate":{"goal_id":"G012-final-gate","status":"passed","team":"g012-final-gate-ultra-e61d2271","commit":"04c2abb","pushed":true,"log":"/tmp/g012-final-quality-gate-pass4.log","checks":[{"name":"git diff --check","status":"pass"},{"name":"doc source of truth","command":"python3 .github/scripts/check_doc_source_of_truth.py","status":"pass"},{"name":"release readiness","command":"python3 .github/scripts/check_release_readiness.py","status":"pass"},{"name":"cc2 board validation","command":"python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json","status":"pass","items":729,"roadmap_headings":"124/124","roadmap_actions":"542/542"},{"name":"issue parity intake","command":"python3 .omx/cc2/validate_issue_parity_intake.py .omx/cc2/issue-parity-intake.json","status":"pass","issue_rows":19,"parity_rows":9},{"name":"rust fmt","command":"cargo fmt --manifest-path rust/Cargo.toml --all -- --check","status":"pass"},{"name":"rust check","command":"cargo check --manifest-path rust/Cargo.toml --workspace","status":"pass"},{"name":"rust workspace tests","command":"cargo test --manifest-path rust/Cargo.toml --workspace -- --nocapture","status":"pass"},{"name":"rust clippy all targets","command":"cargo clippy --manifest-path rust/Cargo.toml --workspace --all-targets -- -D warnings","status":"pass"}],"remote_pr_issue_gate":{"prs_merged":0,"issues_mutated":0,"reason":"G012 reconciliation evidence classified open PRs/issues; no remote merges or issue mutations were safe without maintainer approval/fresh green checks/conflict-free branches.","evidence":["docs/pr-triage-g012-final-gate.json","docs/pr-issue-resolution-gate.md","docs/g012-final-release-readiness-report.md"]},"aiSlopCleaner":{"status":"passed","evidence":"G012 final pass removed gate-blocking test/clippy failures, preserved existing behavior with workspace tests, and avoided new dependencies; cleanup risk documented in commit 04c2abb.","checks":["cargo fmt --check","cargo test --workspace","cargo clippy --workspace --all-targets -- -D warnings"],"changed_files_reviewed":["rust/crates/tools/src/lib.rs","rust/crates/rusty-claude-cli/src/main.rs","rust/Cargo.toml"]},"evidence":["/tmp/g012-final-quality-gate-pass4.log","docs/g012-final-release-readiness-report.md","docs/pr-triage-g012-final-gate.json","docs/pr-issue-resolution-gate.md",".omx/ultragoal/goals.json",".omx/ultragoal/ledger.jsonl"],"verification":{"status":"passed","checks":[{"command":"git diff --check","status":"passed"},{"command":"python3 .github/scripts/check_doc_source_of_truth.py","status":"passed"},{"command":"python3 .github/scripts/check_release_readiness.py","status":"passed"},{"command":"python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json","status":"passed","items":729,"roadmap_headings":"124/124","roadmap_actions":"542/542"},{"command":"python3 .omx/cc2/validate_issue_parity_intake.py .omx/cc2/issue-parity-intake.json","status":"passed","issue_rows":19,"parity_rows":9},{"command":"cargo fmt --manifest-path rust/Cargo.toml --all -- --check","status":"passed"},{"command":"cargo check --manifest-path rust/Cargo.toml --workspace","status":"passed"},{"command":"cargo test --manifest-path rust/Cargo.toml --workspace -- --nocapture","status":"passed"},{"command":"cargo clippy --manifest-path rust/Cargo.toml --workspace --all-targets -- -D warnings","status":"passed"}],"log":"/tmp/g012-final-quality-gate-pass4.log","commands":["git diff --check","python3 .github/scripts/check_doc_source_of_truth.py","python3 .github/scripts/check_release_readiness.py","python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json","python3 .omx/cc2/validate_issue_parity_intake.py .omx/cc2/issue-parity-intake.json","cargo fmt --manifest-path rust/Cargo.toml --all -- --check","cargo check --manifest-path rust/Cargo.toml --workspace","cargo test --manifest-path rust/Cargo.toml --workspace -- --nocapture","cargo clippy --manifest-path rust/Cargo.toml --workspace --all-targets -- -D warnings"],"evidence":"/tmp/g012-final-quality-gate-pass4.log; docs/g012-final-release-readiness-report.md; docs/pr-triage-g012-final-gate.json; docs/pr-issue-resolution-gate.md; .omx/ultragoal/goals.json; .omx/ultragoal/ledger.jsonl"},"codeReview":{"status":"passed","evidence":"Leader reviewed G012 worker outputs, final gate diffs, and verification results; no unresolved code blockers remain after commit 04c2abb.","reviewed":["worker-1 release readiness report","worker-2 final gate failures","worker-3 PR reconciliation","worker-4 issue reconciliation","leader final quality gate fixes"],"recommendation":"APPROVE","architectStatus":"CLEAR"}}} +{"ts":"2026-05-25T04:18:43.420Z","event":"steering_accepted","evidence":"Current-head verification after reset: python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json failed with unmapped ROADMAP headings [7528,7538,7548], corresponding to Pinpoints #693-#695.","message":"The aggregate ROADMAP plan was previously complete, but origin/main now contains newly appended roadmap headings that must be included before claiming all ROADMAP is implemented/tested.","steering":{"kind":"add_subgoal","source":"cli","targetGoalIds":[],"before":{"version":1,"createdAt":"2026-05-14T07:53:46.061Z","updatedAt":"2026-05-15T04:38:54.887Z","briefPath":".omx/ultragoal/brief.md","goalsPath":".omx/ultragoal/goals.json","ledgerPath":".omx/ultragoal/ledger.jsonl","codexGoalMode":"aggregate","goals":[{"id":"G001-stream0-board","title":"Stream 0: Generate canonical CC2 board","objective":"Generate the canonical Claw Code 2.0 board from frozen ROADMAP.md, latest issue snapshot, parity evidence, and approved plan. Classify every actionable roadmap item and context heading with source_anchor, source_type, release_bucket, lifecycle status, dependencies, verification_required, and deferral rationale. Emit machine JSON plus human markdown.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T08:14:23.206Z","startedAt":"2026-05-14T07:54:26.032Z","completedAt":"2026-05-14T08:14:23.206Z","evidence":"G001-stream0-board complete via team ultragoal-g001-stream-e61d2271: team status phase=team-verify, tasks 5/5 completed; worker-2 produced issue/parity intake, worker-3 produced board Markdown/rendering, worker-4 recorded validation evidence, worker-1 completed initial board artifacts. Leader reconciliation commit 45b43b5 aligned scripts/generate_cc2_board.py, scripts/validate_cc2_board.py, scripts/cc2_board.py, .omx/cc2/render_board_md.py. Evidence artifacts: .omx/cc2/board.json, .omx/cc2/board.md, .omx/cc2/issue-parity-intake.json, .omx/cc2/issue-parity-intake.md; .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl remain leader-owned. Verification passed: python3 scripts/generate_cc2_board.py; python3 scripts/validate_cc2_board.py; python3 scripts/cc2_board.py validate; python3 .omx/cc2/validate_issue_parity_intake.py; python3 .omx/cc2/render_board_md.py .omx/cc2/board.json .omx/cc2/board.md --check; python3 -m py_compile scripts/generate_cc2_board.py scripts/validate_cc2_board.py scripts/cc2_board.py .omx/cc2/validate_issue_parity_intake.py .omx/cc2/render_board_md.py; cargo check --manifest-path rust/Cargo.toml --workspace."},{"id":"G002-alpha-security","title":"Stream 6: Day-one security and permissions gate","objective":"Implement/verify alpha-blocking security scope: file tools and shell enforce workspace/path scope across direct paths, symlinks, globbing, shell expansion, worktrees, and Windows path cases. Add regression fixtures for #3007 class behavior and permission-mode event/status visibility.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T08:34:04.243Z","startedAt":"2026-05-14T08:14:46.422Z","completedAt":"2026-05-14T08:34:04.243Z","evidence":"G002-alpha-security team ultragoal-g002-alpha-e61d2271 reached phase=complete with 5/5 tasks completed and no worker .omx/ultragoal mutation. Integrated commits through 37b2b75 on main: workspace/path enforcement in rust/crates/runtime/src/file_ops.rs, rust/crates/runtime/src/lib.rs, rust/crates/tools/src/lib.rs, regressions in rust/crates/tools/tests/path_scope_enforcement.rs and rust/crates/rusty-claude-cli/tests/output_format_contract.rs, verification map docs/g002-security-verification-map.md. Fresh leader validation passed: git diff --check; cargo fmt --manifest-path rust/Cargo.toml --all -- --check; cargo test --manifest-path rust/Cargo.toml -p tools path_scope -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p tools --test path_scope_enforcement -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime workspace_ -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --test output_format_contract -- --nocapture; python3 -m pytest tests/test_security_scope.py -q; cargo check --manifest-path rust/Cargo.toml --workspace. .omx/ultragoal artifacts retained as leader-owned durable audit trail; fresh get_goal JSON captured at .omx/ultragoal/get-goal-G002-alpha-security.json. Known unrelated non-gating gaps from worker verification: full cargo test --workspace has pre-existing session_lifecycle_prefers_running_process_over_idle_shell failure; clippy all-targets has pre-existing runtime lint warnings."},{"id":"G003-boot-session","title":"Stream 1: Reliable worker boot/session control","objective":"Implement/verify worker lifecycle, first prompt acceptance SLA, startup-no-evidence classifier, trust resolver/default trusted roots, structured session control API, and boot preflight/doctor JSON contracts.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T08:54:40.729Z","startedAt":"2026-05-14T08:34:19.605Z","completedAt":"2026-05-14T08:54:40.729Z","evidence":"G003-boot-session team g003-boot-session-ult-e61d2271 reached phase=complete with 5/5 tasks completed and no worker .omx/ultragoal mutation. Implemented/verified Stream 1 reliable worker boot/session control: worker lifecycle/prompt SLA and path guardrails, default trusted roots merge via runtime config and WorkerCreate, startup-no-evidence evidence/classifier timestamp coverage, structured boot preflight/status/doctor JSON, and docs/g003-boot-session-verification-map.md. Integrated/pushed through origin/main aec291c. Final leader validation passed: git diff --check; cargo fmt --manifest-path rust/Cargo.toml --all -- --check; cargo test --manifest-path rust/Cargo.toml -p runtime trusted_roots -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime trust_resolver -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime startup -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime worker_boot -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p tools worker_create_merges_config_trusted_roots -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p tools path_scope -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli boot_preflight -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli branch_freshness -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli status_json_surfaces_session_lifecycle_for_clawhip -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --test output_format_contract -- --nocapture; cargo check --manifest-path rust/Cargo.toml --workspace; python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json; python3 .omx/cc2/validate_issue_parity_intake.py .omx/cc2/issue-parity-intake.json. Fresh get_goal JSON captured at .omx/ultragoal/get-goal-G003-boot-session.complete.json and .omx/ultragoal goals/ledger remain leader-owned audit artifacts. Known non-gating gaps from worker clippy attempts are pre-existing unrelated runtime clippy warnings and full workspace tests remain deferred to final gates."},{"id":"G004-events-reports","title":"Stream 2: Event/report contract families","objective":"Implement/verify canonical lane events, ordering/provenance/identity/dedupe/ownership, report schema/projection/redaction/capability negotiation, approval-token chain, and pinpoint closure batches with golden fixtures.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T09:15:44.223Z","startedAt":"2026-05-14T08:54:55.093Z","completedAt":"2026-05-14T09:15:44.223Z","evidence":"G004-events-reports complete: team g004-events-reports-u-e61d2271 phase complete with 7/7 tasks completed; pushed main through 879962b; leader verification passed cargo fmt --manifest-path rust/Cargo.toml --all -- --check, cargo check --manifest-path rust/Cargo.toml -p runtime, cargo test --manifest-path rust/Cargo.toml -p runtime -- --nocapture (535 unit + g004_conformance 2 + integration 12 + doctests), python3 .github/scripts/check_doc_source_of_truth.py; evidence recorded against .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl"},{"id":"G005-branch-recovery","title":"Stream 3: Branch/test awareness and recovery","objective":"Implement/verify stale branch detection before broad tests, recovery recipes and ledger, green-ness contract, test provenance, hung-test classification, and recovery/status reporting.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T12:41:48.997Z","startedAt":"2026-05-14T09:16:01.781Z","completedAt":"2026-05-14T12:41:48.997Z","evidence":"G005-branch-recovery complete and pushed at 7426ede; team g005-branch-recovery-e61d2271 has 5/5 tasks completed; leader verification passed for branch freshness before broad tests, recovery ledger/status reporting, green-ness contract/test provenance, stale-base doctor/status consistency, hung-test classification, and docs/g005-branch-recovery-verification-map.md. Evidence recorded against .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl."},{"id":"G006-task-policy-board","title":"Stream 4: Task packets, policy engine, lane board","objective":"Implement/verify typed task packet schema, executable policy engine, active lane board/dashboard, running-state liveness heartbeat, and task/lane status JSON.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T00:42:05.094Z","startedAt":"2026-05-14T12:41:57.815Z","completedAt":"2026-05-15T00:42:05.094Z","evidence":"G006-task-policy-board complete in pushed origin/main commit 65a144c; team g006-task-policy-boar-e61d2271 terminal with 5 completed/0 failed after leader reconciliation; verification map docs/g006-task-policy-board-verification-map.md plus quality gate JSON record cargo fmt/check/tests/diff/push; .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl preserved; workers did not mutate .omx/ultragoal."},{"id":"G007-plugin-mcp","title":"Stream 5: Plugin/MCP lifecycle maturity","objective":"Implement/verify plugin/MCP lifecycle states, healthy/degraded/failed startup, required vs optional behavior, malformed config consistency across status/doctor/mcp/plugins, and mock MCP/plugin tests.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T01:16:43.414Z","startedAt":"2026-05-15T00:42:16.309Z","completedAt":"2026-05-15T01:16:43.414Z","evidence":"G007-plugin-mcp complete: team g007-plugin-mcp-ultra-e61d2271 phase complete with 13/13 tasks completed, verification passed, pushed head 2202410, and durable ultragoal artifacts updated in .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl."},{"id":"G008-provider-compat","title":"Stream 7: Provider/model compatibility","objective":"Implement/verify OpenAI-compatible slash-containing model IDs, provider prefix routing over env sniffing, DeepSeek/reasoning diagnostics, web search/fetch behavior, proxy/custom parameter passthrough, token/cost accounting, and provider diagnostics.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T01:38:22.717Z","startedAt":"2026-05-15T01:17:53.783Z","completedAt":"2026-05-15T01:38:22.717Z","evidence":"G008-provider-compat complete: team g008-provider-compat-e61d2271 phase complete with 5/5 tasks terminal; provider/model compatibility implemented and verified; pushed origin/main 2cac66c..8c9a05e; evidence recorded in .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl plus quality gate .omx/ultragoal/quality-gate-G008-provider-compat.json."},{"id":"G009-windows-docs-release","title":"Stream 8: Windows/install/docs/license readiness","objective":"Implement/verify PowerShell-first docs, safe provider switching examples, Windows smoke CI, release artifact quickstart, license/contribution/security/support policies, and command/link validation.","status":"complete","attempt":0,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T01:57:41.565Z","completedAt":"2026-05-15T01:57:41.565Z","evidence":"G009-windows-docs-release complete at commit 5294648 with team g009-windows-docs-rel-e61d2271 phase complete, 5/5 tasks completed; evidence in .omx/ultragoal/quality-gate-G009-windows-docs-release.json, .omx/ultragoal/get-goal-G009-windows-docs-release.complete.json, .omx/ultragoal/goals.json, and .omx/ultragoal/ledger.jsonl."},{"id":"G010-session-hygiene","title":"Stream 9: Session hygiene/local state/recovery UX","objective":"Implement/verify session file hygiene, .gitignore state paths, per-worktree session isolation, list/delete/exists/compact/resume, compact/provider-context recovery, JSONL payload bloat safeguards, interrupt recovery, and clone disambiguation metadata.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T02:20:46.558Z","startedAt":"2026-05-15T01:59:22.219Z","completedAt":"2026-05-15T02:20:46.558Z","evidence":"G010-session-hygiene complete: team g010-session-hygiene-e61d2271 phase complete with 7/7 tasks completed; final verification passed in .omx/ultragoal/g010-final-quality-gate-rerun.log; durable state recorded in .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl."},{"id":"G011-ecosystem-ops-ux","title":"Streams 10–12: Ecosystem, issue ops, and UX laterals","objective":"Implement/verify gated ACP/Zed/JSON-RPC serve plan/status, anti-slop issue/PR triage, issue templates, navigation/file-context docs, TUI/rendering/copy/paste/clickable path improvements, and defer desktop/marketplace features until contracts are stable.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T02:55:26.988Z","startedAt":"2026-05-15T02:21:31.360Z","completedAt":"2026-05-15T02:55:26.988Z","evidence":"G011-ecosystem-ops-ux complete: team g011-ecosystem-ops-ux-e61d2271 phase=complete with 7/7 tasks completed; final pushed HEAD 1ac8ce8; verification evidence in .omx/ultragoal/g011-final-quality-gate.log and .omx/ultragoal/quality-gate-G011-ecosystem-ops-ux.json; ultragoal artifacts tracked in .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl."},{"id":"G012-final-gate","title":"Final release gate: Verify Claw Code 2.0 delivery","objective":"Run final cross-stream quality gate: roadmap board has no unmapped actionable items, fmt/clippy/tests and focused contract suites pass, ai-slop-cleaner on changed files passes/no-ops, code-review approves, and final alpha/beta/GA readiness report is written. Final completion is blocked until docs/pr-issue-resolution-gate.md has fresh evidence showing every open PR and issue was triaged, with correct PRs merged and resolvable correct issues fixed or closed.","status":"complete","attempt":0,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T04:38:54.887Z","evidence":"G012-final-gate complete: team g012-final-gate-ultra-e61d2271 8/8 tasks complete; final gate log /tmp/g012-final-quality-gate-pass4.log; commit 04c2abb pushed; docs/pr-triage-g012-final-gate.json docs/pr-issue-resolution-gate.md docs/g012-final-release-readiness-report.md; .omx/ultragoal/goals.json and ledger.jsonl updated; aiSlopCleaner and codeReview evidence included in quality gate JSON.","completedAt":"2026-05-15T04:38:54.887Z"}],"codexObjective":"Complete the approved Claw Code 2.0 ultragoal delivery: implement all classified ROADMAP.md backlog work through execution-sized stream goals G001-G012, using .omx/ultragoal/ledger.jsonl as the durable audit trail and .omx/plans/claw-code-2-0-adaptive-plan.md as the source plan."},"after":{"id":"G013-implement-roadmap-pinpoints-693-695","title":"Implement ROADMAP pinpoints #693-#695","objective":"Map and implement the newly appended ROADMAP.md pinpoints #693, #694, and #695 after reset to origin/main: typed claw-analog bootstrap phase errors, a local pre-push cargo build gate, and startup/worktree preflight diagnostics; update CC2 board/coverage and verify with targeted and workspace checks.","status":"pending","attempt":0,"createdAt":"2026-05-25T04:18:43.420Z","updatedAt":"2026-05-25T04:18:43.420Z","evidence":"Current-head verification after reset: python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json failed with unmapped ROADMAP headings [7528,7538,7548], corresponding to Pinpoints #693-#695."},"evidence":"Current-head verification after reset: python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json failed with unmapped ROADMAP headings [7528,7538,7548], corresponding to Pinpoints #693-#695.","rationale":"The aggregate ROADMAP plan was previously complete, but origin/main now contains newly appended roadmap headings that must be included before claiming all ROADMAP is implemented/tested.","invariant":{"structuralInvariantAccepted":true,"evidenceBackedNecessity":true,"noEasierCompletion":true,"accepted":true,"rejectedReasons":[],"reasons":[]},"directiveText":"--kind add_subgoal --title Implement ROADMAP pinpoints #693-#695 --objective Map and implement the newly appended ROADMAP.md pinpoints #693, #694, and #695 after reset to origin/main: typed claw-analog bootstrap phase errors, a local pre-push cargo build gate, and startup/worktree preflight diagnostics; update CC2 board/coverage and verify with targeted and workspace checks. --evidence Current-head verification after reset: python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json failed with unmapped ROADMAP headings [7528,7538,7548], corresponding to Pinpoints #693-#695. --rationale The aggregate ROADMAP plan was previously complete, but origin/main now contains newly appended roadmap headings that must be included before claiming all ROADMAP is implemented/tested. --json"},"mutationKind":"add_subgoal","before":{"version":1,"createdAt":"2026-05-14T07:53:46.061Z","updatedAt":"2026-05-15T04:38:54.887Z","briefPath":".omx/ultragoal/brief.md","goalsPath":".omx/ultragoal/goals.json","ledgerPath":".omx/ultragoal/ledger.jsonl","codexGoalMode":"aggregate","goals":[{"id":"G001-stream0-board","title":"Stream 0: Generate canonical CC2 board","objective":"Generate the canonical Claw Code 2.0 board from frozen ROADMAP.md, latest issue snapshot, parity evidence, and approved plan. Classify every actionable roadmap item and context heading with source_anchor, source_type, release_bucket, lifecycle status, dependencies, verification_required, and deferral rationale. Emit machine JSON plus human markdown.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T08:14:23.206Z","startedAt":"2026-05-14T07:54:26.032Z","completedAt":"2026-05-14T08:14:23.206Z","evidence":"G001-stream0-board complete via team ultragoal-g001-stream-e61d2271: team status phase=team-verify, tasks 5/5 completed; worker-2 produced issue/parity intake, worker-3 produced board Markdown/rendering, worker-4 recorded validation evidence, worker-1 completed initial board artifacts. Leader reconciliation commit 45b43b5 aligned scripts/generate_cc2_board.py, scripts/validate_cc2_board.py, scripts/cc2_board.py, .omx/cc2/render_board_md.py. Evidence artifacts: .omx/cc2/board.json, .omx/cc2/board.md, .omx/cc2/issue-parity-intake.json, .omx/cc2/issue-parity-intake.md; .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl remain leader-owned. Verification passed: python3 scripts/generate_cc2_board.py; python3 scripts/validate_cc2_board.py; python3 scripts/cc2_board.py validate; python3 .omx/cc2/validate_issue_parity_intake.py; python3 .omx/cc2/render_board_md.py .omx/cc2/board.json .omx/cc2/board.md --check; python3 -m py_compile scripts/generate_cc2_board.py scripts/validate_cc2_board.py scripts/cc2_board.py .omx/cc2/validate_issue_parity_intake.py .omx/cc2/render_board_md.py; cargo check --manifest-path rust/Cargo.toml --workspace."},{"id":"G002-alpha-security","title":"Stream 6: Day-one security and permissions gate","objective":"Implement/verify alpha-blocking security scope: file tools and shell enforce workspace/path scope across direct paths, symlinks, globbing, shell expansion, worktrees, and Windows path cases. Add regression fixtures for #3007 class behavior and permission-mode event/status visibility.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T08:34:04.243Z","startedAt":"2026-05-14T08:14:46.422Z","completedAt":"2026-05-14T08:34:04.243Z","evidence":"G002-alpha-security team ultragoal-g002-alpha-e61d2271 reached phase=complete with 5/5 tasks completed and no worker .omx/ultragoal mutation. Integrated commits through 37b2b75 on main: workspace/path enforcement in rust/crates/runtime/src/file_ops.rs, rust/crates/runtime/src/lib.rs, rust/crates/tools/src/lib.rs, regressions in rust/crates/tools/tests/path_scope_enforcement.rs and rust/crates/rusty-claude-cli/tests/output_format_contract.rs, verification map docs/g002-security-verification-map.md. Fresh leader validation passed: git diff --check; cargo fmt --manifest-path rust/Cargo.toml --all -- --check; cargo test --manifest-path rust/Cargo.toml -p tools path_scope -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p tools --test path_scope_enforcement -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime workspace_ -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --test output_format_contract -- --nocapture; python3 -m pytest tests/test_security_scope.py -q; cargo check --manifest-path rust/Cargo.toml --workspace. .omx/ultragoal artifacts retained as leader-owned durable audit trail; fresh get_goal JSON captured at .omx/ultragoal/get-goal-G002-alpha-security.json. Known unrelated non-gating gaps from worker verification: full cargo test --workspace has pre-existing session_lifecycle_prefers_running_process_over_idle_shell failure; clippy all-targets has pre-existing runtime lint warnings."},{"id":"G003-boot-session","title":"Stream 1: Reliable worker boot/session control","objective":"Implement/verify worker lifecycle, first prompt acceptance SLA, startup-no-evidence classifier, trust resolver/default trusted roots, structured session control API, and boot preflight/doctor JSON contracts.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T08:54:40.729Z","startedAt":"2026-05-14T08:34:19.605Z","completedAt":"2026-05-14T08:54:40.729Z","evidence":"G003-boot-session team g003-boot-session-ult-e61d2271 reached phase=complete with 5/5 tasks completed and no worker .omx/ultragoal mutation. Implemented/verified Stream 1 reliable worker boot/session control: worker lifecycle/prompt SLA and path guardrails, default trusted roots merge via runtime config and WorkerCreate, startup-no-evidence evidence/classifier timestamp coverage, structured boot preflight/status/doctor JSON, and docs/g003-boot-session-verification-map.md. Integrated/pushed through origin/main aec291c. Final leader validation passed: git diff --check; cargo fmt --manifest-path rust/Cargo.toml --all -- --check; cargo test --manifest-path rust/Cargo.toml -p runtime trusted_roots -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime trust_resolver -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime startup -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime worker_boot -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p tools worker_create_merges_config_trusted_roots -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p tools path_scope -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli boot_preflight -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli branch_freshness -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli status_json_surfaces_session_lifecycle_for_clawhip -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --test output_format_contract -- --nocapture; cargo check --manifest-path rust/Cargo.toml --workspace; python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json; python3 .omx/cc2/validate_issue_parity_intake.py .omx/cc2/issue-parity-intake.json. Fresh get_goal JSON captured at .omx/ultragoal/get-goal-G003-boot-session.complete.json and .omx/ultragoal goals/ledger remain leader-owned audit artifacts. Known non-gating gaps from worker clippy attempts are pre-existing unrelated runtime clippy warnings and full workspace tests remain deferred to final gates."},{"id":"G004-events-reports","title":"Stream 2: Event/report contract families","objective":"Implement/verify canonical lane events, ordering/provenance/identity/dedupe/ownership, report schema/projection/redaction/capability negotiation, approval-token chain, and pinpoint closure batches with golden fixtures.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T09:15:44.223Z","startedAt":"2026-05-14T08:54:55.093Z","completedAt":"2026-05-14T09:15:44.223Z","evidence":"G004-events-reports complete: team g004-events-reports-u-e61d2271 phase complete with 7/7 tasks completed; pushed main through 879962b; leader verification passed cargo fmt --manifest-path rust/Cargo.toml --all -- --check, cargo check --manifest-path rust/Cargo.toml -p runtime, cargo test --manifest-path rust/Cargo.toml -p runtime -- --nocapture (535 unit + g004_conformance 2 + integration 12 + doctests), python3 .github/scripts/check_doc_source_of_truth.py; evidence recorded against .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl"},{"id":"G005-branch-recovery","title":"Stream 3: Branch/test awareness and recovery","objective":"Implement/verify stale branch detection before broad tests, recovery recipes and ledger, green-ness contract, test provenance, hung-test classification, and recovery/status reporting.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-14T12:41:48.997Z","startedAt":"2026-05-14T09:16:01.781Z","completedAt":"2026-05-14T12:41:48.997Z","evidence":"G005-branch-recovery complete and pushed at 7426ede; team g005-branch-recovery-e61d2271 has 5/5 tasks completed; leader verification passed for branch freshness before broad tests, recovery ledger/status reporting, green-ness contract/test provenance, stale-base doctor/status consistency, hung-test classification, and docs/g005-branch-recovery-verification-map.md. Evidence recorded against .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl."},{"id":"G006-task-policy-board","title":"Stream 4: Task packets, policy engine, lane board","objective":"Implement/verify typed task packet schema, executable policy engine, active lane board/dashboard, running-state liveness heartbeat, and task/lane status JSON.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T00:42:05.094Z","startedAt":"2026-05-14T12:41:57.815Z","completedAt":"2026-05-15T00:42:05.094Z","evidence":"G006-task-policy-board complete in pushed origin/main commit 65a144c; team g006-task-policy-boar-e61d2271 terminal with 5 completed/0 failed after leader reconciliation; verification map docs/g006-task-policy-board-verification-map.md plus quality gate JSON record cargo fmt/check/tests/diff/push; .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl preserved; workers did not mutate .omx/ultragoal."},{"id":"G007-plugin-mcp","title":"Stream 5: Plugin/MCP lifecycle maturity","objective":"Implement/verify plugin/MCP lifecycle states, healthy/degraded/failed startup, required vs optional behavior, malformed config consistency across status/doctor/mcp/plugins, and mock MCP/plugin tests.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T01:16:43.414Z","startedAt":"2026-05-15T00:42:16.309Z","completedAt":"2026-05-15T01:16:43.414Z","evidence":"G007-plugin-mcp complete: team g007-plugin-mcp-ultra-e61d2271 phase complete with 13/13 tasks completed, verification passed, pushed head 2202410, and durable ultragoal artifacts updated in .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl."},{"id":"G008-provider-compat","title":"Stream 7: Provider/model compatibility","objective":"Implement/verify OpenAI-compatible slash-containing model IDs, provider prefix routing over env sniffing, DeepSeek/reasoning diagnostics, web search/fetch behavior, proxy/custom parameter passthrough, token/cost accounting, and provider diagnostics.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T01:38:22.717Z","startedAt":"2026-05-15T01:17:53.783Z","completedAt":"2026-05-15T01:38:22.717Z","evidence":"G008-provider-compat complete: team g008-provider-compat-e61d2271 phase complete with 5/5 tasks terminal; provider/model compatibility implemented and verified; pushed origin/main 2cac66c..8c9a05e; evidence recorded in .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl plus quality gate .omx/ultragoal/quality-gate-G008-provider-compat.json."},{"id":"G009-windows-docs-release","title":"Stream 8: Windows/install/docs/license readiness","objective":"Implement/verify PowerShell-first docs, safe provider switching examples, Windows smoke CI, release artifact quickstart, license/contribution/security/support policies, and command/link validation.","status":"complete","attempt":0,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T01:57:41.565Z","completedAt":"2026-05-15T01:57:41.565Z","evidence":"G009-windows-docs-release complete at commit 5294648 with team g009-windows-docs-rel-e61d2271 phase complete, 5/5 tasks completed; evidence in .omx/ultragoal/quality-gate-G009-windows-docs-release.json, .omx/ultragoal/get-goal-G009-windows-docs-release.complete.json, .omx/ultragoal/goals.json, and .omx/ultragoal/ledger.jsonl."},{"id":"G010-session-hygiene","title":"Stream 9: Session hygiene/local state/recovery UX","objective":"Implement/verify session file hygiene, .gitignore state paths, per-worktree session isolation, list/delete/exists/compact/resume, compact/provider-context recovery, JSONL payload bloat safeguards, interrupt recovery, and clone disambiguation metadata.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T02:20:46.558Z","startedAt":"2026-05-15T01:59:22.219Z","completedAt":"2026-05-15T02:20:46.558Z","evidence":"G010-session-hygiene complete: team g010-session-hygiene-e61d2271 phase complete with 7/7 tasks completed; final verification passed in .omx/ultragoal/g010-final-quality-gate-rerun.log; durable state recorded in .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl."},{"id":"G011-ecosystem-ops-ux","title":"Streams 10–12: Ecosystem, issue ops, and UX laterals","objective":"Implement/verify gated ACP/Zed/JSON-RPC serve plan/status, anti-slop issue/PR triage, issue templates, navigation/file-context docs, TUI/rendering/copy/paste/clickable path improvements, and defer desktop/marketplace features until contracts are stable.","status":"complete","attempt":1,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T02:55:26.988Z","startedAt":"2026-05-15T02:21:31.360Z","completedAt":"2026-05-15T02:55:26.988Z","evidence":"G011-ecosystem-ops-ux complete: team g011-ecosystem-ops-ux-e61d2271 phase=complete with 7/7 tasks completed; final pushed HEAD 1ac8ce8; verification evidence in .omx/ultragoal/g011-final-quality-gate.log and .omx/ultragoal/quality-gate-G011-ecosystem-ops-ux.json; ultragoal artifacts tracked in .omx/ultragoal/goals.json and .omx/ultragoal/ledger.jsonl."},{"id":"G012-final-gate","title":"Final release gate: Verify Claw Code 2.0 delivery","objective":"Run final cross-stream quality gate: roadmap board has no unmapped actionable items, fmt/clippy/tests and focused contract suites pass, ai-slop-cleaner on changed files passes/no-ops, code-review approves, and final alpha/beta/GA readiness report is written. Final completion is blocked until docs/pr-issue-resolution-gate.md has fresh evidence showing every open PR and issue was triaged, with correct PRs merged and resolvable correct issues fixed or closed.","status":"complete","attempt":0,"createdAt":"2026-05-14T07:54:21.409575Z","updatedAt":"2026-05-15T04:38:54.887Z","evidence":"G012-final-gate complete: team g012-final-gate-ultra-e61d2271 8/8 tasks complete; final gate log /tmp/g012-final-quality-gate-pass4.log; commit 04c2abb pushed; docs/pr-triage-g012-final-gate.json docs/pr-issue-resolution-gate.md docs/g012-final-release-readiness-report.md; .omx/ultragoal/goals.json and ledger.jsonl updated; aiSlopCleaner and codeReview evidence included in quality gate JSON.","completedAt":"2026-05-15T04:38:54.887Z"}],"codexObjective":"Complete the approved Claw Code 2.0 ultragoal delivery: implement all classified ROADMAP.md backlog work through execution-sized stream goals G001-G012, using .omx/ultragoal/ledger.jsonl as the durable audit trail and .omx/plans/claw-code-2-0-adaptive-plan.md as the source plan."},"after":{"id":"G013-implement-roadmap-pinpoints-693-695","title":"Implement ROADMAP pinpoints #693-#695","objective":"Map and implement the newly appended ROADMAP.md pinpoints #693, #694, and #695 after reset to origin/main: typed claw-analog bootstrap phase errors, a local pre-push cargo build gate, and startup/worktree preflight diagnostics; update CC2 board/coverage and verify with targeted and workspace checks.","status":"pending","attempt":0,"createdAt":"2026-05-25T04:18:43.420Z","updatedAt":"2026-05-25T04:18:43.420Z","evidence":"Current-head verification after reset: python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json failed with unmapped ROADMAP headings [7528,7538,7548], corresponding to Pinpoints #693-#695."}} +{"ts":"2026-05-25T04:18:52.711Z","event":"goal_started","goalId":"G013-implement-roadmap-pinpoints-693-695","status":"in_progress","message":"Attempt 1"} diff --git a/docs/g013-roadmap-pinpoints-693-695-verification-map.md b/docs/g013-roadmap-pinpoints-693-695-verification-map.md new file mode 100644 index 00000000..131c57ce --- /dev/null +++ b/docs/g013-roadmap-pinpoints-693-695-verification-map.md @@ -0,0 +1,47 @@ +# G013 ROADMAP pinpoints #693-#695 verification map + +This map records the current-head follow-up that was discovered after resetting +`main` to `origin/main`: ROADMAP.md contained three new Pinpoint headings not +covered by the Claw Code 2.0 board. + +## Pinpoint #693 — typed phase error instead of silent `unknown` + +- Code: `rust/crates/claw-analog/src/lib.rs` +- Behavior: `format_rag_query_json_for_model` now rejects missing, empty, or + literal `"unknown"` phase values with a structured error envelope containing + `kind:"unknown_bootstrap_phase"`, `field:"phase"`, and `received_value`. +- Regression tests: `rag_response_missing_phase_returns_typed_error` and + `rag_response_unknown_phase_returns_typed_error`. + +## Pinpoint #694 — local pre-push build gate + +- Hook: `.github/hooks/pre-push` +- Install command: `git config core.hooksPath .github/hooks` +- Gate: `cargo build --manifest-path rust/Cargo.toml --workspace` +- Purpose: mirror the CI build job locally so stale field/variant references are + caught before push. + +## Pinpoint #695 — startup/worktree preflight diagnostics + +- Code: `rust/crates/runtime/src/worker_boot.rs` +- Behavior: `startup_preflight_warnings` and + `WorkerRegistry::observe_startup_preflight` emit structured warnings before + the first model turn when a task mentions a path not tracked on the current + branch (`file_absent_on_branch`) or git metadata is not writable + (`git_metadata_not_writable`). +- Regression tests: + - `startup_preflight_warns_when_task_file_is_absent_on_branch` + - `startup_preflight_records_structured_warning_event` + +## Verification commands + +```bash +python3 scripts/generate_cc2_board.py +python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json +python3 .omx/cc2/validate_issue_parity_intake.py .omx/cc2/issue-parity-intake.json +bash -n .github/hooks/pre-push +cargo fmt --manifest-path rust/Cargo.toml --all -- --check +cargo test --manifest-path rust/Cargo.toml -p claw-analog rag_response_ -- --nocapture +cargo test --manifest-path rust/Cargo.toml -p runtime startup_preflight -- --nocapture +cargo build --manifest-path rust/Cargo.toml --workspace +``` diff --git a/rust/crates/claw-analog/src/lib.rs b/rust/crates/claw-analog/src/lib.rs index 7d11a834..0ffc33bc 100644 --- a/rust/crates/claw-analog/src/lib.rs +++ b/rust/crates/claw-analog/src/lib.rs @@ -1111,7 +1111,24 @@ enum BlockKind { pub(crate) fn format_rag_query_json_for_model(body: &str) -> Result { let v: Value = serde_json::from_str(body).map_err(|e| format!("invalid JSON: {e}"))?; - let phase = v.get("phase").and_then(|x| x.as_str()).unwrap_or("unknown"); + let phase = v.get("phase").and_then(|x| x.as_str()).ok_or_else(|| { + json!({ + "kind": "unknown_bootstrap_phase", + "field": "phase", + "received_value": v.get("phase").cloned().unwrap_or(Value::Null), + "message": "RAG response is missing a string phase; refusing to silently render phase as unknown" + }) + .to_string() + })?; + if phase.trim().is_empty() || phase == "unknown" { + return Err(json!({ + "kind": "unknown_bootstrap_phase", + "field": "phase", + "received_value": phase, + "message": "RAG response phase must be a concrete phase name" + }) + .to_string()); + } let hits = v .get("hits") .and_then(|h| h.as_array()) @@ -2557,6 +2574,20 @@ mod tests { assert!(out.contains("score=")); } + #[test] + fn rag_response_missing_phase_returns_typed_error() { + let err = format_rag_query_json_for_model(r#"{"hits":[]}"#).unwrap_err(); + assert!(err.contains(r#""kind":"unknown_bootstrap_phase""#)); + assert!(err.contains(r#""field":"phase""#)); + } + + #[test] + fn rag_response_unknown_phase_returns_typed_error() { + let err = format_rag_query_json_for_model(r#"{"hits":[],"phase":"unknown"}"#).unwrap_err(); + assert!(err.contains(r#""kind":"unknown_bootstrap_phase""#)); + assert!(err.contains(r#""received_value":"unknown""#)); + } + #[test] fn resolve_rag_base_url_toml_beats_env() { let _g = mock_env_lock(); diff --git a/rust/crates/runtime/src/trust_resolver.rs b/rust/crates/runtime/src/trust_resolver.rs index d320f87a..cb6ce965 100644 --- a/rust/crates/runtime/src/trust_resolver.rs +++ b/rust/crates/runtime/src/trust_resolver.rs @@ -438,13 +438,24 @@ fn normalize_path(path: &Path) -> PathBuf { /// Extract repository name from a path for event context. fn extract_repo_name(cwd: &str) -> Option { let path = Path::new(cwd); - // Try to find a .git directory to identify repo root - let mut current = Some(path); - while let Some(p) = current { - if p.join(".git").is_dir() { - return p.file_name().map(|n| n.to_string_lossy().to_string()); + // Ask git from the cwd itself. Walking ancestors manually can accidentally + // classify synthetic/nonexistent paths as an unrelated parent repo (for + // example `/tmp/.git`), which makes trust events point at the wrong repo. + if path.is_dir() { + if let Ok(output) = std::process::Command::new("git") + .args(["rev-parse", "--show-toplevel"]) + .current_dir(path) + .output() + { + if output.status.success() { + let root = String::from_utf8_lossy(&output.stdout).trim().to_string(); + if !root.is_empty() { + return Path::new(&root) + .file_name() + .map(|n| n.to_string_lossy().to_string()); + } + } } - current = p.parent(); } // Fallback: use the last component of the path path.file_name().map(|n| n.to_string_lossy().to_string()) diff --git a/rust/crates/runtime/src/worker_boot.rs b/rust/crates/runtime/src/worker_boot.rs index 7bdb3c1d..0cbe2ce0 100644 --- a/rust/crates/runtime/src/worker_boot.rs +++ b/rust/crates/runtime/src/worker_boot.rs @@ -13,6 +13,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; +use std::process::Command; use std::sync::{Arc, Mutex}; use std::time::{SystemTime, UNIX_EPOCH}; @@ -73,6 +74,7 @@ pub struct WorkerFailure { #[serde(rename_all = "snake_case")] pub enum WorkerEventKind { Spawning, + StartupPreflightWarning, TrustRequired, ToolPermissionRequired, TrustResolved, @@ -102,6 +104,21 @@ pub enum WorkerPromptTarget { Unknown, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum WorkerStartupPreflightWarningKind { + FileAbsentOnBranch, + GitMetadataNotWritable, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct WorkerStartupPreflightWarning { + pub kind: WorkerStartupPreflightWarningKind, + pub message: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub path: Option, +} + /// Classification of startup failure when no evidence is available. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] @@ -212,6 +229,12 @@ pub enum WorkerEventPayload { evidence: StartupEvidenceBundle, classification: StartupFailureClassification, }, + StartupPreflightWarning { + kind: WorkerStartupPreflightWarningKind, + message: String, + #[serde(skip_serializing_if = "Option::is_none")] + path: Option, + }, } #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] @@ -329,6 +352,34 @@ impl WorkerRegistry { inner.workers.get(worker_id).cloned() } + pub fn observe_startup_preflight( + &self, + worker_id: &str, + task_prompt: &str, + ) -> Result { + let mut inner = self.inner.lock().expect("worker registry lock poisoned"); + let worker = inner + .workers + .get_mut(worker_id) + .ok_or_else(|| format!("worker not found: {worker_id}"))?; + + for warning in startup_preflight_warnings(Path::new(&worker.cwd), task_prompt) { + push_event( + worker, + WorkerEventKind::StartupPreflightWarning, + worker.status, + Some(warning.message.clone()), + Some(WorkerEventPayload::StartupPreflightWarning { + kind: warning.kind, + message: warning.message, + path: warning.path, + }), + ); + } + + Ok(worker.clone()) + } + pub fn observe(&self, worker_id: &str, screen_text: &str) -> Result { let mut inner = self.inner.lock().expect("worker registry lock poisoned"); let worker = inner @@ -1064,6 +1115,118 @@ fn extract_server_from_qualified_tool(tool: &str) -> Option { (!server.is_empty()).then(|| server.to_string()) } +pub fn startup_preflight_warnings( + cwd: &Path, + task_prompt: &str, +) -> Vec { + let mut warnings = Vec::new(); + + if let Some(git_path) = git_metadata_path(cwd) { + if !path_is_writable(&git_path) { + warnings.push(WorkerStartupPreflightWarning { + kind: WorkerStartupPreflightWarningKind::GitMetadataNotWritable, + message: format!( + "git metadata is not writable; commits or pushes may fail: {}", + git_path.display() + ), + path: Some(git_path.display().to_string()), + }); + } + } + + for path in mentioned_repo_paths(task_prompt) { + if !git_tracks_path(cwd, &path) { + warnings.push(WorkerStartupPreflightWarning { + kind: WorkerStartupPreflightWarningKind::FileAbsentOnBranch, + message: format!( + "task mentions {path}, but git does not track it on the current branch" + ), + path: Some(path), + }); + } + } + + warnings +} + +fn mentioned_repo_paths(task_prompt: &str) -> Vec { + let mut out = Vec::new(); + for raw in task_prompt.split_whitespace() { + let token = raw.trim_matches(|ch: char| { + matches!( + ch, + '`' | '"' | '\'' | '(' | ')' | '[' | ']' | '{' | '}' | ',' | ';' | ':' + ) + }); + if !token.contains('/') || token.contains("://") || token.starts_with('/') { + continue; + } + let token = token.trim_start_matches("./"); + if token.contains("..") { + continue; + } + if token + .chars() + .all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '/' | '_' | '-' | '.')) + && token + .rsplit('/') + .next() + .is_some_and(|name| name.contains('.')) + && !out.iter().any(|seen| seen == token) + { + out.push(token.to_string()); + } + } + out +} + +fn git_tracks_path(cwd: &Path, path: &str) -> bool { + Command::new("git") + .arg("ls-files") + .arg("--error-unmatch") + .arg("--") + .arg(path) + .current_dir(cwd) + .output() + .is_ok_and(|output| output.status.success()) +} + +fn git_metadata_path(cwd: &Path) -> Option { + let output = Command::new("git") + .args(["rev-parse", "--git-path", "."]) + .current_dir(cwd) + .output() + .ok()?; + if !output.status.success() { + return None; + } + let text = String::from_utf8_lossy(&output.stdout).trim().to_string(); + if text.is_empty() { + return None; + } + let path = PathBuf::from(text); + Some(if path.is_absolute() { + path + } else { + cwd.join(path) + }) +} + +fn path_is_writable(path: &Path) -> bool { + let probe_dir = if path.is_dir() { + path.to_path_buf() + } else { + path.parent().unwrap_or(path).to_path_buf() + }; + let probe = probe_dir.join(format!(".claw-write-probe-{}", now_secs())); + std::fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&probe) + .and_then(|_| std::fs::remove_file(&probe)) + .is_ok() +} + fn detect_trust_prompt(lowered: &str) -> bool { [ "do you trust the files in this folder", @@ -1285,6 +1448,8 @@ fn cwd_matches_observed_target(expected_cwd: &str, observed_cwd: &str) -> bool { #[cfg(test)] mod tests { use super::*; + use std::fs; + use std::process::Command; #[test] fn allowlisted_trust_prompt_auto_resolves_then_reaches_ready_state() { @@ -1431,6 +1596,66 @@ mod tests { assert!(!readiness.ready); } + #[test] + fn startup_preflight_warns_when_task_file_is_absent_on_branch() { + let tmp = tempfile::tempdir().expect("tempdir"); + Command::new("git") + .arg("init") + .current_dir(tmp.path()) + .output() + .expect("git init should run"); + fs::create_dir_all(tmp.path().join("src")).expect("src dir"); + fs::write(tmp.path().join("src/lib.rs"), "pub fn present() {}\n").expect("write file"); + Command::new("git") + .args(["add", "src/lib.rs"]) + .current_dir(tmp.path()) + .output() + .expect("git add should run"); + + let warnings = startup_preflight_warnings( + tmp.path(), + "Fix src/lib.rs and rust/crates/runtime/src/trident.rs before testing.", + ); + + assert!(warnings.iter().any(|warning| { + warning.kind == WorkerStartupPreflightWarningKind::FileAbsentOnBranch + && warning.path.as_deref() == Some("rust/crates/runtime/src/trident.rs") + })); + assert!(!warnings.iter().any(|warning| { + warning.kind == WorkerStartupPreflightWarningKind::FileAbsentOnBranch + && warning.path.as_deref() == Some("src/lib.rs") + })); + } + + #[test] + fn startup_preflight_records_structured_warning_event() { + let tmp = tempfile::tempdir().expect("tempdir"); + Command::new("git") + .arg("init") + .current_dir(tmp.path()) + .output() + .expect("git init should run"); + let registry = WorkerRegistry::new(); + let worker = registry.create(&tmp.path().display().to_string(), &[], true); + + let observed = registry + .observe_startup_preflight(&worker.worker_id, "Open missing/file.rs") + .expect("preflight should run"); + + let event = observed + .events + .iter() + .find(|event| event.kind == WorkerEventKind::StartupPreflightWarning) + .expect("preflight warning event"); + assert!(matches!( + event.payload, + Some(WorkerEventPayload::StartupPreflightWarning { + kind: WorkerStartupPreflightWarningKind::FileAbsentOnBranch, + .. + }) + )); + } + #[test] fn startup_timeout_classifies_tool_permission_prompt() { let registry = WorkerRegistry::new();