Skip to content
Merged
18 changes: 10 additions & 8 deletions .claude/skills/tri-comparison-ledger-sweep/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ has anything to act on) and do a **manual verification** instead:
correctly extracts this," and step 2b below is not optional:**
```python
from gitgalaxy.standards.language_standards import LANGUAGE_DEFINITIONS

rules = LANGUAGE_DEFINITIONS["<lang>"]["rules"]
text = open(path, encoding="utf-8", errors="replace").read()
for m in rules["func_start"].finditer(text):
Expand Down Expand Up @@ -241,11 +242,12 @@ against the same corpus file outside the pipeline (31/31 hits on one scheme file
every time, before writing down a granularity classification:
```python
import json

d = json.load(open("docs/self_scan/tri_comparison_ledger.json"))["entries"]
for k, e in d.items():
if k.startswith(f"{lang}/function/existence/") and e["still_reproduces"]:
print(k, e["status"], e["last_seen_count"]) # a real, unaddressed shape here means
# investigate THAT first, not args
# investigate THAT first, not args
```
A language with a real unvalidated existence-recall gap can't tell you anything meaningful about
its args granularity -- there aren't enough correctly-found functions to judge the shape of their
Expand Down Expand Up @@ -286,11 +288,9 @@ separately.

```python
import json

d = json.load(open("docs/self_scan/tri_comparison_ledger.json"))["entries"]
open_qs = [
(k, e) for k, e in d.items()
if e["still_reproduces"] and e["status"] != "validated"
]
open_qs = [(k, e) for k, e in d.items() if e["still_reproduces"] and e["status"] != "validated"]
open_qs.sort(key=lambda kv: -kv[1]["last_seen_count"])
```
Prioritize within that sorted list:
Expand Down Expand Up @@ -330,15 +330,17 @@ that could plausibly be affected -- functions, classes, and per-name args counts
one the ledger flagged:

```python
import sys; sys.path.insert(0, "tests/tools")
import sys

sys.path.insert(0, "tests/tools")
from tri_comparison_gatherer import gather_language

readings = gather_language("<lang>") # resolves the corpus the SAME way crucible_check.py does
for fr in readings:
gg_names = {o.name for o in fr.gg_funcs}
ts_names = {o.name for o in fr.ts_funcs}
missing = ts_names - gg_names # tree-sitter found, GitGalaxy MISSED -- a real recall gap
extra = gg_names - ts_names # GitGalaxy found, tree-sitter didn't -- over-detection
missing = ts_names - gg_names # tree-sitter found, GitGalaxy MISSED -- a real recall gap
extra = gg_names - ts_names # GitGalaxy found, tree-sitter didn't -- over-detection
if missing or extra:
print(fr.file_path, "missing_from_gg=", missing, "extra_in_gg=", extra)
# repeat the same set-diff for fr.gg_classes/fr.ts_classes, and diff .args per matched name
Expand Down
3 changes: 2 additions & 1 deletion docs/language_status/abap.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,10 @@ line into the comment stream before `detector.py` ever sees it. Isolated repro:
```python
from gitgalaxy.core.prism import Prism
from gitgalaxy.standards.language_standards import LENS_CONFIG, LANGUAGE_DEFINITIONS

p = Prism(LENS_CONFIG.get("COMMENT_DEFINITIONS", {}), LANGUAGE_DEFINITIONS)
result = p.split_streams("CLASS zcl_foo DEFINITION\n PUBLIC\n CREATE PUBLIC .\nENDCLASS.\n", "abap")
print(result["code_stream"]) # '\n PUBLIC\n CREATE PUBLIC .\nENDCLASS.\n' -- header line GONE
print(result["code_stream"]) # '\n PUBLIC\n CREATE PUBLIC .\nENDCLASS.\n' -- header line GONE
print(result["comment_stream"]) # 'CLASS zcl_foo DEFINITION' -- misclassified as a comment
```

