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
7 changes: 6 additions & 1 deletion docs/playbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,12 @@ planted cases first and refuses a run that scored no template.
step 9, allows
2. After improving a template, run `--update` and commit the raised rows
with the change. Never lower a row by hand
3. A new template scores 70 or above, or CI fails it until it is rewritten
3. Every upstream template scores 95 or above, row or no row; CI fails one
below it. A fork's template answers to its row, and a new one to the
new-file floor of 70
4. Raise a template under 95 by its prose: one instruction per rule, short
lead-ins, and each pass condition stated as rules beside its command.
Never change the scorer to pass a file

## Run the test suite

Expand Down
7 changes: 4 additions & 3 deletions tests/baselines/template-quality.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Template quality scores, recorded by `py tools/score_templates.py --update`.
# `--check` fails a template scoring below its row here, a template with no
# row scoring below the new-file floor, and a row naming no template. Raise
# a row by improving the template and re-recording; never lower one by hand.
# `--check` fails a template scoring below its row here, an upstream template
# below 95, a template with no row below the new-file floor, and a row naming
# no template. Raise a row by improving the template and re-recording; never
# lower one by hand.
templates/backend/api.md 100.0
templates/backend/auth.md 98.4
templates/backend/caching.md 100.0
Expand Down
27 changes: 22 additions & 5 deletions tools/score_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
# file is recorded on purpose with --update, never by accident.
NEW_FILE_FLOOR = 70

# Every upstream template scores this or above, with or without a row. A
# fork's templates answer to their own rows and the new-file floor only.
UPSTREAM_FLOOR = 95

# Scores are rounded to one decimal; a drop smaller than this is noise from
# rounding, not a regression.
TOLERANCE = 0.1
Expand Down Expand Up @@ -375,9 +379,10 @@ def write_baseline(path, rows, header):

BASELINE_HEADER = """\
# Template quality scores, recorded by `py tools/score_templates.py --update`.
# `--check` fails a template scoring below its row here, a template with no
# row scoring below the new-file floor, and a row naming no template. Raise
# a row by improving the template and re-recording; never lower one by hand.
# `--check` fails a template scoring below its row here, an upstream template
# below 95, a template with no row below the new-file floor, and a row naming
# no template. Raise a row by improving the template and re-recording; never
# lower one by hand.
"""


Expand All @@ -387,11 +392,14 @@ def unmoved_baselines():
for old, new in MOVED_BASELINES.items() if old.exists()]


def check(scores, baseline, fork_baseline):
def check(scores, baseline, fork_baseline, upstream=()):
"""Findings for the ratchet: each a line naming the file and why."""
findings = []
recorded = {**baseline, **fork_baseline}
for name, value in sorted(scores.items()):
if name in upstream and value < UPSTREAM_FLOOR - TOLERANCE:
findings.append(f"{name}: {value:.1f} below the upstream floor "
f"{UPSTREAM_FLOOR}")
if name in recorded:
if value < recorded[name] - TOLERANCE:
findings.append(f"{name}: {value:.1f} below its baseline "
Expand Down Expand Up @@ -489,6 +497,13 @@ def self_test():
cases.append(("the ratchet fails a drop, a new file under the floor and "
"a stale row, and passes a rounding drift",
named == expect, sorted(named)))
floored = check({"up": 94.0, "edge": 94.95, "fork": 80.0},
{"up": 94.0, "edge": 94.95}, {"fork": 80.0},
upstream={"up", "edge"})
named = {f.split(":")[0] for f in floored}
cases.append(("the upstream floor fails an upstream file under 95 even "
"at its row, and spares a fork's file and a rounding drift",
named == {"up"}, sorted(named)))
failed = 0
for label, ok, value in cases:
print(f" {'PASS' if ok else 'FAIL'} {label} ({value})")
Expand Down Expand Up @@ -604,8 +619,10 @@ def main(args):
if not scores:
print("templates scored: 0 -- refusing: nothing was measured")
return 1
manifest = (TEMPLATES / "manifest.yaml").read_text(encoding="utf-8")
findings = check(scores, read_baseline(BASELINE),
read_baseline(FORK_BASELINE))
read_baseline(FORK_BASELINE),
upstream_files(manifest))
print(f"templates scored: {len(scores)}")
print(f"findings: {len(findings)}")
for finding in findings:
Expand Down
Loading