# Fault Details Full Skill Alignment Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Upgrade `fault-details-report.collect_fault_details` into a real staged browser skill that matches the original fault-details workflow, and make `claw-new` interpret the returned artifact status correctly in the direct-submit path. **Architecture:** Keep routing and direct-skill selection in `claw-new`, but move all fault-details collection, normalization, classification, summary, export, and report-log behavior into the staged skill under `skill_staging`. Implement the staged skill as a true browser-eval entrypoint that remains valid in page context, while exposing testable pure helpers through an environment-safe export guard for `node:test`; then add a narrow Rust artifact interpreter in `src/compat/direct_skill_runtime.rs` so `ok` / `partial` / `empty` map to successful task completion while `blocked` / `error` map to failed completion. **Tech Stack:** Rust 2021, `serde_json`, existing `BrowserPipeTool` / `browser_script` runtime, `node:test`, staged skill fixtures, Cargo integration tests. --- ## Execution Context - Follow @superpowers:test-driven-development for every behavior change. - Follow @superpowers:verification-before-completion before claiming each task is done. - Do **not** create a git worktree unless the user explicitly asks. This repo preference is already established. - Keep scope tight. Do **not** add a new browser protocol, new dispatch metadata, new UI opener behavior, or Rust-side fault classification logic. - Keep the current direct path bootstrap requirement intact: the user instruction must still include an explicit `YYYY-MM`, but the staged skill must treat the page-selected range as the source of truth for collection once execution begins. - Preserve parity with the original package’s real behavior: port the original classification table, `qxxcjl`-based reason heuristics, canonical detail mapping, summary aggregation rules, localhost export call, and report-log call into the staged skill rather than implementing a fixture-only subset. ## File Map ### Existing files to modify in `claw-new` - Modify: `src/compat/direct_skill_runtime.rs` - add narrow structured artifact parsing and status-to-summary mapping - keep direct-skill routing/config ownership unchanged - Modify: `tests/agent_runtime_test.rs` - add direct-submit regressions for `ok`, `partial`, `empty`, `blocked`, and `error` - Modify: `tests/browser_script_skill_tool_test.rs` - add browser-script execution-shape regression for browser-eval return payloads used by fault-details ### Existing files to modify in `skill_staging` - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.js` - replace empty shell with browser-eval entrypoint plus parity helpers - Create: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js` - deterministic fixture coverage for normalization, classification, summary, artifact contract, export/logging degradation, and entrypoint shape helpers - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/SKILL.toml` - align tool description with real collection/export/report-log behavior - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/SKILL.md` - align written contract with actual runtime behavior and artifact fields - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/references/collection-flow.md` - align flow with page-range/query/export/report-log sequence - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/references/data-quality.md` - make canonical columns, original classification tables, reason heuristics, summary rules, and partial semantics explicit - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/scenes/fault-details-report/scene.json` - keep scene output/state contract aligned with real staged artifact behavior ### Existing files to read but not redesign - Read only: `docs/superpowers/specs/2026-04-10-fault-details-full-skill-alignment-design.md` - Read only: `src/agent/mod.rs` - Read only: `src/compat/browser_script_skill_tool.rs` - Read only: `D:/desk/智能体资料/大四区报告监测项/故障明细/index.html` --- ### Task 1: Add staged-skill red tests for normalization, summary, and artifact-contract semantics **Files:** - Create: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js` - Read only: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.js` - Read only: `D:/desk/智能体资料/大四区报告监测项/故障明细/index.html` - [ ] **Step 1: Write the failing staged-skill test file** Add `collect_fault_details.test.js` using `node:test` and `assert/strict`. Cover these behaviors with fixed fixtures: ```javascript const test = require('node:test'); const assert = require('node:assert/strict'); const { DETAIL_COLUMNS, SUMMARY_COLUMNS, normalizeDetailRow, deriveSummaryRows, determineArtifactStatus, buildFaultDetailsArtifact, buildBrowserEntrypointResult } = require('./collect_fault_details.js'); test('normalizeDetailRow maps canonical detail fields from raw repair rows', () => { const row = normalizeDetailRow({ qxdbh: 'QX-1', bxsj: '2026-03-09 08:00:00', cityName: '国网兰州供电公司', maintOrgName: '城关供电服务班', maintGroupName: '抢修一班', bdzMc: '110kV东岗变', xlmc10: '10kV东岗线', byqmc: '东岗1号变', yjflMc: '电网故障', ejflMc: '线路故障', sjflMc: '低压线路', qxxcjl: '现场检查:低压线路断线,已处理完成', gzms: '客户报修停电' }, { companyName: '国网兰州供电公司' }); assert.equal(row.slsj, '2026-03-09 08:00:00'); assert.equal(row.gssgs, '甘肃省电力公司'); assert.equal(row.gddw, '城关供电服务班'); assert.equal(row.gds, '抢修一班'); assert.equal(row.clzt, '处理完成'); assert.equal(row.bdz, '110kV东岗变'); assert.equal(row.line, '10kV东岗线'); assert.equal(row.pb, '东岗1号变'); }); test('deriveSummaryRows groups normalized rows by gds and computes counters', () => { const rows = [ { gds: '抢修一班', gddw: '城关供电服务班', sgs: '国网兰州供电公司', sxfl1: '无效', sxfl2: '无效', gzsb: '' }, { gds: '抢修一班', gddw: '城关供电服务班', sgs: '国网兰州供电公司', sxfl1: '有效', sxfl2: '用户侧', gzsb: '表后线' }, { gds: '抢修一班', gddw: '城关供电服务班', sgs: '国网兰州供电公司', sxfl1: '有效', sxfl2: '电网侧', dwcFl: '低压故障', gzsb: '低压线路' } ]; const summaryRows = deriveSummaryRows(rows, { companyName: '国网兰州供电公司' }); assert.equal(summaryRows.length, 1); assert.equal(summaryRows[0].className, '抢修一班'); assert.equal(summaryRows[0].allCount, 3); assert.equal(summaryRows[0].wxCount, 1); assert.equal(summaryRows[0].khcCount, 0); assert.equal(summaryRows[0].dyGzCount, 1); assert.equal(summaryRows[0].dyxlCount, 1); assert.equal(summaryRows[0].bhxCount, 1); }); test('determineArtifactStatus follows blocked > error > partial > empty > ok precedence', () => { assert.equal(determineArtifactStatus({ blockedReason: 'missing_session', fatalError: null, partialReasons: [], detailRows: [{}] }), 'blocked'); assert.equal(determineArtifactStatus({ blockedReason: null, fatalError: 'parse_failed', partialReasons: [], detailRows: [{}] }), 'error'); assert.equal(determineArtifactStatus({ blockedReason: null, fatalError: null, partialReasons: ['export_failed'], detailRows: [{}] }), 'partial'); assert.equal(determineArtifactStatus({ blockedReason: null, fatalError: null, partialReasons: [], detailRows: [] }), 'empty'); assert.equal(determineArtifactStatus({ blockedReason: null, fatalError: null, partialReasons: [], detailRows: [{}] }), 'ok'); }); test('buildFaultDetailsArtifact keeps canonical fields, selected range, counts, and downstream results', () => { const artifact = buildFaultDetailsArtifact({ period: '2026-03', selectedRange: { start: '2026-03-08 16:00:00', end: '2026-03-09 16:00:00' }, detailRows: [{ qxdbh: 'QX-1' }], summaryRows: [{ index: 1 }], partialReasons: ['report_log_failed'], downstream: { export: { attempted: true, success: true, path: 'http://localhost/export.xlsx' }, report_log: { attempted: true, success: false, error: '500' } } }); assert.equal(artifact.type, 'report-artifact'); assert.equal(artifact.status, 'partial'); assert.deepEqual(artifact.selected_range, { start: '2026-03-08 16:00:00', end: '2026-03-09 16:00:00' }); assert.equal(artifact.counts.detail_rows, 1); assert.equal(artifact.counts.summary_rows, 1); assert.deepEqual(artifact.partial_reasons, ['report_log_failed']); }); test('buildFaultDetailsArtifact keeps required top-level fields for blocked artifact', () => { const artifact = buildFaultDetailsArtifact({ period: '2026-03', blockedReason: 'selected_range_unavailable', partialReasons: ['selected_range_unavailable'] }); assert.equal(artifact.type, 'report-artifact'); assert.equal(artifact.report_name, 'fault-details-report'); assert.equal(artifact.period, '2026-03'); assert.equal(artifact.status, 'blocked'); assert.deepEqual(artifact.partial_reasons, ['selected_range_unavailable']); assert.equal('downstream' in artifact, false); }); test('buildFaultDetailsArtifact keeps known selected range and counts on late error', () => { const artifact = buildFaultDetailsArtifact({ period: '2026-03', selectedRange: { start: '2026-03-08 16:00:00', end: '2026-03-09 16:00:00' }, detailRows: [], summaryRows: [], fatalError: 'summary_failed', partialReasons: ['summary_failed'] }); assert.equal(artifact.status, 'error'); assert.deepEqual(artifact.selected_range, { start: '2026-03-08 16:00:00', end: '2026-03-09 16:00:00' }); assert.equal(artifact.counts.detail_rows, 0); assert.equal(artifact.counts.summary_rows, 0); }); test('buildBrowserEntrypointResult returns blocked artifact when selected range is unavailable', async () => { const artifact = await buildBrowserEntrypointResult({ period: '2026-03' }, { readSelectedRange: async () => null }); assert.equal(artifact.status, 'blocked'); assert.ok(artifact.partial_reasons.includes('selected_range_unavailable')); }); ``` - [ ] **Step 2: Run the staged-skill test file and verify it fails** Run: ```bash node "D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js" ``` Expected: FAIL because `collect_fault_details.js` does not export these helpers yet and still only returns an empty shell. --- ### Task 2: Implement staged-skill parity helpers and a valid browser entrypoint **Files:** - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.js` - Test: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js` - [ ] **Step 1: Implement the helper exports and browser entrypoint shape needed to satisfy the red tests** Refactor `collect_fault_details.js` so the file remains a valid browser-eval script in page context while still supporting `node:test` through an environment-safe export guard. Required implementation pieces: ```javascript const DETAIL_COLUMNS = [/* existing canonical columns */]; const SUMMARY_COLUMNS = [/* existing summary columns */]; function normalizeDetailRow(raw, context) { // map qxdbh/gssgs/sgs/gddw/gds/slsj/clzt/bdz/line/pb // derive sxfl1/sxfl2/sxfl3/gzsb/gzyy from the original package rules } function deriveSummaryRows(detailRows, context) { // group by gds and compute all original package counters } function determineArtifactStatus({ blockedReason, fatalError, partialReasons, detailRows }) { // blocked > error > partial > empty > ok } function buildFaultDetailsArtifact({ period, selectedRange, detailRows, summaryRows, partialReasons, blockedReason, fatalError, downstream }) { // return report-artifact with columns, sections, counts, status, partial_reasons, downstream } async function buildBrowserEntrypointResult(input, deps = defaultBrowserDeps()) { // read selected range from page // collect raw rows from page query // normalize rows // derive summary // attempt export + report log // return final artifact } if (typeof module !== 'undefined' && module.exports) { module.exports = { DETAIL_COLUMNS, SUMMARY_COLUMNS, normalizeDetailRow, deriveSummaryRows, determineArtifactStatus, buildFaultDetailsArtifact, buildBrowserEntrypointResult }; } return await buildBrowserEntrypointResult(args); ``` Rules: - keep `DETAIL_COLUMNS` and `SUMMARY_COLUMNS` canonical and stable - keep helper functions self-contained in this file unless a separate pure helper file becomes necessary for runtime validity - keep the browser entrypoint compatible with current `eval` wrapper - keep browser runtime free of unguarded Node-only assumptions - do **not** invent a new protocol or callback surface - [ ] **Step 2: Re-run the staged-skill test file and verify it now reaches deeper failures or passes the initial helper coverage** Run: ```bash node "D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js" ``` Expected: either PASS for the Task 1 cases, or fail only on the still-missing full parity/export/history specifics added in Task 3. --- ### Task 3: Add red tests for full classification parity, downstream partials, and empty-result export semantics **Files:** - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js` - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.js` - Read only: `D:/desk/智能体资料/大四区报告监测项/故障明细/index.html` - [ ] **Step 1: Extend the staged-skill tests with failing parity and downstream cases** Add focused failing tests such as: ```javascript test('normalizeDetailRow derives gzyy from qxxcjl text heuristics', () => { const row = normalizeDetailRow({ qxxcjl: '现场检查:客户表后线烧损,已恢复送电', ejflMc: '客户侧故障', sjflMc: '表后线' }, { companyName: '国网兰州供电公司' }); assert.equal(row.gzsb, '表后线'); assert.equal(row.gzyy, '表后线烧损'); }); test('buildBrowserEntrypointResult returns partial when export fails after detail collection succeeds', async () => { const artifact = await buildBrowserEntrypointResult({ period: '2026-03' }, { readSelectedRange: async () => ({ start: '2026-03-08 16:00:00', end: '2026-03-09 16:00:00' }), queryFaultRows: async () => [{ qxdbh: 'QX-1', bxsj: '2026-03-09 08:00:00', maintGroupName: '抢修一班' }], readCompanyContext: () => ({ companyName: '国网兰州供电公司' }), exportWorkbook: async () => { throw new Error('export_failed'); }, writeReportLog: async () => ({ success: true }) }); assert.equal(artifact.status, 'partial'); assert.ok(artifact.partial_reasons.includes('export_failed')); assert.equal(artifact.counts.detail_rows, 1); assert.equal(artifact.downstream.export.attempted, true); assert.equal(artifact.downstream.export.success, false); }); test('buildBrowserEntrypointResult returns error when normalized detail rows cannot be produced', async () => { const artifact = await buildBrowserEntrypointResult({ period: '2026-03' }, { readSelectedRange: async () => ({ start: '2026-03-08 16:00:00', end: '2026-03-09 16:00:00' }), queryFaultRows: async () => [{ qxdbh: '', bxsj: '' }], readCompanyContext: () => ({ companyName: '国网兰州供电公司' }) }); assert.equal(artifact.status, 'error'); assert.ok(artifact.partial_reasons.includes('detail_normalization_failed')); }); test('buildBrowserEntrypointResult keeps canonical rows empty for empty result and omits downstream before attempts', async () => { const artifact = await buildBrowserEntrypointResult({ period: '2026-03' }, { readSelectedRange: async () => ({ start: '2026-03-08 16:00:00', end: '2026-03-09 16:00:00' }), queryFaultRows: async () => [], readCompanyContext: () => ({ companyName: '国网兰州供电公司' }) }); assert.equal(artifact.status, 'empty'); assert.deepEqual(artifact.rows, []); assert.equal('downstream' in artifact, false); }); ``` Also add fixture cases derived from the original package’s full classification table and summary counters so the staged skill is forced toward parity, not a subset implementation. - [ ] **Step 2: Run the staged-skill test file and verify it fails on the new cases** Run: ```bash node "D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js" ``` Expected: FAIL on missing full classification parity or downstream partial/error behavior. - [ ] **Step 3: Implement the full business logic needed to satisfy the new tests** In `collect_fault_details.js`: - port the original classification table and `qxxcjl` text heuristics for `sxfl1`, `sxfl2`, `sxfl3`, `gzsb`, `gzyy` - port the original summary derivation rules and counters completely - add required-field validation so structurally unusable normalized rows escalate to `error` - add downstream `exportWorkbook` and `writeReportLog` stages that record `{attempted, success, path, error}` - keep collection success distinct from downstream failures so export/logging failures become `partial`, not full failure - keep placeholder rows, if needed for downstream empty-export payloads, downstream-only and never in canonical returned `rows` - include both `period` and `selected_range` in the artifact - omit `downstream` when export/report-log have not been attempted yet - [ ] **Step 4: Re-run the staged-skill test file and verify it passes** Run: ```bash node "D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js" ``` Expected: PASS. --- ### Task 4: Align staged-skill metadata and reference docs with the implemented behavior **Files:** - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/SKILL.toml` - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/SKILL.md` - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/references/collection-flow.md` - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/references/data-quality.md` - Modify: `D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/scenes/fault-details-report/scene.json` - [ ] **Step 1: Update the staged metadata/docs to match the implemented runtime contract** Required changes: - `SKILL.toml`: description must say the tool collects rows, derives summary, attempts localhost export, and records report history - `SKILL.md`: artifact example must include `selected_range`, `counts`, `status`, `partial_reasons`, and `downstream` - `references/collection-flow.md`: sequence must explicitly include page-selected range -> raw query -> normalization -> summary -> export -> report-log - `references/data-quality.md`: document the original classification tables, `qxxcjl` heuristics, summary rules, partial/error escalation rules, and empty-result semantics explicitly enough to match the implemented helpers - `scene.json`: keep inputs/outputs/status semantics aligned with the richer artifact; do not add routing policy there - [ ] **Step 2: Read the updated staged docs and verify they match the implemented JS behavior** Read and confirm: - descriptions no longer claim “artifact shell” behavior - docs do not move routing ownership out of `claw-new` - docs do not promise auto-opening/downloading behavior in this slice - docs reflect blocked/error field-presence rules and downstream-attempt semantics Expected: staged metadata/docs accurately reflect the implemented collector. --- ### Task 5: Add Rust red tests for artifact-status interpretation in the direct-submit runtime **Files:** - Modify: `tests/agent_runtime_test.rs` - Modify: `tests/browser_script_skill_tool_test.rs` - Modify: `src/compat/direct_skill_runtime.rs` - Read only: `src/compat/browser_script_skill_tool.rs` - [ ] **Step 1: Add failing direct-submit runtime tests for structured artifact statuses** Extend `tests/agent_runtime_test.rs` with focused regressions that use the existing temp skill-root harness but return real `report-artifact` payloads: ```rust #[test] fn submit_task_treats_partial_report_artifact_as_success_with_warning_summary() { let skill_root = build_direct_runtime_skill_root(); let runtime_context = direct_submit_runtime_context(&skill_root); let transport = Arc::new(MockTransport::new(vec![success_browser_response( 1, serde_json::json!({ "text": { "type": "report-artifact", "report_name": "fault-details-report", "period": "2026-03", "selected_range": { "start": "2026-03-08 16:00:00", "end": "2026-03-09 16:00:00" }, "columns": ["qxdbh"], "rows": [{ "qxdbh": "QX-1" }], "sections": [{ "name": "summary-sheet", "columns": ["index"], "rows": [{ "index": 1 }] }], "counts": { "detail_rows": 1, "summary_rows": 1 }, "status": "partial", "partial_reasons": ["report_log_failed"], "downstream": { "export": { "attempted": true, "success": true, "path": "http://localhost/export.xlsx" }, "report_log": { "attempted": true, "success": false, "error": "500" } } } }), )])); // ... invoke handle_browser_message_with_context(...) // assert TaskComplete.success == true // assert summary contains partial/report_log_failed/detail_rows=1 } #[test] fn submit_task_treats_empty_report_artifact_as_success() { /* status=empty => success=true */ } #[test] fn submit_task_treats_blocked_report_artifact_as_failure() { /* status=blocked => success=false */ } #[test] fn submit_task_treats_error_report_artifact_as_failure() { /* status=error => success=false */ } ``` Also add one focused helper regression to `tests/browser_script_skill_tool_test.rs` that proves the browser-script helper can return a structured object payload used by the fault-details path without flattening required fields away. Suggested test name: ```rust #[tokio::test] async fn execute_browser_script_tool_preserves_structured_report_artifact_payload() { /* ... */ } ``` - [ ] **Step 2: Run the focused Rust tests and verify they fail** Run: ```bash cargo test --test agent_runtime_test submit_task_treats_partial_report_artifact_as_success_with_warning_summary -- --nocapture cargo test --test browser_script_skill_tool_test execute_browser_script_tool_preserves_structured_report_artifact_payload -- --nocapture ``` Expected: the new `agent_runtime_test` case fails because `execute_direct_submit_skill` still returns raw JSON text and `src/agent/mod.rs` still marks all direct-submit results as success when no Rust-side interpretation exists. --- ### Task 6: Implement narrow Rust artifact interpretation without moving business rules into Rust **Files:** - Modify: `src/compat/direct_skill_runtime.rs` - Modify: `tests/agent_runtime_test.rs` - Modify: `tests/browser_script_skill_tool_test.rs` - [ ] **Step 1: Implement a narrow structured-artifact interpreter in `src/compat/direct_skill_runtime.rs`** Add a small internal result type and parser, for example: ```rust struct DirectSubmitOutcome { success: bool, summary: String, } fn interpret_direct_submit_output(output: &str) -> DirectSubmitOutcome { // parse JSON if possible // if type == "report-artifact", read status/counts/partial_reasons/downstream // map ok/partial/empty => success=true // map blocked/error => success=false // build concise summary with report_name, period, detail_rows, summary_rows, status, partial reasons // fall back to raw output text when payload is not a recognized artifact } ``` Then change the public entrypoint shape from `Result` to a narrow result carrying `success` and `summary`, or add a second helper that `src/agent/mod.rs` can use without changing routing ownership. Rules: - do **not** reimplement fault normalization/classification/summary in Rust - do **not** add fault-specific branching in `src/agent/mod.rs` - keep unrecognized non-artifact outputs working as before - keep explicit `YYYY-MM` derivation and configured `skill.tool` resolution unchanged - [ ] **Step 2: Update the submit-path caller to use the interpreted success flag** Adjust the direct-submit branch so `TaskComplete.success` comes from the artifact interpretation instead of blindly treating every `Ok(summary)` as success. Implementation target: - keep the direct path in `src/agent/mod.rs` - keep error handling narrow - if needed, return a dedicated direct-submit outcome from `execute_direct_submit_skill` - [ ] **Step 3: Re-run the focused Rust tests and verify they pass** Run: ```bash cargo test --test agent_runtime_test submit_task_treats_partial_report_artifact_as_success_with_warning_summary -- --nocapture cargo test --test agent_runtime_test submit_task_treats_empty_report_artifact_as_success -- --nocapture cargo test --test agent_runtime_test submit_task_treats_blocked_report_artifact_as_failure -- --nocapture cargo test --test agent_runtime_test submit_task_treats_error_report_artifact_as_failure -- --nocapture cargo test --test browser_script_skill_tool_test execute_browser_script_tool_preserves_structured_report_artifact_payload -- --nocapture ``` Expected: PASS. --- ### Task 7: Run the full verification sweep for the staged skill and direct runtime **Files:** - Verify only - [ ] **Step 1: Run the staged-skill deterministic test file** Run: ```bash node "D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js" ``` Expected: PASS. - [ ] **Step 2: Run the relevant Rust regression suites** Run: ```bash cargo test --test browser_script_skill_tool_test -- --nocapture cargo test --test agent_runtime_test -- --nocapture ``` Expected: PASS. - [ ] **Step 3: Run the broader compatibility coverage and build** Run: ```bash cargo test --test compat_runtime_test -- --nocapture cargo test --test compat_config_test -- --nocapture cargo build --bin sgclaw ``` Expected: PASS. - [ ] **Step 4: Manually verify the requirements against the approved spec** Checklist: - staged skill now reads page-selected range instead of inventing a month window after entry - staged skill returns canonical detail rows and summary rows - staged skill ports the original classification table, `qxxcjl` heuristics, and summary counters with parity coverage - staged skill records downstream export/report-log outcome - staged skill distinguishes `ok` / `partial` / `empty` / `blocked` / `error` - `blocked` / `error` artifacts keep the required top-level fields, and preserve known `selected_range` / `counts` when failure happens late enough - `downstream` is omitted when export/report-log were not attempted and included with attempted/success flags once they were attempted - empty-result canonical `rows` stay empty even if downstream export uses a placeholder transport row - `claw-new` maps `ok` / `partial` / `empty` to success and `blocked` / `error` to failure - no new routing metadata was added to `SKILL.toml` or `scene.json` - no new browser protocol or opener/UI behavior was introduced Expected: all checklist items satisfied before calling the work complete. --- ## Verification Checklist ### Staged skill behavior ```bash node "D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills/fault-details-report/scripts/collect_fault_details.test.js" ``` Expected: deterministic fixture coverage passes for normalization, full classification parity, summary derivation, artifact shape, empty semantics, and downstream partial semantics. ### Direct-submit runtime mapping ```bash cargo test --test agent_runtime_test -- --nocapture ``` Expected: - valid artifact `ok` / `partial` / `empty` completes successfully - valid artifact `blocked` / `error` completes as failure - existing invalid config regression still passes - existing direct-submit happy path still passes ### Browser-script helper safety ```bash cargo test --test browser_script_skill_tool_test -- --nocapture ``` Expected: current browser-script execution semantics remain intact while returning structured artifact payloads. ### Compatibility/build ```bash cargo test --test compat_runtime_test -- --nocapture cargo test --test compat_config_test -- --nocapture cargo build --bin sgclaw ``` Expected: no regressions in compat execution/config loading; main binary builds cleanly. --- ## Notes For The Engineer - The paired spec is `docs/superpowers/specs/2026-04-10-fault-details-full-skill-alignment-design.md`. - Keep all fault business transforms in `skill_staging`, not in Rust. - Keep direct routing config-owned via `skillsDir` + `directSubmitSkill`. - Do **not** broaden this slice into LLM routing, generic dispatch policy, new browser opcodes, or export auto-open behavior. - If the original package reveals extra classification rules that are needed for parity, add them only inside `collect_fault_details.js` and its staged references/tests, not in `claw-new`.