| name | tool-fit-validation |
| description | Pre-Stage-4 specialist that validates a tool build before code is written. Produces a one-page Tool Validation Report covering demand floor, data moat, usefulness, prototype spec, kill conditions, and effort sanity-check. Used exclusively by Stage 3 Update Decision when a brief is routed to create-new with tag interactive_tool. |
| metadata | {"family":"ops","owner":"seo","last_reviewed":"2026-05-01T00:00:00.000Z","version":"1.0.0","related_skills":["tool-fit","opportunity-discovery","content-refresh","tool-page-builder","seo-foundations"],"kpis":["Tool builds reaching Stage 4 with passing validation report ≥90%","Stage 4 effort overrun on tool builds <20% vs sub-type baseline","Tool freshness SLA registered for 100% of approved tools"],"marketing_pillar":4,"seo_standard":"B_C","kpi_tier":14,"funnel_stage":"mofu_bofu","content_class":"transactional","maturity_stage":"prescriptive","used_by_stages":[3]} |
Tool-Fit Validation
The cheapest way to keep velocity on tool bets is to kill bad tools before Stage 4 starts coding. With AI-agent generation, the implementation cost has collapsed (3-8h reviewer + integration time depending on sub-type), but the real costs are still real: reviewer attention (capped at 4 YMYL tools/month), topical-authority dilution per cluster, and exposure surface for trust + maintenance.
This specialist runs only when Stage 3 Update Decision routes a brief to create-new with the interactive_tool tag.
When to Use
- Stage 3 Update Decision — invoked once per brief with
route: create-new and 90_10_class: interactive_tool.
Do Not Use When
- Brief routed to
refresh-existing — ops/content-refresh owns that path.
- Brief routed to
extend-template AND the existing template already passes its quality gates — extension reuses prior validation; only re-validate if the extension changes the data moat or YMYL surface.
- Article opportunities — they have no tool surface.
Inputs
- Approved Strategic Brief from Stage 2 (with
tool_fit block populated by seo/tool-fit).
- Existing tool registry:
nextjs-app/src/features/tools/shared/data/tool-registry/data.ts.
- Existing tool routes under
nextjs-app/src/app/(career-hub)/tools/.
- Latest seo-foundations/reference/pseo-quality-gates.md for demand floor.
- Latest BLS / IRS / state data sources required for the tool's logic (cite, do not embed).
Output Artifact
One-page Tool Validation Report at nextjs-app/docs/reports/<date>/03-tool-validation-<slug>.md.
brief_id: <slug>-<date>
verdict: ship | hold | kill
reasons: [<reason-id list>]
# Schwartz Three Rules
schwartz_rule_1_data_moat: pass | fail
schwartz_rule_1_evidence: <text>
schwartz_rule_2_usefulness: pass | fail
schwartz_rule_2_user_job: <one-sentence user job>
schwartz_rule_3_demand: pass | fail
schwartz_rule_3_volume: <monthly searches head + cluster total>
# Reuse check
existing_registry_match: false | <existing-tool-slug>
recommended_route_change: none | extend-template | use-existing
# Prototype spec (one page)
inputs:
- { name, type, range, default }
logic_summary: <text — formula or decision tree in plain English>
output_shape: <text — what the user sees>
success_metric: <Tier 2 or Tier 4 metric the tool must move>
# Effort sanity-check (reviewer + integration hours, not coding hours)
recommended_subtype: calculator | decision_tool | generator
effort_baseline_hours: 8 | 6 | 3
estimated_effort_hours: <number>
overrun_risk: low | medium | high
overrun_drivers: [<text>]
# YMYL + maintenance + freshness moat
ymyl_pillar_3: true | false
reviewer_credentialed: true | false | n/a
ymyl_throughput_remaining_this_month: <0-4> # from reviewer-throughput cap
data_source_watcher_subscribed: true | false
authoritative_sources: [<source-id list, per tool-cluster-map>]
freshness_sla_after_release: <hours or days>
freshness_banner_committed: true | false
tool_cluster_id: pay-and-tax | cost-and-tradeoffs | career-and-skills | shift-and-schedule | application-and-communication
cluster_uniqueness_ratio_post_ship: <0.0-1.0> # must remain ≥0.40 (≥0.50 for cluster 5)
# Kill list re-check
kill_conditions_triggered: [<K1..K9 list>] | []
override_paths: [<text>]
Tools Allowed
- File system + grep / Glob (registry + corpus inspection)
- Web search (data source freshness verification)
user-semrush (cached only — confirmation of head-term volume and SERP shape)
plugin-slack-slack (only if verdict: kill and human override is requested)
Context Loaded (≤6 skills, ~22K tokens)
seo/tool-fit — the lens skill that produced the upstream tags
seo/seo-foundations — Schwartz Three Rules, pSEO gates, YMYL standard, tool-cluster map
code/tool-page-builder — registry + ToolPageShell pattern (referenced for reuse check, not for code)
ops/content-refresh — reactive freshness counterpart
ops/data-source-watcher — proactive update-velocity moat; required subscription before approving
marketing/marketing-foundations — measurement framework + reviewer-throughput cap + content-class balance
NOT loaded: frontend-design, tailwind-design-system, webapp-testing, gsc-mcp raw queries (Stage 1+2 already provided), full vendored skills.
Workflow
For each brief flagged interactive_tool + create-new:
1. Schwartz Three Rules
- Rule 1 — Data moat (proprietary content): cite the data source layered with Indeed Flex platform data. If pure-public, fail unless the override path in K2 of tool-fit/reference/kill-list.md applies.
- Rule 2 — Usefulness (do something useful): write the user job in one sentence. If you can't, fail.
- Rule 3 — Validated demand: check the head-term monthly search volume against the per-subtype floor in tool-fit/reference/kill-list.md K1.
If any rule fails → verdict: kill, return to Discovery backlog with reason.
2. Existing-Registry Reuse Check
Grep src/features/tools/shared/data/tool-registry/data.ts and existing tool routes for:
- Same primary formula or decision logic
- Same input shape (≥70% input overlap)
- Same target persona + intent
If a match is found:
- Recommend Stage 3 re-route to
extend-template instead of create-new.
- Effort estimate drops to
new_generator_or_template_extension: 15h baseline.
- Update the registry entry; do not create a new route unless the extension's URL is a clearly distinct query target.
3. One-Page Prototype Spec
Write the prototype in plain text — no code, no Figma:
- Inputs: 3-8 fields max. Each with type (number / enum / text), valid range, default.
- Logic: the formula or decision tree in plain English. If it requires more than 5 lines, the tool is too complex — re-scope or split.
- Output: what the user sees on submit. Specify shape (single number, comparison table, ranked list, generated text block).
- Success metric: which Tier 2 or Tier 4 metric the tool must move (e.g., "tool-completion event ≥40% of sessions" or "app-store CTR from this route ≥2%"). This is what
monthly-attribution-review verifies at 30/60/90d.
4. Effort Sanity-Check
Pull the recommended sub-type from the brief's tool_fit.subtype field. Compare against:
If estimated > baseline × 1.3 → overrun_risk: high. Common drivers:
- Edge cases in tax / pay calculations across states (calculators)
- Decision-tree branches with bespoke content per leaf (decision tools)
- Per-role content variants (generators)
- YMYL review cycles
If overrun risk is high without explicit mitigation → verdict: hold, return brief to Stage 2 for re-scoping.
5. YMYL + Maintenance + Freshness Moat Gate
This is the most important step in validation under the AI-agent generation model. Three sub-checks:
- YMYL reviewer: if Pillar 3 (financial) → credentialed reviewer (CPA / EA) required. Confirm reviewer name + credential before
verdict: ship. Without one, the tool damages entire pillar's E-E-A-T per Standard B.
- Reviewer throughput cap: confirm the YMYL reviewer monthly cap (default 4) has remaining slots this month. If full →
verdict: hold and queue for next month. The cap protects the pillar; missing it for a single tool is preferable to overloading the reviewer and shipping unreviewed work.
- Freshness moat: every approved tool that depends on changing authoritative data must commit to all three:
freshnessSla field in tool-registry/data.ts with explicit cadence + owner
- Subscription registered with ops/data-source-watcher for the upstream authoritative sources
- User-visible freshness banner component placement on the tool page
Without all three, K6 fires and verdict: hold until secured. The freshness moat is the update-velocity pillar of the moat scorecard — it's not an optional add-on; it's the load-bearing pillar for tools that depend on changing data.
6. Tool-Cluster Placement
Per seo-foundations/reference/tool-cluster-map.md:
- Assign the tool to one of the five clusters.
- Confirm post-ship cluster uniqueness ratio remains ≥40% (≥50% for application-and-communication cluster).
- Verify the tool fills a documented cluster gap, or justify why it's a net-new entry not in the gap list.
- Plan in-cluster cross-links and methodology-page contribution.
If cluster uniqueness ratio would drop below floor → verdict: hold and re-route to refresh / extension of an existing cluster member.
7. Re-Check Kill List
Re-run all K1-K9 conditions from tool-fit/reference/kill-list.md with the prototype spec in hand. New information from the prototype (input count, logic complexity, data dependencies) often surfaces kill conditions that were unclear at Discovery.
8. Verdict
ship — proceed to Stage 4 with prototype spec attached.
hold — return brief to Stage 2 with specific re-scope ask (overrun risk, missing reviewer, kill condition with override path).
kill — return to Discovery backlog with reason; the topic may still be valid as an article tag.
Memory Layer Update
Append to nextjs-app/docs/reports/_index.json:
{
"agent": "tool-fit-validation",
"stage": 3,
"run_at": "<ISO-8601>",
"inputs_hash": "<sha256 of brief>",
"outputs_path": "nextjs-app/docs/reports/<date>/03-tool-validation-<slug>.md",
"confidence": 0.9,
"human_decision_if_gated": null,
"verdict": "ship | hold | kill",
"tool_subtype": "calculator | decision_tool | generator",
"estimated_effort_hours": "<number>",
"ymyl": "true | false"
}
Failure Modes
- Data source unavailable: BLS or IRS data source missing for required computation →
verdict: hold, request data sourcing as a separate Discovery opportunity.
- Reviewer not yet credentialed: YMYL tool blocked →
verdict: hold until reviewer is identified. Do not ship YMYL tools without reviewer; this hurts entire pillar's E-E-A-T.
- Cannibalization re-detected: K7 fires after prototype spec reveals same query target as an existing winning page → re-route to
extend-template (embed tool inside the article).
- Bundle budget violation: prototype spec implies >120KB JS bundle →
verdict: hold, request scope split.
Anti-Patterns
- ❌ Treating validation as a rubber stamp. The kill list re-check after the prototype spec is the most valuable step — it catches issues Discovery couldn't see.
- ❌ Validating an extension as if it were a net-new tool (skip the demand-floor and data-moat steps for confirmed extensions; reuse the parent tool's evidence).
- ❌ Approving without a freshness owner. Tools without owners rot silently.
- ❌ Approving with reviewer name TBD. The credential is the gate; defer the build until secured.
References