Skip to content
Open
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
5 changes: 3 additions & 2 deletions docs/METRICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ Always populated. These are the foundational signal/noise proxy.

**`stabilization_ratio`** — of all files touched in the window, the
fraction that had *no* subsequent modification within `churn_days` of any
prior touch. Files touched exactly once count as stabilized. Core quality
prior touch. Files touched exactly once count as stabilized. Core rework
signal: closer to `1.0` = changes persist; closer to `0.0` = constant
rework.
rework. Persistence means a file was not revisited within the window — it
is not evidence of correctness (unreviewed or defective code persists too).

**`churn_events`** — count of files modified 2+ times with at least one
consecutive pair of modifications ≤ `churn_days` apart.
Expand Down
2 changes: 1 addition & 1 deletion docs/ONE-PAGER.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ iris /path/to/repo --push
## Who It's For

- **Engineering leaders** who need to understand AI's impact on delivery quality
- **Platform teams** evaluating which AI tools produce the most durable code
- **Platform teams** understanding how AI-assisted changes hold up after they land
- **FinOps / compliance** preparing for EU AI Act requirements (August 2026)

---
Expand Down
12 changes: 6 additions & 6 deletions iris/i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
"finding_stabilization_high": (
"Stabilization ratio is {ratio} — "
"the majority of changes persisted without further modification. "
"This suggests durable delivery."
"Persistence indicates low rework, not verified correctness."
),
"finding_revert_high": (
"Revert rate is {rate} "
Expand Down Expand Up @@ -326,7 +326,7 @@
"Stabilization ratio per change type: "
"Feature {feat_ratio}, Fix {fix_ratio}, Refactor {refactor_ratio}. "
"Comparing stability across intents reveals which types of changes "
"produce durable outcomes and which require further iteration."
"are revisited soon after landing and which are not."
),

# CLI
Expand Down Expand Up @@ -430,7 +430,7 @@
"trend_finding_stabilization_up": (
"Stabilization improved by {delta}pp in the last {recent} days "
"compared to the {baseline}-day baseline. "
"This suggests delivery is becoming more durable."
"Less of the recent code is being reworked."
),
"trend_finding_churn_up": (
"Churn rate increased by {delta}pp recently. "
Expand Down Expand Up @@ -1007,7 +1007,7 @@
"finding_stabilization_high": (
"A taxa de estabilização é {ratio} — "
"a maioria das alterações persistiu sem modificação posterior. "
"Isso sugere entrega durável."
"Persistência indica pouco retrabalho, não correção verificada."
),
"finding_revert_high": (
"A taxa de revert é {rate} "
Expand Down Expand Up @@ -1206,7 +1206,7 @@
"Taxa de estabilização por tipo de mudança: "
"Feature {feat_ratio}, Fix {fix_ratio}, Refactor {refactor_ratio}. "
"Comparar a estabilidade entre intenções revela quais tipos de mudanças "
"produzem resultados duráveis e quais requerem iteração adicional."
"são revisitadas logo após entrarem e quais não são."
),

# CLI
Expand Down Expand Up @@ -1311,7 +1311,7 @@
"trend_finding_stabilization_up": (
"A estabilização melhorou {delta}pp nos últimos {recent} dias "
"comparado à baseline de {baseline} dias. "
"Isso sugere que a entrega está se tornando mais durável."
"Menos do código recente está sendo retrabalhado."
),
"trend_finding_churn_up": (
"A taxa de churn aumentou {delta}pp recentemente. "
Expand Down
92 changes: 92 additions & 0 deletions tests/test_i18n_parity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""Structural guards for the i18n string tables.

The narrative formats strings by key with named placeholders, so a key
missing from one language is a runtime KeyError and a placeholder missing
from one language is a runtime format error — neither is caught by any
other test. These guards fail before a report does.

The last test is a wording guard for Absolute Rule #4 (metrics are
hypotheses): the three stabilization strings must not infer durability from
persistence. Rewording them is a deliberate act — update that test in the
same change.

Runnable as a plain script: `python tests/test_i18n_parity.py`.
"""

import re
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from iris.i18n import get_strings

_LANGS = ("en", "pt-br")
_PLACEHOLDER = re.compile(r"\{(\w+)\}")


def _placeholders(text: str) -> set[str]:
return set(_PLACEHOLDER.findall(text))


def test_every_language_has_the_same_keys() -> None:
key_sets = {lang: set(get_strings(lang)) for lang in _LANGS}
reference = key_sets["en"]
for lang, keys in key_sets.items():
missing = reference - keys
extra = keys - reference
assert not missing, f"{lang} is missing keys: {sorted(missing)}"
assert not extra, f"{lang} has extra keys: {sorted(extra)}"


def test_every_key_has_the_same_placeholders_in_every_language() -> None:
en = get_strings("en")
mismatches = []
for lang in _LANGS[1:]:
other = get_strings(lang)
for key, text in en.items():
if not isinstance(text, str) or not isinstance(other.get(key), str):
continue
if _placeholders(text) != _placeholders(other[key]):
mismatches.append((key, lang, _placeholders(text), _placeholders(other[key])))
assert not mismatches, f"placeholder drift: {mismatches}"


def test_stabilization_findings_format_in_every_language() -> None:
# The keys rewritten to drop the durability over-inference must still
# accept exactly the arguments narrative.py passes them.
for lang in _LANGS:
s = get_strings(lang)
assert s["finding_stabilization_high"].format(ratio="85%")
assert s["finding_stabilization_low"].format(ratio="40%", unstable_pct="60%")
assert s["trend_finding_stabilization_up"].format(delta="3", recent=30, baseline=90)
assert s["explain_intent_stability_body"].format(
feat_ratio="80%", fix_ratio="60%", refactor_ratio="90%",
)


def test_stabilization_findings_do_not_claim_durability() -> None:
# Persistence is not evidence of correctness; the wording must not imply it.
for lang in _LANGS:
s = get_strings(lang)
for key in ("finding_stabilization_high", "trend_finding_stabilization_up",
"explain_intent_stability_body"):
assert "durable" not in s[key].lower(), (lang, key)
assert "durável" not in s[key].lower(), (lang, key)
assert "duráveis" not in s[key].lower(), (lang, key)


if __name__ == "__main__":
tests = [fn for name, fn in globals().items() if name.startswith("test_")]
failed = 0
for fn in tests:
try:
fn()
print(f"ok {fn.__name__}")
except AssertionError as exc:
failed += 1
print(f"FAIL {fn.__name__}: {exc}")
if failed:
print(f"\n{failed} failure(s)")
sys.exit(1)
print(f"\n{len(tests)} tests passed")
Loading