Skip to content

decompose: cut-score + app-facts fix (split from #293, 1/6) - #341

Merged
MendixMau merged 3 commits into
masterfrom
split-293/cut-score
Oct 15, 2026
Merged

MendixMau merged 3 commits into
masterfrom
split-293/cut-score

Conversation

@MendixMau

@MendixMau MendixMau commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Split from #293 (1/6). #293's branch is untouched; files were copied from its head with git checkout origin/claude/youthful-hypatia-qapq73 -- <paths> and adapted to current master.

Direct lane

What changed and why (one paragraph):
bin/cut-score.sh scores a proposed split of an existing app into several apps. You pass --cut "A,B|C|D", or it uses the default of one app per level of app-layer-map.json. It lists every module edge in analysis/app-facts/dependencies.json that crosses an app boundary and names the integration lane each ref kind would need: OData external entity, published action or REST, copy, deep-link, or none. It then gives each partition a clean / costly / blocked verdict and prints the denominator. Aggregates over a foreign entity are read from .mxcli/catalog.db. When that can't be done, rows read NOT DETECTED and name the actual reason: no catalog, empty table, missing columns, or unreadable. The fixture is tests/wave2/test-cut-score.sh plus the captured tests/wave2/fixtures/cut-score/. The project-bin/app-facts.sh change from #293 runs the one-column guard queries through Python's sqlite3 when the sqlite3 CLI is missing, stripping the \r that native Windows Python prints.

Adapted to master (not in #293): #259 changed the catalog guard to stop testing the build_mode label, because mxcli v0.24+ labels a complete catalog source. #293's cut-score still tested build_mode != 'full'. Now the label is recorded and not tested, and an empty activities_data reads NOT DETECTED. The header no longer cites the decompose plan doc, which lands in a later split; it now points at skills/layering-review.md.

Field evidence: this is #293's run, now stated in the script header.

  • App: a public Mendix field-service template app (Marketplace, 9.24.2, MPR v1), mxcli v0.26.0, 42 own modules, 312 own edges, 4,508 refs. app-facts took 25 s; each cut-score run took ≤ 1 s.

  • Cuts scored: seven, all blocked. One app per level crossed 312 edges / 4,508 refs, which means little on its 36-module tangle. The best web | mobile landscape found was 132 edges / 1,442 refs with 2 bidirectional pairs.

  • Spot-check: 6 blocker rows checked with describe. All 6 were real references, but 2 had the wrong lane.

  • Captured fixture: a planted four-module Mendix 10.24 app (fixtures/cut-score/CAPTURE.txt).

  • Known limits from that run, not fixed here:

    • call mixes client-side nanoflow/JS calls in with server-side ones. That is about 30% of the main seam's blocker mass.
    • The catalog kinds sync, widget, schedule, event and publish never reach dependencies.json.
    • Nanoflows that aggregate the device store produce false aggregate hits.
  • No client data anywhere in the diff (leak guard and whole-word name grep are clean)

  • Size cap: exceeded. This PR needs the maintainer's size waiver. There are 612 non-test lines: bin/cut-score.sh (~600) plus app-facts (+12). I looked at splitting off the HTML renderer (~180 lines). It is not a clean cut: HTML is the default output, -o and fixture section 7 depend on it, and what remains would still be about 430 lines, over the cap.

  • Test tier reached: T1, fixtures on captured input plus synthetic layout trees and derived probes:

  • For a new/changed instrument: golden input is captured (CAPTURE.txt). Two-tree layout (.mpr under app/): probed only with synthetic trees, and cut-score finds the catalog in both. No real two-tree project has been run. macOS and Git Bash/Windows: unverified. Everything ran on Linux. The CRLF case simulates native Windows Python's output, but nothing has been run on Windows.

  • CHANGELOG.md line appended (crediting Decompose and Rehost pipelines: field runs on FSM and GenAI Showcase, three new skills #293's field runs)

Checks: render-routing.sh --check passes; the baseline is 75,038 words before and after. check-scripts, check-portability, the leak guard, check-no-private-citations and check-pr-discipline are all clean.

Review

The independent review returned MERGE-AFTER-FIX. Commit c55182f addresses each item:

  1. MEDIUM: the app-facts Python fallback did not strip \r, so on native Windows Python every [ "$(q …)" = "1" ] failed with "catalog schema is missing".
    • Fixed: | tr -d '\r', as _common.sh does.
    • Test seam: APPFACTS_NO_SQLITE3_CLI=1 forces the Python path.
    • New fixture case: in test-catalog-edge-guard.sh, a Python wrapper that ends every line in CRLF, run on both layouts. It passes 22/22 with the fix and 20/22 without it.
  2. LOW: rows said "NOT DETECTED (no catalog)" even when a catalog existed. Fixed: they now carry the actual reason, with new cases for an empty table and an unreadable file.
  3. LOW: in {from} | {to} - {None} the precedence was wrong. Fixed: parenthesised, with a new case of no scope plus an edge missing from. Decompose and Rehost pipelines: field runs on FSM and GenAI Showcase, three new skills #293's copy crashes on it.
  4. Size: waiver requested; the reasoning is in the size-cap item above. Field proof: the template-app run is now stated inline in the header, as results only.

Impact

Row Effect Evidence
Process None new. bin/cut-score.sh is an on-demand instrument, not wired into any gate. app-facts.sh no longer stops when the sqlite3 CLI is missing (falls back to Python's sqlite3). diff
Dependencies Shared file: project-bin/app-facts.sh (installed script). Merges clean onto master 868b3cb (git merge-tree). No conflicts with the other PRs in this batch; #346 cites bin/cut-score.sh, so this lands before #346. Platform: Linux only; native-Windows CRLF path simulated, not run on Windows or macOS. Reads analysis/app-facts/dependencies.json (producer: project-bin/app-facts.sh), analysis/app-layer-map.json (producer: bin/app-layer-map.sh; without it --cut is required), optional .mxcli/catalog.db (left by app-facts.sh). Size waiver requested. git merge-tree vs 868b3cb and pairwise; cut-score.sh header
Context cost Unchanged: baseline 73,522 → 73,522 words (budget 80,000); Stage 5 mdl 30,185 → 30,185, lead 25,820 → 25,820 bin/render-routing.sh --check on master 868b3cb vs this head (c55182f) merged onto 868b3cb via git merge-tree in a temporary worktree
Behaviour n/a (scripts only). diff touches no skill or agent stub
Runtime No change to exec, gates or checks. cut-score ≤ 1 s per run on the field app (42 modules); app-facts unchanged on the CLI path. PR field-evidence section

🤖 Generated with Claude Code

https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw

bin/cut-score.sh, its fixture (tests/wave2/test-cut-score.sh + captured
fixtures/cut-score/) and the app-facts.sh sqlite3-CLI fallback, copied
from #293's head and adapted to master: the catalog build_mode label is
recorded, not tested (#259), and an empty activities_data reads NOT
DETECTED. Fixture 56 -> 64 checks (label, empty table, both layouts).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
- app-facts: the Python sqlite3 fallback strips \r (native Windows Python
  under Git Bash, which has no sqlite3 CLI); APPFACTS_NO_SQLITE3_CLI=1
  forces that path. test-catalog-edge-guard gains a CRLF case (22/22).
- cut-score: rows name the actual NOT DETECTED reason; parenthesise the
  own-module set difference; header states the template-app field run.
- test-cut-score 64 -> 70.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
@MendixMau
MendixMau marked this pull request as ready for review October 15, 2026 08:21
@MendixMau
MendixMau merged commit 863ca3c into master Oct 15, 2026
2 checks passed
@MendixMau
MendixMau deleted the split-293/cut-score branch October 15, 2026 10:48
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.

2 participants