Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Regulator-grade feature attribution for any LSTM/Transformer signal — single-entry PageRank ranks the top-K features that drove the prediction (ADR-126 Phase 6, ADR-123 single-entry PR)
.claude/skills/ruvnet-trader-explain/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 28% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 68% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 155% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 62% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 66% | 0% |
Explain a trading signal by building a feature-contribution graph and running single-entry forward-push PageRank from the signal output node. Top-K ranked features are returned as a markdown table AND persisted to trading-analysis as a SignedAttributionArtifact (ADR-126 Phase 6).
Why this skill matters:
mcp__ruflo-sublinear__page-rank-entry once that tool is registered in the runtime — until then, the local power-iteration kernel ships in signed-attribution.mjs and produces the same ordering (seeded mulberry32).Steps:
trading-signals namespace (ADR-126 Phase 1 + Phase 2 lifecycle):text mcp__plugin_ruflo-core_ruflo__memory_retrieve({ key: "SIGNAL_ID", namespace: "trading-signals" }) The signal entry includes modelId, prediction, and the feature vector at the time of inference.
bash npx neural-trader --predict --signal "$SIGNAL_ID" --explain --json The expected output shape: ts { features: Array<{ name: string; contribution: number }>; // for Transformers, also includes per-head attention co-occurrence: attention?: Array<{ head: string; cooccur: Array<[number, number, number]> }>; }
Fallback path — if --explain is not shipped on the installed neural-trader build (older versions; the flag was scoped for a follow-up upstream PR), the skill degrades to a deterministic feature-importance heuristic over the signal's input vector: contribution_i = |input_i - μ_i| / σ_i (z-score magnitude). This is a known proxy — not as faithful as attention/SHAP — and the resulting artifact is tagged attribution_method: "input-zscore-fallback" so downstream consumers can filter it out for regulator filings. Document the fallback path in the resulting markdown summary so the agent surfaces it to the user.
__signal_output__ for the prediction.__signal_output__ to each feature node, weighted by contribution_i. When attention co-occurrence data is available, also add edges between feature nodes weighted by cooccur — this is what makes the PageRank single-entry rather than degenerating to plain top-K.__signal_output__ (index 0 by convention so the smoke can assert reproducibility).mcp__ruflo-sublinear__page-rank-entry is registered:text mcp__ruflo-sublinear__page-rank-entry({ nodes: GRAPH_NODES, edges: GRAPH_EDGES, sourceIndex: 0, damping: 0.85, maxIterations: 100, tolerance: 1e-8, seed: 42 }) The local fallback (localSingleEntryPageRank in plugins/ruflo-neural-trader/src/signed-attribution.mjs) runs ~30 LOC of seeded power-iteration when the MCP tool is not available — same math, same result up to floating-point tolerance, same ordering for the same seed (the Phase 6 smoke asserts this).
AttributionFeature[] via topKFeatures(graph, scores, k=10, excludeIndex=0) — excludes the source node from the ranked output. Ties broken by node index (lower index wins) so the ranking is deterministic.SignedAttributionArtifact body:ts { signalId: SIGNAL_ID, modelId: SIGNAL.modelId, features: TOP_K_FEATURES, // from step 5 graphMetadata: { nodeCount: GRAPH.nodes.length, edgeCount: COUNT_EDGES, pageRankIterations: PR_RESULT.iterations, seed: SEED // load-bearing for reproducibility }, generatedAt: NEW_DATE_ISO }
RUFLO_WITNESS_KEY_PATH env var — JSON file with { "privateKey": "<hex>" }.verification/witness-key.json (the ADR-103 default path).signAttributionArtifact(body, privateKeyHex) from plugins/ruflo-neural-trader/src/signed-attribution.mjs."[WARN] ruflo-neural-trader: no witness signing key found — storing attribution artifact in UNSIGNED degraded mode. Regulator filings will reject UNSIGNED artifacts." and store the body unsigned. NEVER silently fall back.trading-analysis namespace (ADR-126 Phase 1):text mcp__plugin_ruflo-core_ruflo__memory_store({ key: "attribution-SIGNAL_ID-TIMESTAMP", namespace: "trading-analysis", value: JSON.stringify(signedArtifact) }) The trading-analysis namespace is the canonical home for model-analysis output (regime classifications, technical-indicator summaries, model-training results — and now attribution rankings). Long-lived — no TTL — because the audit trail is the deliverable.
## Feature attribution for signal SIGNAL_ID (model: MODEL_ID)
| Rank | Feature | Score | |------|---------|-------| | 1 | NAME | 0.42 | | 2 | NAME | 0.18 | | … | … | … |
Downstream consumers verify the artifact before any regulator-facing report or paper→live promotion:
tsimport { verifyAttributionArtifact } from 'plugins/ruflo-neural-trader/src/signed-attribution.mjs'; const ok = await verifyAttributionArtifact(artifact, trustedPublicKey); if (!ok) { // [ERROR] attribution verification failed — refuse to publish. // Pin to trustedPublicKey from project config; do NOT trust the // artifact.witnessPublicKey field (CWE-347 / #1922 — attacker-controllable). return; }
Acceptance criteria (ADR-126 Phase 6):
trader-explain <signalId> returns a ranked feature list whose top-3 features overlap the model's attention argmax (when --explain available; documented tolerance).signalId + same --seed produce byte-identical rank ordering (asserted by scripts/smoke-neural-trader-feature-attribution.mjs).graphMetadata.seed invalidates the signature.--explain flag missing, z-score heuristic runs and the artifact is tagged.Refs:
plugins/ruflo-neural-trader/src/signed-attribution.ts (the typed contract)plugins/ruflo-neural-trader/src/signed-attribution.mjs (the runtime mirror)scripts/smoke-neural-trader-feature-attribution.mjs (the regression smoke)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-06 | pass→pass | 9,447 | 6,818 | -28% | 1 | 1 | 0% | 1,772 | 3,232 | +82% | 0 | 0 | — |
case-01 | fail→fail | 14,565 | 5,016 | -66% | 1 | 1 | 0% | 2,763 | 2,396 | -13% | 0 | 0 | — |
case-02 | fail→fail | 14,231 | 5,243 | -63% | 1 | 1 | 0% | 2,702 | 2,420 | -10% | 0 | 0 | — |
case-03 | fail→fail | 11,311 | 4,664 | -59% | 1 | 1 | 0% | 2,309 | 2,414 | +5% | 0 | 0 | — |
case-04 | fail→pass | 26,870 | 6,070 | -77% | 1 | 1 | 0% | 2,543 | 3,245 | +28% | 0 | 0 | — |
case-05 | fail→pass | 9,731 | 3,823 | -61% | 1 | 1 | 0% | 1,649 | 2,765 | +68% | 0 | 0 | — |
case-07 | fail→pass | 5,980 | 3,780 | -37% | 1 | 1 | 0% | 1,080 | 2,750 | +155% | 0 | 0 | — |
case-08 | fail→pass | 9,950 | 5,077 | -49% | 1 | 1 | 0% | 1,897 | 3,067 | +62% | 0 | 0 | — |
case-09 | fail→pass | 9,646 | 4,484 | -54% | 1 | 1 | 0% | 1,816 | 3,015 | +66% | 0 | 0 | — |
case-10 | fail→pass | 17,023 | 5,058 | -70% | 1 | 1 | 0% | 808 | 3,100 | +284% | 0 | 0 | — |
case-11 | pass→pass | 6,263 | 4,130 | -34% | 1 | 1 | 0% | 1,134 | 2,783 | +145% | 0 | 0 | — |
case-12 | fail→pass | 9,405 | 3,475 | -63% | 1 | 1 | 0% | 1,571 | 2,732 | +74% | 0 | 0 | — |
case-13 | pass→pass | 13,157 | 9,687 | -26% | 1 | 1 | 0% | 2,479 | 3,920 | +58% | 0 | 0 | — |
case-14 | fail→pass | 8,635 | 4,641 | -46% | 1 | 1 | 0% | 1,594 | 2,859 | +79% | 0 | 0 | — |
case-15 | fail→pass | 8,264 | 2,874 | -65% | 1 | 1 | 0% | 1,405 | 2,537 | +81% | 0 | 0 | — |
case-16 | fail→pass | 26,337 | 6,658 | -75% | 1 | 1 | 0% | 1,300 | 3,385 | +160% | 0 | 0 | — |
case-17 | pass→pass | 8,820 | 2,298 | -74% | 1 | 1 | 0% | 1,492 | 2,420 | +62% | 0 | 0 | — |
case-18 | fail→pass | 4,692 | 3,628 | -23% | 1 | 1 | 0% | 805 | 2,704 | +236% | 0 | 0 | — |
case-19 | fail→pass | 9,948 | 4,367 | -56% | 1 | 1 | 0% | 1,729 | 2,371 | +37% | 0 | 0 | — |
case-20 | pass→pass | 3,043 | 10,751 | +253% | 1 | 1 | 0% | 478 | 4,085 | +755% | 0 | 0 | — |
case-21 | pass→fail | 11,955 | 14,810 | +24% | 1 | 1 | 0% | 2,593 | 5,102 | +97% | 0 | 0 | — |
case-22 | fail→fail | 12,510 | 21,658 | +73% | 1 | 1 | 0% | 2,490 | 6,270 | +152% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 17 counted toward the lift figure. The other 5 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +50 percentage points is the difference between those two pass rates over the 17 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.