Files
claw/docs/superpowers/plans/2026-04-10-fault-details-full-skill-alignment-plan.md
木炎 311cc1fee6 docs: add fault-details alignment design and plan
Capture the approved fault-details staged-skill design and implementation plan so the remaining work can be resumed from the documented contract.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 18:10:02 +08:00

30 KiB
Raw Permalink Blame History

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 packages 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:

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:

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:

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:

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:

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 packages 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:

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:

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:

#[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:

#[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:

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:

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<String, PipeError> 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:

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:

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:

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:

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

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

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

cargo test --test browser_script_skill_tool_test -- --nocapture

Expected: current browser-script execution semantics remain intact while returning structured artifact payloads.

Compatibility/build

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.