Repository navigation
docs(adr): retain the current layering engine (ADR 0032) - #3286
Conversation
Measures dependency-cruiser 18.5 and fallow 3.32 against the custom layering edge model for R2, R4, R5, R6, R77, R78, R14 and R71: edge-set diff, planted-violation parity, and runtime. Not a gate; ADR 0032 owns its deletion. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Records the #3278 boundary-tool spike: neither dependency-cruiser nor fallow boundaries reaches parity for the eight plain graph rules, and either would add a second import graph beside the one ~20 other rules consume. Includes the four comparison tables and revisit triggers. Closes #3278 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Size Report
Startup median (7 runs, lower is better):
|
There was a problem hiding this comment.
7 issues found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="docs/adr/README.md">
<violation number="1" location="docs/adr/README.md:36">
P3: This entry describes replacing the custom rules, but ADR 0032 explicitly keeps them. Change “replacing” to “evaluating replacement of” so the index matches the decision.</violation>
</file>
<file name="docs/adr/0032-layering-graph-engine.md">
<violation number="1" location="docs/adr/0032-layering-graph-engine.md:95">
P3: ADR 0010 (error-system.md) governs the user-facing error contract (code, message, hint, details via normalizeError) and never prescribes a `file:line` layout for layering violations. Custom violations do carry `file` and `line` (see `check.ts`, e.g. `{ file: edge.file, line: edge.line }`), but that format is not "required" by ADR 0010, so the citation will mislead a reader tracing the reference. Drop the citation or point at `check.ts` instead.</violation>
<violation number="2" location="docs/adr/0032-layering-graph-engine.md:106">
P2: The harness computes each median from three measured runs, not five. Change the count to three or update the harness to collect five runs so the reported timing is reproducible.</violation>
</file>
<file name="scripts/layering/boundary-engine-spike.ts">
<violation number="1" location="scripts/layering/boundary-engine-spike.ts:91">
P2: R4 still scans the 13 runner `__tests__` helpers that do not end in `.test.ts`, because the global exclude preserves the whole runner subtree for R77. Exclude test-path modules, including intermediate cycle nodes, from R4 while retaining R77 test coverage.</violation>
<violation number="2" location="scripts/layering/boundary-engine-spike.ts:165">
P2: The engine configuration scans every on-disk source under `src` and `packages`, while the custom side reads tracked files only. An unrelated untracked source can alter engine findings and baselines; fail closed on untracked production files or constrain the engine inputs to the tracked scope.</violation>
<violation number="3" location="scripts/layering/boundary-engine-spike.ts:276">
P2: `run()` discards the engines' `stderr` and, outside the stale-gate path, their exit status. When depcruise or fallow fails — invalid config, tsconfig resolution, missing TypeScript 6 — `stdout` is empty or partial and `JSON.parse` in `depcruise()`/`fallow()` throws a bare `SyntaxError: Unexpected end of JSON input`, hiding the engine's actual diagnostic. Return `stderr` from `run()` and include it (plus `status`) in the parse-failure error so the harness surfaces the underlying engine error.</violation>
<violation number="4" location="scripts/layering/boundary-engine-spike.ts:706">
P3: `writePlants()` dirtied the working tree (new `ws2-plant*` files plus edits to `runner-provider.ts`, `runner-artifact.ts`, `runner-cache.ts`, `daemon-client-lease-beat.ts`) and cleanup only runs via the surrounding try/finally. SIGINT/SIGTERM during the multi-minute timed fallow runs kills the process without unwinding, leaving the edited files modified and the plant files on disk — contradicting the header's "removed ... before the script exits" promise and polluting `git status` in a checkout that also runs the layering gate. Register signal handlers that call `restore()` before exiting.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
- Refuse to run unless the production roots hold exactly the tracked tree: the engines read the disk, the custom rules read tracked files. - Exclude test modules, helpers included, from R4 (start, first hop and via nodes) and R5/R6 through one TEST_PATH pattern. - Report engine stderr, exit status and signal when output is not JSON. - Record plants in a manifest before touching the tree; restore on exit, error and SIGINT/SIGTERM/SIGHUP, and at the next start after SIGKILL. - Median of five runs, and measure every runtime the ADR reports. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Runtime table and fallow's marginal cost now come from the harness run; custom messages cite check.ts report() instead of ADR 0010; the index entry says the ADR evaluates a replacement rather than performing one. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
The plant manifest outlives a killed run, so restoring it blindly could overwrite a tracked file edited in between. Record each touched file's content before and after planting; restore only when every file still holds one of the two, and otherwise stop without touching anything. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Status names d9959f5, where the harness produced the tables (its production tree is 7dda0c2's); the Measured section separates what the harness emits from the line counts of the deletion table; runtimes are re-measured there, and fallow's marginal cost is stated as within noise. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
I reviewed 3de1186. The ADR reads well and the code review found no problems, but I did not run the harness, so the edge-set, parity, clean-tree and runtime numbers are the author's re-run and not reproduced here. I also did not confirm that the production tree at d9959f5 matches 7dda0c2; I inferred it because the diff touches no src or packages files. I counted only the file-level rows of the deletion table with wc, so the R2, R5 and R6 function-range counts are unchecked. Checks are green (19 reported, none failing), and the diff touches no daemon, backend or surface route, only docs/adr and a script outside every gate. There are no conflicts. The only open item is the question about the harness below. Not blocking: https://github.com/callstack/agent-device/blob/3de1186/scripts/layering/boundary-engine-spike.ts#L1 is an 859-line harness that no gate covers. It is excluded from typecheck and from fallow, and it imports ten internal symbols from check.ts, model.ts, package-boundaries.ts, ratchet-reference.ts, apple-runner-host-port-policy.ts and tracked-sources.ts. A rename in any of those would break it silently, and the ADR's re-run plan would then find a script that does not compile. You can take or leave this. Either delete the file and cite it as Could you merge the ADR alone, about 140 lines, and pin the measurement to d9959f5, which the Status line already names? The revisit procedure would then retrieve the harness from that commit. That drops 859 unchecked lines from the production tree and keeps every number reproducible. Nothing has to change first except the Deletion section saying "retrieve from d9959f5" instead of "re-run the in-tree file". The ten earlier inline threads from cubic-dev-ai are all fixed at this head, so you can resolve them: RUNS = 5, tracked-scope check, test paths in R4, parseOutput failure detail, README row wording, ADR 0010 citation, plant manifest restore, deletion table wording, restorePlants on edited files and Status line production tree. |
The harness imports internal symbols from six layering modules, and no gate typechecks or fallow-scans scripts/layering/, so a rename would break it silently. It now lives only at d9959f5, where every number in the ADR was produced; the Measured and Deletion sections retrieve it with git show. Numbers the pinned run did not emit are removed or stated as file counts at that commit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Done in 478fbd8. The PR now merges the ADR alone, as you asked: 2 files, 148 lines (ADR 0032 and its index row). Harness pinned, not in the tree. ADR wording.
Only numbers produced at
To answer two points you couldn't check: Threads. All ten cubic threads you listed were already resolved, each with a reply naming its fix commit: 7 from the first round, 3 from the second. 10/10 resolved, 0 open. Validation. |
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
At d9959f5 the harness derives R5/R6 from model.ts's RANKED_ZONES and zoneRank, not TARGET_DAG_RANK, and writes the other rules' paths inline (R77's from RUNNER_SUBTREE) rather than reading the rule tables. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Thanks for the update. The code review of 0993bb0 is clean: the earlier thread is fixed, because docs/adr/0032-layering-graph-engine.md line 24 now names RANKED_ZONES and zoneRank, which matches the pinned harness. All 8 checks pass, and since the diff is docs only, no CI route overlaps with it. There are no conflicts, and nothing else needs to change before merge. I did not re-run the pinned harness to check the ADR's measurement numbers (the edge counts and the 122-line figure), and I did not confirm that the pinned commit stays reachable after the squash merge. The earlier inline thread (#3286 (comment)) no longer applies at this commit, so you can resolve it. |
|
Closing the open point on reachability with a measurement. No change was needed, so I pushed nothing and the head stays What survives a squash merge. Three PRs squash-merged earlier today (#3262, #3253, #3217) all have their branches deleted on the remote, yet
So after a squash merge and branch deletion, the PR ref is the only thing keeping a PR's commits. The pin today. In the same clone, ADR wording. It already names exactly this path: "Retrieve it with Remaining limit. The PR ref is a GitHub-hosted guarantee. A mirror or migration that drops |
|
Design follow-up on
Suggested decision wording:
The four evidence tables and the out-of-tree harness are useful as they stand. I checked that the pinned production trees match, but did not rerun the benchmark/parity harness; its measurements remain author-reported. |
Adopt the maintainer's decision statement. Graph-based checks share one normalized import model whose implementation stays replaceable; list its actual consumers and the facts they need instead of tying it to the AST rules. Separate the semantic blockers (missed dynamic imports, orphan files) from migration costs (formatting, config comments, a path check for filesystem-placement rules), retarget the revisit triggers, and link the parser-gap follow-up #3293. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Done in 081d869: ADR wording and the index row only. The evidence tables and the pinned harness are unchanged. The title is now "Retain the Current Engine". 1. One import model, implementation not frozen. I classified the 29
"About 20 … keep it alive" is replaced by that list of consumers and the facts they need. Rules at a glance now says graph-based checks share one normalized import model, "today built by 2. Blockers vs migration costs. The Decision section opens with your statement verbatim, then splits the reasons.
The engine triggers now name only blockers: a dedupe key that includes the dependency type, and fallow gaining a dynamic kind plus rule-pack coverage of unreachable files. 3. Parser gap. Rules at a glance links #3293 and gives its direction.
|
|
Summary
ADR 0032 records the workstream-2 spike of #3276: retain the current layering engine for R2, R4, R5, R6, R77, R78, R14 and R71. Graph-based checks share one normalized import model whose implementation remains replaceable.
The ADR has the edge-set diff, planted-violation parity (23 plants), runtime and lines-deletable tables for dependency-cruiser 18.5 and fallow 3.32. It separates semantic blockers from migration costs:
import(). Its rule packs skip orphan files.Both engines also find 9 TS
import('x').Tpairs thatparseImportsmisses. The fix is tracked in #3293.Every measurement is pinned to
d9959f510(production tree of7dda0c2bf). The spike harness lives only there, retrieved withgit show d9959f510:scripts/layering/boundary-engine-spike.ts.2 files (ADR and index row). Closes #3278.
Validation
081d869a2.pnpm check:affected --run: passed (docs-only diff; no local checks selected).pnpm format:checkpassed.d9959f510on a clean tree and matches every ADR table;git diff 7dda0c2bf d9959f510 -- src packagesis empty.🤖 Generated with Claude Code