Expand Down
2 changes: 1 addition & 1 deletion docs/wiki/08-03-transforming-regex-counts.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ A regex sees different amounts in different languages, so a raw count is not com
|---|---|---|---|
| **Our rules catch less in some languages.** A `safety` rule that fires 3 times on 2 planted constructs over-credits every hit. | Measured. keyword-rosetta plants identical defence in every language and records what each rule found. | $Fc_s = \min(1,\ planted_s / measured_s)$ per language **and per signal**, generated into `gitgalaxy/standards/fidelity_table.py`. Under-firing stays at 1.0 — that is a rule to fix, and a coefficient that compensates for a fixable gap is a way to stop fixing it. | the single per-language $Fc$, and `_calc_safety`'s `systems_buffer_ratio` |
| **This language lets you leave things unsaid.** Unenforced error paths, implicit globals, no memory safety, no static types. | The language specification — objective yes/no columns, checkable against documentation. | `analysis_lens.LANGUAGE_STRICTNESS`: one row per language; $Irc$ = number of gaps (0–4), $Ot = 1 + 0.1 \cdot Irc$. Data, markup and configuration formats have no runtime and carry **no** term. Dialects resolve through `LANGUAGE_FAMILY`. | the tier lists |
| **This file does runtime-dynamic things a regex cannot follow.** `eval`, reflection, dynamic dispatch. | The file — these are already registry signals, counted per file. | Per-file dynamism replaces the flat $Irc$ term in the six equations that read it (#2719, in progress). | the flat $Irc$ |
| **This file does runtime-dynamic things a regex cannot follow.** `eval`, reflection, dynamic dispatch. | The file — these are already registry signals, counted per file. | `SignalProcessor._dynamism()` = the file's `reflection_metaprogramming` count (`high_risk_execution` is the safety attack vocabulary and stays there), read by documentation (as risk) and cognitive load (as heat). Concurrency and state flux lost their language term outright; safety and tech debt keep the strictness $Irc$ with a stated reason each (#2719). | the flat $Irc$ in four of the six equations |

Two invariants bound the mechanism. $Irc$ *corrects* measured risk and never creates it: zero measured evidence scores zero in every language (#2655). And the weight on the strictness term is provisional — nothing in the system can validate a language-level shift yet (keyword-rosetta's null hypothesis *is* "no correction", the crucible has no risk labels), so #2720 pilots an outcome fixture before that weight is trusted with more than it carries now.

Expand Down
8 changes: 5 additions & 3 deletions docs/wiki/08-05-cognitive-load.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ $$\text{BranchDensity} = \min\left(\frac{\text{branch}}{M}, 0.5\right)$$
$$\text{FluxDensity} = \min\left(\frac{\text{state\_mutation}}{M} \times 2.0, 0.75\right)$$

2. **Sum Heavy Logic & Apply Gini Coefficient:**
$$\text{HeavyLogic} = (\text{concurrency} \times 3.0) + (\text{reflection} \times 5.0) + (\text{unsafe} \times 5.0)$$
$$\text{TotalDensity} = \left(\text{BranchDensity} + \text{FluxDensity} + \frac{\text{HeavyLogic}}{M} + \frac{Irc}{M}\right) \times \text{GiniMultiplier}$$
$$\text{HeavyLogic} = (\text{concurrency} \times 3.0) + (\text{dynamism} \times 5.0)$$
where $\text{dynamism}$ is the file's `reflection_metaprogramming` count (#2719) -- reflection, metaprogramming and dynamic dispatch, the code a reader cannot follow. `high_risk_execution` is not part of it: across the registry that signal is the safety attack vocabulary (`panic!`, `System.exit`, `STOP RUN`, `rm -rf`) and is read by [08-07](08-07-structural-fortification.md).
$$\text{TotalDensity} = \left(\text{BranchDensity} + \text{FluxDensity} + \frac{\text{HeavyLogic}}{M}\right) \times \text{GiniMultiplier}$$
The flat per-language $Irc / M$ pseudo-hit is gone (#2719): what it stood in for is the dynamism term above, measured per file.

3. **Map Through Sigmoid Curve:**
$$\text{RawScore} = \frac{100}{1 + e^{-4.0 \times (\text{TotalDensity} - 0.75)}}$$
Expand Down Expand Up @@ -74,4 +76,4 @@ Currently, the system relies on fixed heuristic weights and limits documentation
## Related Components
- Static Analysis Engine
- Path Modifier ($Mp$)
- Universal Framework Parameters ($Irc$, $Fc$)
- Universal Framework Parameters ($Fc_{doc}$ for the documentation cooling; no language-level $Irc$ since #2719)
5 changes: 3 additions & 2 deletions docs/wiki/08-09-documentation-risk.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ $$\text{UmbrellaDefense} = \text{doc\_umbrella} \times 50.0$$
$$\text{DefenseHits} = (\text{InlineDocs} \times Fc_{doc}) + (\text{Ownership} \times 0.5 \times Fc_{ownership}) + (\text{DocLOC} \times 0.33) + \text{UmbrellaDefense}$$
2. **Undocumented Risk Calculation:**
$$\text{UndocumentedRisk} = \sum_{\text{undocumented}} \left( 5.0 + \ln(\text{Impact}) \right)$$
$$\text{RiskHits} = \text{UndocumentedRisk} + (\text{API\_Exposure} \times 2.0) + Irc$$
$$\text{RiskHits} = \text{UndocumentedRisk} + (\text{API\_Exposure} \times 2.0) + \text{Dynamism}$$
$\text{Dynamism}$ = the file's `reflection_metaprogramming` count (`documentation.dynamism_weight`, 1.0): runtime-decided behaviour is what most needs documenting and what a reader cannot recover from the text. It replaces the flat per-language $Irc$ (#2719).
3. **Net Exposure & Line Density:**
$$\text{NetExposure} = \max\left(0, \text{RiskHits} - \frac{\text{DefenseHits}}{2.0}\right)$$
$$\text{Density} = \left( \frac{\text{NetExposure}}{\max(\text{LOC}, 50) + 20} \right) \times 100.0$$
The denominator is the UEF evidence-mass floor plus the equation's smoothing pad ([08-03](08-03-transforming-regex-counts.md)). $Irc$ corrects measured risk, it never creates it: when $\text{UndocumentedRisk} + \text{API\_Exposure} = 0$ the score is $0$ in every language (#2655).
The denominator is the UEF evidence-mass floor plus the equation's smoothing pad ([08-03](08-03-transforming-regex-counts.md)). Dynamism corrects measured risk, it never creates it: when $\text{UndocumentedRisk} + \text{API\_Exposure} = 0$ the score is $0$ whatever the file does at runtime (#2655).
4. **Systemic Multipliers & Mapping:**
$$\text{FinalMultiplier} = \left(1.0 + \frac{\text{Pop}}{10}\right) \times \left(1.0 + \frac{\text{Silo}}{200}\right) \times Mp$$
$$\text{RawRisk} = \frac{100.0}{1 + e^{-0.2 \times (\text{Density} - 10.0)}}$$
Expand Down
7 changes: 2 additions & 5 deletions docs/wiki/08-15-concurrency-exposure.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ The static analysis engine extracts concurrency keywords and synchronization pri
| `raw_concurrency` | Keywords | **1.0x** | Asynchronous and threading constructs: `async`, `await`, `Promise`, `thread`, `spawn`, `go`, `chan`, `synchronized`. |
| `sync_locks` | Mitigations | **-1.5x** | Synchronization primitives (mutexes, locks, semaphores). Each lock mitigates 1.5 thread spawns. |
| `loc` | Denominator | **Base Density** | Meaningful lines of code, padded by `loc_padding` (default 150). |
| `irc` | Language Modifier | **0.1x** | Implicit Risk Correction: the language's strictness-gap count (0–4) from `analysis_lens.LANGUAGE_STRICTNESS` ([08-03](08-03-transforming-regex-counts.md)); 0 for data and markup formats. |
| `mp` | Path Modifier | **Threshold Modifier** | Context-specific modifier (e.g., `0.5` for UI components where race conditions trigger UI defects). |

The calculation balances raw concurrency against synchronization locks and applies a sigmoid transformation.
Expand All @@ -32,9 +31,9 @@ $$\text{net\_concurrency} = \max(0.0, \text{raw\_concurrency} - (\text{sync\_loc
If $\text{net\_concurrency} = 0$, the metric immediately returns $0.0$.

### 2. Density Calculation
Density measures concurrent logic per line of code, factoring in implicit language risk ($\text{IRC} \times 0.1$):
Density measures concurrent logic per line of code. There is no language term (#2719): no strictness column is about concurrency and per-file dynamism is not concurrency -- the inputs are the file's own spawns and locks.

$$\text{Density} = \left( \frac{\text{net\_concurrency}}{\max(\text{LOC} + \text{loc\_padding}, 1)} \right) \times 100.0 + (\text{IRC} \times 0.1)$$
$$\text{Density} = \left( \frac{\text{net\_concurrency}}{\max(\text{LOC} + \text{loc\_padding}, 1)} \right) \times 100.0$$

### 3. Sigmoid Transformation
Maps density to a 0–100 score using a base threshold of $4.0$ and slope of $0.4$, scaled by the path modifier ($Mp$):
Expand All @@ -47,7 +46,6 @@ def _calc_concurrency(
self,
loc: int,
raw_signals: dict[str, int],
irc: int,
mp: float,
) -> float:
"""
Expand All @@ -67,7 +65,6 @@ def _calc_concurrency(
return 0.0

density = (net_concurrency / max(loc + loc_padding, 1)) * 100.0
density += irc * tuning.get("irc_mult", 0.1)

threshold = tuning.get("threshold_base", 4.0)
slope = tuning.get("sigmoid_slope", 0.4)
Expand Down
8 changes: 3 additions & 5 deletions docs/wiki/08-16-state-flux-exposure.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ The static analysis engine counts mutation keywords and immutability controls:
| `raw_flux` | `state_mutation` | **1.0x** | Reassignment and mutation keywords: `let`, `var`, `mut`, `setState`, `push`, `pop`, `+=`, `=`. |
| `freeze_hits` | `immutability_locks` | **-0.5x** | Immutability enforcements (`Object.freeze`, const locks). Subtracts 0.5 per hit from raw mutation. |
| `loc` | Denominator | **Base Density** | Meaningful lines of code (`loc_padding` defaults to 0 to ensure mutations immediately impact density). |
| `irc` | Language Modifier | **0.15x** | Implicit Risk Correction: the language's strictness-gap count (0–4) from `analysis_lens.LANGUAGE_STRICTNESS` ([08-03](08-03-transforming-regex-counts.md)); 0 for data and markup formats. |
| `mp` | Path Modifier | **Threshold Modifier** | Context modifier (e.g., `0.8` for UI components where state spaghetti introduces UI state bugs). |

### 1. Net Volatility Calculation
Expand All @@ -30,9 +29,9 @@ $$\text{net\_volatility} = \max(0.0, \text{raw\_flux} - (\text{freeze\_hits} \ti
If $\text{net\_volatility} = 0$, the function returns $0.0$.

### 2. Volatility Density
Calculate mutation density per line of code, adding the dampened language risk ($\text{IRC} \times 0.15$):
Calculate mutation density per line of code. There is no language term (#2719): "implicit mutability defaults" is not a strictness column and dynamism is not mutation -- the inputs are the file's own writes and immutability locks.

$$\text{Density} = \left( \frac{\text{net\_volatility}}{\max(\text{LOC}, 50) + \text{loc\_padding}} \right) \times 100.0 + (\text{IRC} \times 0.15)$$
$$\text{Density} = \left( \frac{\text{net\_volatility}}{\max(\text{LOC}, 50) + \text{loc\_padding}} \right) \times 100.0$$
$\max(\text{LOC}, 50)$ is the UEF evidence-mass floor ([08-03](08-03-transforming-regex-counts.md)): two mutations in a 10-line file no longer read as 20% volatility (#2655).

### 3. Sigmoid Normalization
Expand All @@ -42,7 +41,7 @@ $$\text{RawScore} = \frac{1.0}{1.0 + e^{-0.2 \times (\text{Density} - 15.0)}}$$
$$\text{FinalScore} = \min(\text{RawScore} \times 100.0 \times Mp, 100.0)$$

```python
def _calc_state_flux(self, loc: int, raw_signals: dict[str, int], irc: int, mp: float) -> float:
def _calc_state_flux(self, loc: int, raw_signals: dict[str, int], mp: float) -> float:
"""
Calculates State Flux Exposure & Mutation Volatility.
"""
Expand All @@ -59,7 +58,6 @@ def _calc_state_flux(self, loc: int, raw_signals: dict[str, int], irc: int, mp:
return 0.0

density = (net_volatility / max(loc + loc_padding, 1)) * 100.0
density += irc * tuning.get("irc_mult", 0.15)

threshold = tuning.get("threshold_base", 15.0)
slope = tuning.get("sigmoid_slope", 0.2)
Expand Down
Loading
Loading