/find-workflow-duplication
You are the orchestrator for a product-topology SUSPECT skill. Detect
when the same workflow step knowledge is repeated across layers instead
of owned by a registry.
How success is judged
report.md and findings.json agree on finding count and bucket
counts, and the closeout pastes the real detect.py and report.py
output lines (wrote ...) as artifact truth.
- Findings are promoted only when at least two active executable owner
layers can drift; docs, tests, route definitions, and unloaded legacy
files are context unless paired with active executable repeats.
- Every finding names the proposed canonical owner: workflow registry
for labels/tab IDs, or route helper/router for route literals. A
repeated string without an owner
decision is evidence, not a finding.
- The run is read-only: it writes only under
reports/workflow-duplication/<scan-id>/.
Scope
- Workflow is host-authored — read from
.engineering/docs/product-workflows.md. With no descriptor the scan
finds nothing (the toolkit assumes no product flow).
- Scans the host's declared
## Text-file globs; templates declared
under ## UI template globs split loaded JS from legacy/unloaded.
- Output:
reports/workflow-duplication/<scan-id>/.
- No code edits.
- Python:
python3 (stdlib-only scripts).
Pipeline
SCAN_ID="scan-$(date -u +%Y%m%d-%H%M%S)"
REPORT_DIR="reports/workflow-duplication/$SCAN_ID"
mkdir -p "$REPORT_DIR"
python3 .claude/skills/find-workflow-duplication/scripts/detect.py \
--project-root "$(pwd)" \
--min-active-owners 2 \
--output "$REPORT_DIR/detections.jsonl"
python3 .claude/skills/find-workflow-duplication/scripts/report.py \
--detections "$REPORT_DIR/detections.jsonl" \
--output-md "$REPORT_DIR/report.md" \
--output-json "$REPORT_DIR/findings.json" \
--scan-id "$SCAN_ID" \
--target "product workflow" \
--project-root "$(pwd)"
The skill default is --min-active-owners 2; pass it explicitly. The
script's compatibility default is 0 and is too permissive for this skill
because it can surface docs/legacy repeats without active executable
drift. Leave --min-owners at its script default of 3 unless the user
asks for a broader diagnostic pass.
After the commands finish, paste the detect.py and report.py stdout
lines into the report or closeout. Do not claim findings from memory;
read findings.json for counts and report.md for the rows the user
will see.
Findings
duplicated_workflow_label: step label repeated across owner layers.
duplicated_workflow_tab_id: tab key repeated across owner layers.
duplicated_route_literal: route literal repeated across owner
layers.
duplicated_workflow_knowledge: fallback for any future
descriptor-driven value kind; treat it as evidence until the owner is
explicit.
Every finding includes surface classification:
active_executable: current templates, loaded JS, views, or services
that can change runtime behavior.
legacy_unloaded: JS or templates in the workflow file family that
are not loaded by current site-config templates.
route_definition: URLconf definitions. These can stay literal when
route names and consumers are registry-owned.
docs / tests: reference material and regression coverage.
Triage Rules
- Lexical repeats are evidence, not findings. A label, tab id, route
prefix, or endpoint suffix appearing in docs/tests does not matter by
itself.
- Start from active executable repeats. Treat legacy/unloaded files,
docs/tests, and route definitions as context unless they are paired
with two or more active executable owners that can drift.
- Use a two-pass migration lens for route-literal cleanup: first migrate
consumers loaded by current templates, then sweep the remaining
workflow-family static files. Dormant prototype JS should be deleted
when it has no unique knowledge; otherwise quarantine it with an
explicit reason instead of keeping silent compatibility debt.
- Promote to a finding only when multiple executable layers can change
behavior independently: navigation, page tabs, status providers,
route/URL generation, endpoint construction, feature visibility, or
boot payload shape.
- Every finding must name the proposed canonical owner — the workflow
registry for duplicated labels/tab IDs, or the route helper/router for
duplicated route literals.
- Do not fold a distinct sub-workflow's rules into the primary
workflow's findings unless the user explicitly scopes that work in.
Decision fork: when a duplicate value appears in active code plus docs or
tests, promote it only if the active code spans at least two owner
layers. When it appears in one active owner plus any amount of
docs/tests/route definitions/legacy unloaded files, report it as context
or ignore it; do not hand it to /fix-workflow.
Next Skills
- Use
/extract-workflow-registry to propose the explicit owner.
- Use
/fix-workflow only after tests pin the current labels, tabs,
redirects, and page rendering.
When things go sideways
| Symptom |
Action |
.engineering/docs/product-workflows.md is absent |
Report "descriptor absent; 0 findings expected" and stop. Do not infer another project's workflow |
Descriptor exists but ## Text-file globs is empty or matches no files |
Report the empty scan surface and ask the host to declare text-file globs before treating 0 findings as health |
detect.py writes 0 findings |
Read the descriptor and command output. If active owners are below 2, this is a clean result; if no files were scanned, it is a descriptor/setup issue |
| Findings are only docs/tests/route definitions/legacy unloaded files |
Do not promote them to cleanup. Keep them as context or follow-up unless two active executable owners also drift |
report.py cannot write or findings.json is missing |
Stop and report the exact failure. Do not summarize from detections.jsonl as though the final artifact exists |
scripts/log_effectiveness.py fails during report.py |
report.py uses check=False; the audit artifacts still count if report.md and findings.json were written. State that effectiveness logging failed or was not confirmed |
Replay case
For future repairs, replay with a temporary project that declares one
workflow step in .engineering/docs/product-workflows.md, includes the
step label in one template and one service file listed under
## Text-file globs, then runs the two documented commands. Expected
evidence: detect.py writes at least one JSONL record only when active
owners meet the explicit threshold, and report.py writes both
report.md and findings.json.
1---2name: find-workflow-duplication3description: Detect duplicated product-step authority for the host-declared workflow labels, tab IDs, and route literals listed in `.engineering/docs/product-workflows.md`. The deterministic scanner reads the descriptor's `## Text-file globs`, classifies active executable owners versus docs/tests/routes/legacy surfaces, and reports repeated values that can drift across backend, templates, loaded JS, and docs. Detection-only; never edits production code.4---56# /find-workflow-duplication78You are the orchestrator for a product-topology SUSPECT skill. Detect9when the same workflow step knowledge is repeated across layers instead10of owned by a registry.1112## How success is judged1314- `report.md` and `findings.json` agree on finding count and bucket15 counts, and the closeout pastes the real `detect.py` and `report.py`16 output lines (`wrote ...`) as artifact truth.17- Findings are promoted only when at least two active executable owner18 layers can drift; docs, tests, route definitions, and unloaded legacy19 files are context unless paired with active executable repeats.20- Every finding names the proposed canonical owner: workflow registry21 for labels/tab IDs, or route helper/router for route literals. A22 repeated string without an owner23 decision is evidence, not a finding.24- The run is read-only: it writes only under25 `reports/workflow-duplication/<scan-id>/`.2627## Scope2829- Workflow is host-authored — read from30 `.engineering/docs/product-workflows.md`. With no descriptor the scan31 finds nothing (the toolkit assumes no product flow).32- Scans the host's declared `## Text-file globs`; templates declared33 under `## UI template globs` split loaded JS from legacy/unloaded.34- Output: `reports/workflow-duplication/<scan-id>/`.35- No code edits.36- Python: `python3` (stdlib-only scripts).3738## Pipeline3940```bash41SCAN_ID="scan-$(date -u +%Y%m%d-%H%M%S)"42REPORT_DIR="reports/workflow-duplication/$SCAN_ID"43mkdir -p "$REPORT_DIR"44python3 .claude/skills/find-workflow-duplication/scripts/detect.py \45 --project-root "$(pwd)" \46 --min-active-owners 2 \47 --output "$REPORT_DIR/detections.jsonl"48python3 .claude/skills/find-workflow-duplication/scripts/report.py \49 --detections "$REPORT_DIR/detections.jsonl" \50 --output-md "$REPORT_DIR/report.md" \51 --output-json "$REPORT_DIR/findings.json" \52 --scan-id "$SCAN_ID" \53 --target "product workflow" \54 --project-root "$(pwd)"55```5657The skill default is `--min-active-owners 2`; pass it explicitly. The58script's compatibility default is 0 and is too permissive for this skill59because it can surface docs/legacy repeats without active executable60drift. Leave `--min-owners` at its script default of 3 unless the user61asks for a broader diagnostic pass.6263After the commands finish, paste the `detect.py` and `report.py` stdout64lines into the report or closeout. Do not claim findings from memory;65read `findings.json` for counts and `report.md` for the rows the user66will see.6768## Findings6970- `duplicated_workflow_label`: step label repeated across owner layers.71- `duplicated_workflow_tab_id`: tab key repeated across owner layers.72- `duplicated_route_literal`: route literal repeated across owner73 layers.74- `duplicated_workflow_knowledge`: fallback for any future75 descriptor-driven value kind; treat it as evidence until the owner is76 explicit.7778Every finding includes surface classification:7980- `active_executable`: current templates, loaded JS, views, or services81 that can change runtime behavior.82- `legacy_unloaded`: JS or templates in the workflow file family that83 are not loaded by current site-config templates.84- `route_definition`: URLconf definitions. These can stay literal when85 route names and consumers are registry-owned.86- `docs` / `tests`: reference material and regression coverage.8788## Triage Rules8990- Lexical repeats are evidence, not findings. A label, tab id, route91 prefix, or endpoint suffix appearing in docs/tests does not matter by92 itself.93- Start from active executable repeats. Treat legacy/unloaded files,94 docs/tests, and route definitions as context unless they are paired95 with two or more active executable owners that can drift.96- Use a two-pass migration lens for route-literal cleanup: first migrate97 consumers loaded by current templates, then sweep the remaining98 workflow-family static files. Dormant prototype JS should be deleted99 when it has no unique knowledge; otherwise quarantine it with an100 explicit reason instead of keeping silent compatibility debt.101- Promote to a finding only when multiple executable layers can change102 behavior independently: navigation, page tabs, status providers,103 route/URL generation, endpoint construction, feature visibility, or104 boot payload shape.105- Every finding must name the proposed canonical owner — the workflow106 registry for duplicated labels/tab IDs, or the route helper/router for107 duplicated route literals.108- Do not fold a distinct sub-workflow's rules into the primary109 workflow's findings unless the user explicitly scopes that work in.110111Decision fork: when a duplicate value appears in active code plus docs or112tests, promote it only if the active code spans at least two owner113layers. When it appears in one active owner plus any amount of114docs/tests/route definitions/legacy unloaded files, report it as context115or ignore it; do not hand it to `/fix-workflow`.116117## Next Skills118119- Use `/extract-workflow-registry` to propose the explicit owner.120- Use `/fix-workflow` only after tests pin the current labels, tabs,121 redirects, and page rendering.122123## When things go sideways124125| Symptom | Action |126|---|---|127| `.engineering/docs/product-workflows.md` is absent | Report "descriptor absent; 0 findings expected" and stop. Do not infer another project's workflow |128| Descriptor exists but `## Text-file globs` is empty or matches no files | Report the empty scan surface and ask the host to declare text-file globs before treating 0 findings as health |129| `detect.py` writes 0 findings | Read the descriptor and command output. If active owners are below 2, this is a clean result; if no files were scanned, it is a descriptor/setup issue |130| Findings are only docs/tests/route definitions/legacy unloaded files | Do not promote them to cleanup. Keep them as context or follow-up unless two active executable owners also drift |131| `report.py` cannot write or `findings.json` is missing | Stop and report the exact failure. Do not summarize from `detections.jsonl` as though the final artifact exists |132| `scripts/log_effectiveness.py` fails during `report.py` | `report.py` uses `check=False`; the audit artifacts still count if `report.md` and `findings.json` were written. State that effectiveness logging failed or was not confirmed |133134## Replay case135136For future repairs, replay with a temporary project that declares one137workflow step in `.engineering/docs/product-workflows.md`, includes the138step label in one template and one service file listed under139`## Text-file globs`, then runs the two documented commands. Expected140evidence: `detect.py` writes at least one JSONL record only when active141owners meet the explicit threshold, and `report.py` writes both142`report.md` and `findings.json`.