Skip to content

arch_api conflates api-rule hits with converted orphans, and the rosetta gate reads the conflated column -- 36 of 44 languages pass api without the rule matching anything #2729

Description

@squid-protocol

Found by the #2669 F.4 census. This is the biggest of the three and it needs a decision before anything is changed.

What the gate is actually asserting

The Contextual Baseline Fix (galaxyscope.py L2228) rewrites api in place when a file is imported:

if popularity > 0 and orphans > 0:
    meta["equations"]["api"] = meta["equations"].get("api", 0) + orphans
    meta["equations"]["orphaned_logic"] = 0

raw_arch_api keeps the pre-fix value (#2536); arch_api carries the sum. keyword-rosetta's verify_language.py builds its column map from RecordKeeper.SHORT_KEY_MAP, which maps api → arch_api — the conflated column. Measured per file:

file manifest api rule finds orphans converted gate reads
shell/a.sh 3 0 3 3 ✓
go/a.go 3 0 3 3 ✓
python/a.py 6 3 3 6 ✓
c/a.c 12 9 3 12 ✓

Shell's api rule is ^export NAME and no probe exports anything. Go's is ^func [A-Z]… and every probe function is lowercase. Both measure zero and both pass, because three uncalled functions become three API surfaces. The manifests were recorded from the adjusted column, so the conversion is baked into the expectation.

Corpus-wide, raw_arch_api is 0 in 36 of the 44 languages that define an api rule. The median is therefore 0, and the bias report flags the ten languages whose rule does fire (c, python, embedded_python, fortran, lua, scala, livecode, css, makefile, html) as the deviants. The finding is inverted: those ten are the only ones measuring anything.

Why it matters beyond the corpus

_calc_api_exposure and _calc_documentation read the adjusted api, so on real code an uncalled-but-imported function is scored as public surface. That may well be the intent (it is what #2536 argued), but it means api in the risk equations is not the api rule, and nothing in the test surface distinguishes them. It also interacts with #2727: a language whose syntax repeats function names produces no orphans, hence no conversion, hence api == 0, hence _calc_api_exposure's if api_hits == 0: return 0.0 short-circuit — which is exactly why ada, haskell, sqlite, yaml and dockerfile sit at the bottom of risk_api_exposure and risk_documentation.

Fix shape (two halves, both needed)

  1. Engine/test surface: make the split explicit. RISK_INPUT_COLUMNS in keyword-rosetta's bias_report.py already maps api → raw_arch_api for exactly this reason; the gate should do the same, so api asserts what the rule found and the conversion is asserted separately (as arch_api - raw_arch_api, or not at all).
  2. Corpus: once the gate reads the raw column, ~36 languages go red on api and each needs a call — either the probe grows an exported construct in that language's own vocabulary (export in shell, a capitalised func in Go, pub in rust) or the language's api rule is too narrow. That is a corpus wave of its own, comparable in size to Batch A, and should not be folded into F.4.

F.4 bakes the current behaviour into deviation_ledger.json per GATING's upstream rule and cites this issue. Part of #2669; siblings #2727, #2728.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugUnintended behavior or logic failure in the enginecore-engineModifications to the central physics and parsing enginemetricsHeuristics, risk exposures, and topological math updates

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions