Skip to content

fix(core-engine): four metric defects — tcl body slicing, groovy/apex args call sites, m4 arity (#2763, #2782, #2783, #2784) - #2790

Merged
squid-protocol merged 6 commits into
mainfrom
fix/args-and-slicing-2750s
Sep 6, 2026
Merged

squid-protocol merged 6 commits into
mainfrom
fix/args-and-slicing-2750s

Conversation

@squid-protocol

@squid-protocol squid-protocol commented Sep 6, 2026 •

Copy link
Copy Markdown
Owner

Four measured metric defects found by the 2026-09-05 pass over the keyword-rosetta bias
variance chart and the 46-language args audit in docs/args_rule_contract.md. They are
batched into one PR because they share a single golden-master bless and one CI cycle;
each is a separate commit with its own evidence, so the audit trail stays per-issue.

commit issue language defect
57952db1 #2783 apex args counted call sites (+38%)
1dc32fc8 #2782 groovy args counted call sites (+46%)
2f1cd411 #2784 m4 avg_func_args took the first $N, not the highest
b0565306 #2763 tcl Mode B sliced the parameter list as the function body
f103d171 — docs folds the three args results back into the audit table

The three args fixes

#2782 and #2783 are the same defect #2773 fixed for typescript and objective-c: a
declaration arm whose return-type requirement was optional, so it collapsed to
^IDENT(...) — the shape of a bare call statement. Per the contract, args matches the
parameters a callable declares; a call site consumes a parameter surface, it does not
publish one.

corpus apex before → after groovy before → after
keyword-rosetta 18 → 13 19 → 13
language-crucible 41 → 39 2157 → 991

Both land on the planted count exactly on rosetta. Neither loses a real declaration:

  • groovy — the new crucible match set is a strict subset of the old, verified
    offset-by-offset across 304 files: 0 additions, 1166 removals. The removals are call
    statements plus 7 def (a, b) = … destructurings, which declare locals rather than
    parameters.
  • apex — recall is 38/38 unchanged against tree-sitter ground truth; precision
    38/41 → 38/39. The old 41-vs-41 was a coincidence, not agreement: 38 real declarations
    plus 3 false positives in SOQLRecipes.cls.

The interesting part of both is what the anchor had to avoid. A bare ; fallback for
bodyless declarations readmitted 163 matches in groovy, 60 of them paren-less DSL calls
(implementation project(':lib')) — the same trap typescript hit in #2773. Naming the
construct instead (mandatory type, primitive/def/uppercase-initial) recovers 122 genuine
interface and abstract declarations that a {-anchor alone cannot reach.

#2784 corrects its own issue

The m4 fix ships, but the issue's headline example does not reproduce.
AT_SETUP($1) AT_CHECK($1) never read arity 2 — the per-function path .search()es and
takes the leftmost hit, so a doubled $1 already read 1. Measured old-vs-new:

macro body before after true arity
AT_SETUP($1) AT_CHECK($1) (the issue) 1 1 1
AS_IF([test x$1], [do_thing($3)]) 1 3 3
AC_BEFORE([$0],[AC_OTHER]) 1 0 0

The real defects a first-match-only arity causes are the other two rows: every position
after the first was dropped, and $0 — the macro's own name — counted as a parameter.
Both are fixed by porting shell's _args_findall_max_groups (#1518).

The file-level count is deliberately untouched (18/18 rosetta, 70/70 crucible): it is
intended morphology, settled in keyword-rosetta's m4-parameters-are-use-sites. Wrapping
the alternation in a capture group moves no match boundary.

#2763 is gated on purpose, and the gating is the decision

A tcl proc has two brace groups. Mode B's generic fallback searched from start_idx, so
it always found the parameter list and closed one character later — every tcl function
in every scan recorded loc 1, complexity 0, struct_branch 0.

The blanket fix ("anchor at match.end() for all of Mode B") was measured first and is
catastrophic. 24 languages route to Mode B; 12 reach this generic fallback. Divergent
matches across both corpora:

c cpp scheme groovy powershell apex/css/html/php/swift
1756/1756 1247/1247 96/96 11 10 0

c/cpp consume their own body { inside func_start, so match.end() lands on the next
function's brace; scheme's opener is (. tcl is the only language in this fallback whose
func_start consumes a non-body brace group, so it is the only one the anchor may move
for. After the change, c (1756 functions) and cpp (1147) produce byte-identical
per-function records.

corpus functions loc<=1 mean loc branch>0
rosetta before → after 13 → 13 13 → 0 1.00 → 4.62 0 → 2
crucible before → after 389 → 389 389 → 5 1.00 → 35.90 1 → 272

Zero functions lost or gained. A no-brace fallback to the old anchor is retained
deliberately: a tcl body need not be a brace group (proc faultsim_test_proc {…} $O(-test)
passes a variable), and without the fallback that real declaration was dropped. The fix
is a strict superset of previous behaviour.

The commit also removes the C-family // comment shield from tcl's
_build_brace_safe_stream arm — perl's #1437 bug one language over. A URL's // blanked
the rest of the line including its }, unbalancing the depth counter; bzrfetch measured
loc 515 for a real 37-line proc. Invisible before this fix, because a tcl body was never
brace-walked at all.

Adds 6 regression tests, each verified to fail on 08a08c6a.

Verification

Every fix was re-measured independently by the integrator against the engine, not accepted
from its agent's report.

check result
ruff_audit.py --ci no new findings beyond the 70-finding baseline
mypy_audit.py --ci no new errors beyond the 2-error baseline
language extraction + strict tests 283 passed (tcl, groovy, apex, m4)
tree_sitter_accuracy_audit.py --ci --all 30 languages, all OK, no regressions
tri_comparison_chart.py --all --ci 3 languages, all OK, no regressions
rosetta_audit.py 2 regressions (apex, groovy) — expected, see below
crucible_check.py clean after the bless commit

Labelled rosetta:rebless-owed; a corpus PR is owed for apex and groovy. Their
manifests currently encode the pre-fix counts, which included the call sites this PR stops
matching. tcl and m4 pass unchanged.

file manifest args this PR planted func_start
apex/main.cls 7 4 4
apex/a.cls 5 3 3
groovy/main.groovy 7 4 4
groovy/a.groovy 4 3 3
groovy/c.groovy 5 3 3

Both languages now total 13, matching the 13 planted declarations exactly. b is already
correct in both and does not move. The corpus change is manifests-only — no authoring
change — and keyword-rosetta's ledger already tracks this as
args-call-site-counting-apex-groovy, split out in #2773's corpus pairing precisely for
these two follow-ups.

Golden masters were blessed once for all four fixes, in a single commit, after
regenerating and classifying the full uncapped diff: 1374 differences, of which 1069 are
the corpus-wide topological re-solve and 305 are content — 0 of them off-target.

Known and deliberately not fixed here, each a different defect class:

  • apex — a SOQL clause inside [...] of the shape SELECT SUM(Amount) total still reads
    as type=SELECT, name=SUM (1 crucible hit, 0 rosetta, unchanged by this PR). Wants a
    _scope_filters entry; blanket-excluding select is unsafe under this rule's re.I
    per the apex import rule: re.IGNORECASE neutralises the [A-Z] guard, so every qualified reference (foo.bar) counts as an import #2671 ledger entry.
  • groovy — arm 1's zero-prefix form still admits a DSL call with a closure argument
    (configure(foo) {), the likely source of the residual a/f > 1.00.
  • tcl — an upstream prism.py defect blanks # inside string map {1.#INF …} as a
    comment.

Closes #2763
Closes #2782
Closes #2783
Closes #2784

🤖 Generated with Claude Code

squid-protocol and others added 6 commits September 5, 2026 22:44
…tes (#2783)

The `args` method arm's return-type group carried a trailing `?`. With the annotation
and modifier runs both zero-allowed, that made the whole prefix optional and the arm
degenerated to `^[ \t]*IDENT(...)` -- the exact shape of a bare call statement. Per
`docs/args_rule_contract.md`, `args` matches the parameters a callable DECLARES; a call
site consumes a parameter surface, it does not publish one.

Same defect and same fix family as #2773 (objective-c, typescript) and #2782 (groovy).

* The return type is now MANDATORY, which is what `java` and `csharp` -- the same
  C-family rule, same shape -- already require. Apex has no `def`: every method
  declaration carries an explicit return type, and a constructor carries the class name
  in that position (`public Foo(x)` backtracks to type=`public`, name=`Foo`).
* `return` joins `new` in the return-type slot's exclusion, as csharp branch 1 already
  does: `return doWork(x);` is a call whose two tokens otherwise satisfy `type name(...)`.
* A new branch 3 reaches the one real declaration a mandatory return type cannot -- a
  modifier-less constructor (`MyClass(Integer x) {`, default private) -- anchored on the
  body `{` that FOLLOWS the parameter list, the way java/csharp anchor their own
  constructor branches. It is placed LAST so the method and trigger arms keep their
  capture-group indices, since `_calculate_block_metrics` reads `group(lastindex)`.

A `(?=[ \t\n]*\{)` lookahead was rejected as the PRIMARY anchor: it cannot reach Apex's
bodiless interface and `abstract` declarations, and relaxing it to `[{;]` re-admits
`foo(x);` verbatim. It is correct only as the secondary constructor branch.

Measured (raw rule counts over the prism code stream, both corpora):

| corpus            | func_start | args before | args after |
|-------------------|-----------:|------------:|-----------:|
| keyword-rosetta   |         13 |          18 |         13 |
| language-crucible |         41 |          41 |         39 |

keyword-rosetta lands on the 13 planted declarations exactly. The crucible's previous
41-vs-41 was a coincidence, not agreement: tree-sitter ground truth is 38 declarations,
so the old rule was 38 real plus 3 false positives in `SOQLRecipes.cls`. Recall is
38/38 unchanged; precision goes 38/41 -> 38/39. Per-function `args_count` has zero
differences across all 51 spliced functions -- the removed hits sat inside bodies, and
the block search takes the signature first -- so per-function metrics are untouched.

Known and deliberately not fixed here: a SOQL clause inside `[...]` of the shape
`SELECT SUM(Amount) total` still reads as type=`SELECT`, name=`SUM` (1 hit in
language-crucible, 0 in keyword-rosetta, unchanged by this commit). That is a different
defect class -- an embedded sub-language scanned as Apex statements, which wants a
`_scope_filters` entry rather than another keyword exclusion, and blanket-excluding
`select` is unsafe under this rule's `re.I` per the #2671 ledger entry.

Golden masters move (`SOQLRecipes.cls` file-level `args` 16->14 plus the corpus-wide
X/Y/Z re-solve); blessed once for all four fixes in a later commit on this branch.

Closes #2783

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…sites (#2782)

The `args` method arm's return-type run was `{0,3}`. At zero repetitions, with the
annotation and modifier runs also zero-allowed, the arm collapsed to `^[ \t]*IDENT(...)`
-- the shape of a bare call statement -- so `close(conn)`, `assertEquals(kit, kit)` and
`probeBranch(argv)` all scored as declared parameter lists. Per
`docs/args_rule_contract.md`, `args` matches the parameters a callable DECLARES; a call
site consumes a parameter surface, it does not publish one.

Same defect and same fix family as #2773 (objective-c, typescript) and #2783 (apex).

The terminator lookahead was the right family but insufficient alone, so the declaration
form is now two arms:

* Arm 1 (bodied) keeps the fully-optional prefix -- Groovy genuinely declares
  `def entry(argv) {` and bare constructors `FineractPluginExtension(Project project) {`
  -- and anchors on the body brace via `(?=[ \t\n]*(?:throws ...)?\{)`. It is a
  lookahead, so `group(0)` still ends at `)`, which a strict test asserts.
* Arm 2 (bodyless) reaches the casualty class a `{`-anchor cannot: Retrofit interface
  methods, `@Managed` model-rule interfaces, abstract Gradle property getters. Allowing a
  bare `;`/end-of-line here readmitted 163 matches, 60 of them Groovy's paren-less-call
  DSL sugar (`implementation project(':lib')`, `storePassword getReleaseKeystorePassword()`)
  -- the same trap typescript hit in #2773. So the construct is named instead: arm 2 makes
  the declaration type MANDATORY and limits it to a primitive, `def`, or an
  uppercase-initial type. That is the exact discriminator, since the DSL sugar's receiver
  is always a lowercase property name.

A `{`-lookahead alone yields 890 on the crucible; arm 2 recovers 122 genuine bodyless
declarations on top of that -- the measured difference between a correct fix and a merely
narrower one.

The parameter-list matcher is now string-aware (`[^()"']|"[^"]*"|'[^']*'|\([^()]*\)`),
because once you check what FOLLOWS the list, a stray `)` inside a default value's string
literal breaks the match -- `test_groovy.py`'s pathological case. This is count-neutral:
the crucible match set is byte-identical with and without it.

Measured (raw rule counts over the prism code stream):

| corpus                      | func_start | args before | args after |
|-----------------------------|-----------:|------------:|-----------:|
| keyword-rosetta (4 files)   |         13 |          19 |         13 |
| language-crucible (304)     |        875 |        2157 |        991 |

keyword-rosetta lands on the 13 planted declarations exactly, and per file now equals the
func_start column (3/3/3/4). a/f goes 2.48 -> 1.13. No corpus authoring change needed.

Recall: the new crucible match set is a strict SUBSET of the old -- 0 additions, 1166
removals, verified by diffing both match sets offset-by-offset. The removals are call
statements plus 7 `def (a, b) = ...` multiple-assignment destructurings, which declare
locals rather than parameters and are correctly out of contract. No real declaration lost.

The pattern now has 5 capture groups rather than 3 (the closure group moves 3 -> 5). This
is safe: `_calculate_block_metrics` reads `group(lastindex)`, and groovy declares no
index-keyed `_args_*_groups` config and no `_scope_filters` -- both confirmed empty.

Pre-existing and deliberately not addressed: arm 1's zero-prefix form still admits a DSL
call with a closure argument (`configure(foo) {`), the likely source of the residual
a/f > 1.00. `func_start` guards that with a DSL-keyword exclusion list plus a
named-argument lookahead; porting either is a separate change carrying its own risk.

Golden masters move (groovy appears in both audits); blessed once for all four fixes in a
later commit on this branch.

Closes #2782

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ex, not the first (#2784)

`m4` has no formal parameter list, so `$1`/`$@` in a macro body is the whole parameter
surface. The FILE-LEVEL count of those references is intended morphology, settled in
keyword-rosetta's `m4-parameters-are-use-sites` ledger entry, and this change deliberately
leaves it untouched: wrapping the existing alternation in one capture group moves no match
boundary, so the raw rule count is byte-for-byte identical (verified: keyword-rosetta 18
-> 18, language-crucible 70 -> 70).

What moves is the PER-FUNCTION arity. m4 has no `args_search_text` bound -- that exists
only for objective-c/c/cpp/dart -- so `_calculate_block_metrics` searches the whole macro
body and trusts the single LEFTMOST hit. `shell` hit exactly this in #1518 and solved it
with `_args_findall_max_groups`, which makes the shared counter re-scan the block and take
the highest positional index via `_count_shell_positional_max`. This ports that mechanism;
group 1 is the hook the helper indexes on.

CORRECTION TO THE ISSUE: #2784's headline example does not reproduce. Measured
old-vs-new on the per-function path:

| macro body                              | before | after | true arity |
|-----------------------------------------|-------:|------:|-----------:|
| `AT_SETUP($1) AT_CHECK($1)` (the issue)  |      1 |     1 |          1 |
| `AS_IF([test x$1], [do_thing($3)])`      |      1 |     3 |          3 |
| `AC_BEFORE([$0],[AC_OTHER])`             |      1 |     0 |          0 |
| `do_all($@)`                             |      1 |     1 |          1 |

A doubled `$1` already read 1, because the leftmost-hit path takes `"$1"` and stops --
so the issue's "reads arity 2" claim was wrong. The +38% it measured is purely the
file-level total, which is the ledgered morphology and correctly stays. The defects the
first-match-only path really does cause are the other two rows: every position after the
first was silently dropped, and `$0` -- the macro's own NAME, not a parameter -- was
counted as one. Both are fixed, which is the issue's actual intent (an arity should
reflect declared positions), so it is closed here rather than reopened.

Corpus effect, hand-verified:

* keyword-rosetta: file-level 18 -> 18, per-function sum 13 -> 13, `avg_func_args`
  1.0000 -> 1.0000. Nothing moves; no corpus re-authoring needed.
* language-crucible: file-level 70 -> 70, per-function sum 14 -> 0, `avg_func_args`
  0.3590 -> 0.0000. This is a precision gain, not a recall loss: every `$N` inside a
  sliced macro on that corpus is `$0` (curl-confopts 9, zz40-xc-ovr 51, xc-am-iface 3),
  all the `AC_BEFORE([$0],[...])` idiom inside genuinely argument-less `AC_DEFUN`s --
  true arity 0, where the old 1.0 was `$0` misread as a parameter. The only real
  `$1`/`$2` on that corpus is in `curl/configure.ac`, which has `func_start = 0`, so no
  satellite gained or lost a count. No macro that actually references a positional
  argument went to zero.

The block is safely bounded for a whole-block re-scan: `_slice_by_m4_brackets` (Mode F)
cuts at the macro's own bracket-aware paren span, so no neighbouring macro's positions
leak in despite the missing `args_search_text`.

Golden masters move -- the crucible per-function sum flows through `avg_func_args` ->
`log_avg_func_args` -> magnitude for the `m4/curl/*` entries; blessed once for all four
fixes in a later commit on this branch.

Closes #2784

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… audit

The 46-language audit table still described apex, groovy and m4 as open violations and
carried the counts they had BEFORE the three fixes on this branch. Updates each row to the
measured post-fix numbers and the anchor shape that got them there.

Corollary 3 is also corrected on a point the m4 work disproved. It asserted that
`$1 … $1` "is one parameter referenced twice under any reading" and implied the engine
read it as 2. It did not -- the per-function path takes the LEFTMOST hit, so a doubled
`$1` already read 1. The real failure of a first-match-only arity is that it drops every
higher position after the first (`$1 … $3` read 1, not 3) and counts `$0`, the macro's own
name, as a parameter. The corollary now states the rule that actually holds: an arity is
the highest position DECLARED, not the first one seen.

Rows now read as fixed rather than filed:

* `apex` 18 -> 13 rosetta, 41 -> 39 crucible. Records that the old 41-vs-41 was a
  coincidence -- 38 real declarations plus 3 false positives -- so the fix is a precision
  gain with recall unchanged at 38/38.
* `groovy` 19 -> 13 rosetta, 2193 -> 991 crucible, a/f 2.48 -> 1.13.
* `m4` file-level 18/70 unchanged (the ledgered morphology), with the correction that its
  `$1 ... $1` example never reproduced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… not the parameter list (#2763)

A tcl `proc` has TWO brace groups -- the parameter list (`proc name {a b}`) and then the
body (`{ ... }`). Mode B's generic fallback starts its brace search at `start_idx`, so for
tcl it always found the PARAMETER LIST and `_find_balanced_end` closed one character
later. Every tcl function in every scan recorded `loc` 1, `complexity` 0 and
`struct_branch` 0: 13/13 functions in keyword-rosetta, 389/389 in language-crucible.

`func_start` already consumes the parameter group via its optional
`(?:[ \t\n]+\{...\})?` arm, so `match.end()` is the correct body anchor.

THE FIX IS GATED TO TCL, AND THAT GATING IS THE LOAD-BEARING DECISION. The blanket form
-- "search from `match.end()` for every Mode B language" -- was measured first and is
catastrophic. 24 languages route to Mode B; 13 have their own `elif` earlier, so 12 reach
this generic fallback. Every one of them except tcl either consumes its own body `{`
inside `func_start` or stops before the parameter list, so moving the anchor skips the
real body and grabs the NEXT declaration's brace. Divergent matches (first `{` from
`start_idx` != first `{` from `match.end()`) across both corpora:

| c | cpp | scheme | groovy | powershell | apex/css/html/php/swift |
|---:|---:|---:|---:|---:|---:|
| 1756/1756 | 1247/1247 | 96/96 | 11 | 10 | 0 |

scheme's opener is `(` rather than `{`. tcl is the only language in this fallback whose
`func_start` consumes a NON-BODY brace group, so it is the only one the anchor may move
for. Verified after the change: c (1756 functions) and cpp (1147) produce byte-identical
per-function records, as do the other nine.

On the #2758/#2760 precedent (Mode D anchoring at the declaration rather than the brace):
that change carried no per-language gate and added no reusable flag, but it cuts toward
gating rather than away -- it is self-gating by construction, its message justifies scope
by a property "Mode D specifically" has, and it measured the broad form (601 golden-master
diffs), rejected it, and shipped the narrow one (20). Precedent for measure-then-narrow.

A no-brace fallback to the old anchor is retained deliberately. A tcl body need not be a
brace group at all -- it is just another word, and `proc faultsim_test_proc {testrc
testresult testnfail} $O(-test)` (sqlite/malloc_common.tcl:347) passes a VARIABLE as the
body. Without the fallback that real declaration was DROPPED (376 -> 375). With it, every
proc either gets a correct body span or exactly what it had before, so the fix is a strict
superset and the function count never moves.

Also fixes a second, separable defect in the same language's `_build_brace_safe_stream`
arm, which carried the C-family `//[^\n]*|/\*.*?\*/` shield -- exactly perl's #1437 bug one
language over. Tcl's only comment introducer is `#` (already blanked upstream by prism),
but `//` appears constantly as a URL scheme separator, and shielding from it blanked the
rest of the line including any `}` on it, silently unbalancing the depth counter. This was
invisible before the slicer fix because a tcl body was never brace-walked at all; with it,
`portfetch.tcl`'s `bzrfetch` measured loc 515 for a real 37-line proc. 14 of 376 crucible
procs over-captured this way; all 14 resolve with the branch removed.

Measured:

| corpus  | functions | loc<=1 | mean loc | branch>0 |
|---------|----------:|-------:|---------:|---------:|
| rosetta before / after | 13 / 13 | 13 / 0 | 1.00 / 4.62 | 0 / 2 |
| crucible before / after | 389 / 389 | 389 / 5 | 1.00 / 35.90 | 1 / 272 |

Recall: 0 functions lost, 0 gained on either corpus; `args_count` identical for all of
them. The residual `loc<=1` rows are genuine one-line procs plus the variable-bodied one.

An independent tcl-aware raw-source brace walker (more reliable here than
tree-sitter-tcl, which is itself wrong on this corpus) puts functions with a verifiably
correct span at 8/376 -> 370/376. Of the 2 residuals, one is an oracle artifact (nested
`proc finish_test`) and one is an upstream `prism.py` defect -- `#` inside
`string map {1.#INF ...}` blanked as a comment -- filed separately, out of scope here.

Adds 6 regression tests to `tests/extraction/languages/test_tcl_strict.py`, each verified
to FAIL on 08a08c6.

Golden masters move and are NOT blessed here; the branch blesses once for all four fixes.
Quantified against a clean baseline (committed GM vs unmodified-HEAD scan = 0 diffs):
585 diffs, of which 430 are topological X/Y/Z from the corpus-wide re-solve, 152 are
tcl-path content fields and 3 are global roll-ups whose inputs include tcl. No off-target
content change, and no function added or removed anywhere.

Closes #2763

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
One bless covering all four engine fixes on this branch, rather than four separate
re-blesses of the same two fixtures.

The full uncapped diff was regenerated and classified before blessing, because
`crucible_check.py`'s own output is capped twice (50 differences in `golden_diff.py`, a
4000-char window in the wrapper) and cannot support a scoped review on its own. Method is
CLAUDE.md's: rescan the corpus with the zero-dependency venv, then `deep_compare` against
the committed fixture.

1374 differences, every one attributed:

| class | count |
|---|---:|
| topological X/Y/Z coordinates | 1069 |
| tcl content | 136 |
| groovy content | 131 |
| global roll-ups | 27 |
| m4 content | 10 |
| apex content | 1 |
| **off-target content** | **0** |

The 1069 coordinate diffs are the corpus-wide 3D layout re-solving, which happens whenever
any node's mass changes and therefore ripples into languages this branch never touched;
they are attributable as a class, not individually. All 305 content differences fall in
the four languages the branch changes, plus 27 global roll-ups whose inputs include them
(`directory_groups/tcl/*`, `directory_groups/m4/curl/m4/*`, `health/avg_documentation`,
`health/avg_cognitive_load`, and the `exposures/documentation/lowest` leaderboard, whose
entries are literally the tcl files whose documentation became measurable once their
bodies were sliced correctly).

The largest single movers are the expected consequences of #2763: `directory_groups/tcl/
sqlite/total_mass` 1970.88 -> 3819.68 and `avg_exposures/documentation` 0.0 -> 3.97,
because every tcl function previously recorded `loc` 1 with no body to carry documentation
or complexity.

`scope_check.py --expect tcl,groovy,apex,m4` also ran; it exits non-zero because the
topological re-solve touches other languages' coordinates, which is expected and is why
the classification above was done directly rather than relying on its verdict.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

@squid-protocol squid-protocol added the rosetta:rebless-owed Intentionally moves keyword-rosetta counts; audit warns, corpus re-blesses after merge label Sep 6, 2026
@squid-protocol
squid-protocol merged commit 2ca956a into main Sep 6, 2026
43 of 44 checks passed
@squid-protocol
squid-protocol deleted the fix/args-and-slicing-2750s branch September 6, 2026 03:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment