Skip to content

feat(topology): recover complexity per sub-package with per-child engine routing#123

Merged
maudlin merged 1 commit into
mainfrom
78-perpackage-complexity
Jun 25, 2026
Merged

feat(topology): recover complexity per sub-package with per-child engine routing#123
maudlin merged 1 commit into
mainfrom
78-perpackage-complexity

Conversation

@maudlin

@maudlin maudlin commented Jun 25, 2026

Copy link
Copy Markdown
Owner

What

The last whole-tree measurement arm. On an undeclared fan-out, complexity ran once over the whole tree, routed by whole-tree engine selection. This recovers it per assessment root, with the full engine ladder re-routed per child (route_complexity_child, a scoped mirror of the whole-tree routing):

  • ESLint on the JS/TS slice, using the child's own flat config + local bin;
  • lizard on the non-JS slice (inventory sliced to the subtree via inventory_paths_under);
  • scc fallback (keep-set sliced via scc_keep_for_root).

Findings are namespaced (backend/complexity) and labelled per package (πŸ“¦ Sub-package: …).

git-hotspots CSV stays whole-tree. The single complexity-full.csv is accumulated across packages β€” truncated once before the loop, appended per arm, always in TARGET-relative (namespaced) paths (scc/lizard/eslint findings re-prefixed; the standalone-lizard CSV's file column namespaced via awk) β€” so the churn Γ— complexity join keeps working. If nothing is measured, the empty CSV is dropped to match the pre-#78 absent state exactly.

One honest note: a fan-out child lacking its own eslint flat config reports its JS/TS complexity as unmeasured (rather than borrowing a root config) β€” strictly more honest than today's single-engine-for-the-whole-fanout behaviour.

Why this is safe

Single package / declared workspace β†’ one iteration at . reusing the whole-tree routing, no cd, SLUG_NS empty, $PWD == $TARGET, ns="" β†’ byte-identical to before (the gate).

Verification

  • Full CI suite green locally (12 suites).
  • Byte-identical on single-package fixtures across all three arms β€” lizard (Go), scc (Classic-ASP-only), merged (node/TS) β€” diffing the complexity record, complexity-full.csv, and console; plus a full parsed-set diff (all records identical bar the CHECKUP_OUT_DIR path in one git-hotspots message). The empty-vs-absent CSV edge is normalised so even the filesystem matches.
  • Fan-out smoke: a Go-dominant child and a Python-dominant child (both node packages) each route to lizard per child β†’ proc/complexity + svc/complexity records, and complexity-full.csv accumulates namespaced rows (proc/job.py, svc/server.go).

Completes #78

With stats (#121), duplication (#122) and now complexity, every measurement arm recovers per sub-package. The eslint/lizard/scc arms, the duplication engines, and the scc-based stats all honour the detected topology.

Closes #78

πŸ€– Generated with Claude Code

…ine routing (#78)

The last whole-tree measurement arm. On an undeclared fan-out, complexity ran
once over the whole tree, routed by whole-tree engine selection. Recover it per
assessment root with the FULL engine ladder re-routed per child
(route_complexity_child, a scoped mirror of the whole-tree routing): ESLint on
the JS/TS slice using the child's OWN flat config + local bin, lizard on the
non-JS slice (inventory sliced to the subtree), scc fallback (keep-set sliced).
Findings are namespaced (backend/complexity) and labelled per package.

The single git-hotspots CSV is accumulated across packages β€” truncated once
before the loop, appended per arm, always in TARGET-relative (namespaced) paths
(scc/lizard/eslint findings re-prefixed; the standalone-lizard CSV's file column
namespaced via awk) β€” so the churn Γ— complexity join stays whole-tree. If nothing
is measured the (empty) CSV is dropped, matching the pre-#78 absent state.

Single package / declared workspace β†’ one iteration at "." reusing the whole-tree
routing, no cd, SLUG_NS empty, $PWD == $TARGET β†’ byte-identical to before, CSV
included (verified end-to-end on the lizard, scc and merged arms + full
parsed-set diff). A fan-out routes each child to its own engine and accumulates a
namespaced CSV.

With stats (#121), duplication (#122) and now complexity, every measurement arm
recovers per sub-package β€” #78 is complete.

Closes #78

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012oHR4g8pH7Ui242SRycFzw
@maudlin maudlin merged commit 984fd53 into main Jun 25, 2026
6 checks passed
@maudlin maudlin deleted the 78-perpackage-complexity branch June 25, 2026 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scan root/scope is a hypothesis: detect topology, judge it, recover (assess where first-party code actually lives)

1 participant