Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions gitgalaxy/core/detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,26 @@ def _resolve_class_start_match(match: re.Match, groups_count: int) -> tuple[Opti
INVOCATION_POSITIONAL = "positional"
INVOCATION_MODELS = frozenset({INVOCATION_BY_NAME, INVOCATION_POSITIONAL})

# #2904: the export-visibility models a registry may declare through the
# top-level `export_visibility` key. `standard` is the default and needs no
# declaration: a symbol an `export`/visibility construct marks is an ordinary
# public symbol, and an exported-but-uncalled unit is still measured as
# `unreferenced_by_name` (the #2774 dead-code population). `external_entry_points`
# says the language's export construct is narrow and curated -- it names the
# units an EXTERNAL invoker runs (a makefile `.PHONY:` target is invoked by a
# human typing `make all`, by CI, by a Dockerfile -- never by an in-repo
# caller or import), so those declared orphans are public surface, not dead
# weight. galaxyscope.py's Contextual Baseline Fix reads this to give such a
# unit the same api-surface credit an imported file's orphans get (tier 3),
# WITHOUT the language ever being imported. Opt-in per language and asserted
# closed by `tests/core_engine/test_export_visibility_contract_2904.py`, so a
# typo cannot silently exempt a language from the dead-code census -- and it is
# deliberately NOT set on languages whose `export` decorates every symbol
# (JS/TS), where a blanket exemption would blind #2774.
EXPORT_VISIBILITY_STANDARD = "standard"
EXPORT_VISIBILITY_EXTERNAL_ENTRY_POINTS = "external_entry_points"
EXPORT_VISIBILITY_MODELS = frozenset({EXPORT_VISIBILITY_STANDARD, EXPORT_VISIBILITY_EXTERNAL_ENTRY_POINTS})

# #2728: a THIRD family of slicer-synthesized names, distinct from both sets
# above. Where a language's `func_start` capture group is a closed set of
# literal keywords -- css `@(media|supports|container|layer|keyframes|
Expand Down Expand Up @@ -2015,6 +2035,15 @@ def splice(
# already counted as public surface. Consumed by galaxyscope.py's
# Contextual Baseline Fix; never a signal in its own right.
"api_declared_orphans": api_declared_orphans,
# #2904: does this file's language declare its export construct to
# name EXTERNAL entry points (a `.PHONY:` target), not ordinary
# public symbols? Read from the closed `export_visibility` registry
# key, mirroring how `invocation_model` is consumed above. Consumed
# by the Contextual Baseline Fix's tier-3 branch; never a signal.
"exports_are_external_entry_points": (
self.languages.get(self.primary_lang_id, {}).get("export_visibility", EXPORT_VISIBILITY_STANDARD)
== EXPORT_VISIBILITY_EXTERNAL_ENTRY_POINTS
),
}
if profile_regex:
result_payload["regex_telemetry"] = regex_telemetry
Expand Down
35 changes: 35 additions & 0 deletions gitgalaxy/galaxyscope.py
Original file line number Diff line number Diff line change
Expand Up @@ -2324,6 +2324,41 @@ def _calculate_risk_exposures(self):
func["is_public"] = True
func["usage_status"] = 0
# =================================================================
# ---> #2904: TIER-3 EXTERNAL-ENTRY-POINT RESCUE <---
# A makefile is never imported (nothing `import`s a makefile; its
# caller is a human typing `make all`, CI, or a Dockerfile), so its
# popularity is STRUCTURALLY 0 and the tier-2 fix above can never
# reach it -- every `.PHONY:` entry point falls through to
# `risk_tech_debt`. But a `.PHONY:` target is a curated declaration
# of the file's EXTERNAL interface, not dead weight. For a language
# that opts in via `export_visibility: external_entry_points`, credit
# its DECLARED entry-point orphans (`api_declared_orphans` -- the
# orphans whose name sits on an api-rule line) the same way an
# imported file's orphans are credited: clear them from the tech-debt
# census. Only the declared portion moves -- a genuinely internal,
# UNdeclared orphan target (never .PHONY, no in-repo caller) stays
# real dead weight, so this cannot blind #2774. Gated on the tier-2
# branch NOT firing (elif), so popularity>0 never double-runs it.
# The honest census survives in `raw_pre_adjustment` above; only the
# debt/surface classification moves, never the raw count.
elif meta.get("exports_are_external_entry_points") and "equations" in meta:
orphans = meta["equations"].get("unreferenced_by_name", 0)
declared = min(meta.get("api_declared_orphans", 0), orphans)
if declared > 0:
# No api credit: a declared entry point's own declaration
# line is already an api-rule hit, so `api` already carries
# it -- re-crediting would double-count. Just stop reading it
# as tech debt.
meta["equations"]["unreferenced_by_name"] = orphans - declared
for func in meta.get("functions", []):
# A unit that is already public (api/export source B) AND
# uncalled is exactly a declared external entry point --
# clear its unused flag (is_public source C analogue). An
# undeclared internal orphan (is_public False) is left
# flagged, so it keeps contributing to the census.
if func.get("usage_status") == 1 and func.get("is_public"):
func["usage_status"] = 0
# =================================================================

meta["temporal_telemetry"] = self.chronometer.get_file_history_metrics(rel_path)
meta["authors"] = meta["temporal_telemetry"].get("authors", {})
Expand Down
11 changes: 11 additions & 0 deletions gitgalaxy/standards/language_standards/languages/makefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@
# UPGRADED: Maps to Family 3 (Pure Hash)
# Rationale: Make natively uses '#' exclusively for line-level comments.
"lexical_family": "line_exclusive",
# #2904: a makefile's callable units are invoked EXTERNALLY -- a human typing
# `make all`, CI, a Dockerfile -- never by an in-repo caller or import, so a
# `.PHONY:` target is a curated declaration of the file's external interface,
# not dead weight. This opts makefile into the tier-3 Contextual Baseline Fix
# (galaxyscope.py): its declared entry-point orphans are credited as api
# surface instead of `risk_tech_debt`, while the census keeps reading the
# orphan honestly. Narrow and safe because `_visibility_export_list`
# (`.PHONY:`) names exactly the external interface, unlike a JS/TS `export`
# that decorates every symbol. Closed set asserted by
# tests/core_engine/test_export_visibility_contract_2904.py.
"export_visibility": "external_entry_points",
"rules": {
# --------------------------------------------------------------------------
# 1. GEOMETRY & SHAPE (Geometry & Shape)
Expand Down
81 changes: 81 additions & 0 deletions tests/core_engine/test_export_visibility_contract_2904.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# ==============================================================================
# GitGalaxy
# Copyright (c) 2026 Joe Esquibel
#
# This source code is licensed under the PolyForm Noncommercial License 1.0.0.
# You may not use this file except in compliance with the License.
# A copy of the license can be found in the LICENSE file in the root directory
# of this project, or at https://polyformproject.org/licenses/noncommercial/1.0.0/
# ==============================================================================
"""The `export_visibility` contract (#2904), pinned in one cross-language module.

The registry key answers one question: does a language's export construct name
EXTERNAL entry points (a makefile `.PHONY:` target, invoked by a human, CI, or a
Dockerfile -- never by an in-repo caller or import), or ordinary public symbols?

The default is `standard`: an exported-but-uncalled unit is still measured as
`unreferenced_by_name` (the #2774 dead-code population). Only where the export
construct is NARROW and CURATED (`.PHONY:`) may a language opt into
`external_entry_points`, which lets galaxyscope's Contextual Baseline Fix credit
those declared orphans as api surface instead of tech debt (tier 3). Opting in a
language whose `export` decorates every symbol (JS/TS) would blind #2774, so the
opted-in family is pinned here as a literal -- adding to it is a deliberate edit
reviewed against the contract, never a side effect of a registry tweak.

Like the #2806 `invocation_model` contract, this is a cross-language table, not a
per-language test: a language that disagrees shows up as a row, not a missing file.
"""

from __future__ import annotations

from gitgalaxy.core.detector import (
EXPORT_VISIBILITY_EXTERNAL_ENTRY_POINTS,
EXPORT_VISIBILITY_MODELS,
EXPORT_VISIBILITY_STANDARD,
)
from gitgalaxy.standards.language_standards import LANGUAGE_DEFINITIONS


def _declared_visibility(lang: str) -> str:
return LANGUAGE_DEFINITIONS[lang].get("export_visibility", EXPORT_VISIBILITY_STANDARD)


# The languages whose export construct names external entry points. Kept as a
# literal so ADDING a language is a deliberate edit reviewed against #2904's
# "narrow and curated" constraint, never a side effect of a registry tweak.
EXTERNAL_ENTRY_POINT_LANGUAGES = {"makefile"}


def test_export_visibility_values_are_a_closed_set():
"""A typo in a registry must not silently mean `standard`.

`export_visibility` is read with a default, so a misspelt
`"external_entrypoints"` would take the default branch and the language
would go on being censused as dead code with nobody noticing -- or, worse,
a misspelt opt-in would silently fail to exempt a real external interface.
The set is closed here instead.
"""
for lang, defn in LANGUAGE_DEFINITIONS.items():
model = defn.get("export_visibility", EXPORT_VISIBILITY_STANDARD)
assert model in EXPORT_VISIBILITY_MODELS, f"{lang} declares an unknown export_visibility {model!r}"


def test_exactly_the_declared_family_opts_into_external_entry_points():
declared = {
lang for lang in LANGUAGE_DEFINITIONS if _declared_visibility(lang) == EXPORT_VISIBILITY_EXTERNAL_ENTRY_POINTS
}
assert declared == EXTERNAL_ENTRY_POINT_LANGUAGES, (
"the external-entry-point family changed; read #2904 before widening it -- the exemption is "
"only sound where the export construct is narrow and curated (makefile `.PHONY:`), not where "
"it decorates every symbol in the file (a JS/TS `export`), which would blind the #2774 "
"dead-exported-code census"
)


def test_the_family_is_opt_in_and_leaves_every_other_language_standard():
"""Every language NOT in the family reads as `standard` (the census-everything default)."""
for lang in LANGUAGE_DEFINITIONS:
if lang not in EXTERNAL_ENTRY_POINT_LANGUAGES:
assert _declared_visibility(lang) == EXPORT_VISIBILITY_STANDARD, (
f"{lang} is not in the external-entry-point family but does not read as standard"
)
86 changes: 86 additions & 0 deletions tests/core_engine/test_galaxyscope.py
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,92 @@ def test_contextual_baseline_fix_skips_already_declared_orphans(self):
f"{path}: #2536's raw snapshot must still hold the pre-adjustment orphan count",
)

# ==============================================================================
# TEST 17d: #2904 -- TIER-3 EXTERNAL-ENTRY-POINT RESCUE (makefile .PHONY)
# ==============================================================================
def test_contextual_baseline_fix_tier3_external_entry_points(self):
"""
#2904: a makefile is never imported (popularity is structurally 0), so the
tier-2 fix can never reach it and every `.PHONY:` entry point falls through
to tech debt. A language that opts in via `export_visibility:
external_entry_points` gets its DECLARED entry-point orphans
(`api_declared_orphans`) cleared from the census -- while a genuinely
internal, UNdeclared orphan stays real dead weight, and the raw census
survives in `raw_pre_adjustment`. `api` is NOT re-credited: a declared
entry point's declaration line is already an api-rule hit.
"""
scope = Orchestrator(".", self.mock_config)

scope.ram_cache = {
# bootos/Makefile's real shape: 3 orphans (all, clean, runqemu), all 3
# declared external entry points -> census clears to 0, api unchanged.
"asm/Makefile": {
"path": "asm/Makefile",
"coding_loc": 18,
"lang_id": "makefile",
"equations": {"api": 5, "unreferenced_by_name": 3},
"api_declared_orphans": 3,
"exports_are_external_entry_points": True,
"functions": [
{"name": "all", "usage_status": 1, "is_public": True},
{"name": "clean", "usage_status": 1, "is_public": True},
{"name": "runqemu", "usage_status": 1, "is_public": True},
],
},
# Mixed: 2 orphans, only 1 declared. The undeclared internal orphan
# (is_public False) must stay dead weight.
"asm/Internal.mk": {
"path": "asm/Internal.mk",
"coding_loc": 9,
"lang_id": "makefile",
"equations": {"api": 3, "unreferenced_by_name": 2},
"api_declared_orphans": 1,
"exports_are_external_entry_points": True,
"functions": [
{"name": "all", "usage_status": 1, "is_public": True},
{"name": "_secret", "usage_status": 1, "is_public": False},
],
},
# A language that did NOT opt in: unchanged, orphans stay as debt even
# though it too is never imported (popularity 0).
"src/lib.py": {
"path": "src/lib.py",
"coding_loc": 40,
"lang_id": "python",
"equations": {"api": 1, "unreferenced_by_name": 2},
"api_declared_orphans": 2,
"functions": [{"name": "helper", "usage_status": 1, "is_public": True}],
},
}
scope.stem_map = {k: k for k in scope.ram_cache}
scope.popularity_scores = dict.fromkeys(scope.ram_cache, 0) # nothing is imported

scope._calculate_risk_exposures()
by_path = {f.get("path"): f for f in scope.parsed_files}

# 1. All orphans declared: census cleared, api NOT re-credited, functions healed.
boot = by_path["asm/Makefile"]
self.assertEqual(boot["equations"]["unreferenced_by_name"], 0, "declared .PHONY orphans stayed as debt!")
self.assertEqual(
boot["equations"]["api"], 5, "tier-3 must not re-credit api (declaration is already an api hit)!"
)
self.assertEqual(boot["raw_pre_adjustment"], {"api": 5, "unreferenced_by_name": 3})
self.assertTrue(all(f["usage_status"] == 0 for f in boot["functions"]), "declared entry points not healed!")

# 2. Only the declared orphan is cleared; the internal one stays dead weight.
internal = by_path["asm/Internal.mk"]
self.assertEqual(
internal["equations"]["unreferenced_by_name"], 1, "undeclared internal orphan wrongly exempted!"
)
healed = {f["name"]: f["usage_status"] for f in internal["functions"]}
self.assertEqual(healed["all"], 0, "declared entry point not healed!")
self.assertEqual(healed["_secret"], 1, "internal undeclared orphan wrongly healed!")

# 3. A non-opted-in language is untouched, popularity 0 or not.
lib = by_path["src/lib.py"]
self.assertEqual(lib["equations"]["unreferenced_by_name"], 2, "a non-opted-in language must keep its census!")
self.assertEqual(lib["equations"]["api"], 1)

# ==============================================================================
# TEST 18: WORKER I/O ERRORS & BINARY THREAT ESCALATION
# ==============================================================================
Expand Down
Loading
Loading