Skip to content

chore(test): guard a plan against a single-exercise monoculture, and close #89 - #152

Merged
kilianmc merged 1 commit into
devfrom
chore/89-monoculture-guard
Sep 10, 2026
Merged

kilianmc merged 1 commit into
devfrom
chore/89-monoculture-guard

Conversation

@kilianmc

Copy link
Copy Markdown
Owner

Closes #89 as a non-defect, and keeps the part that is genuinely owed.

Why #89 closed

It tracked "~36 exercises carry ~80% of every plan" as a library concentration defect. Measured over 144 plans (both disciplines × three grade bands × 1–7 days/week × three weakness settings, crossed with a full-vocabulary and a bouldering-wall-only equipment column):

full vocabulary bouldering wall only
distinct rows a plan uses (median) 68 of 94 eligible 34 of 38 eligible
smallest head carrying 80% of blocks 36 18
head ÷ rows actually used 0.55 0.55
max single row, blocks / minutes 11.3% / 13.6% 14.8% / 10.9%

There is no concentrated head: an even spread over the rows a plan uses reads 0.80 and it reads 0.55. The head count is mostly set by the eligible pool, which the climber's equipment fixes, so it moves on a purchase rather than on a defect. Ruling 47 had already measured the one route to moving it — re-weighting the rotation — as moving presence, not proportion, because a 2-session week reads only 2 of 16 ring positions.

A hypothesis worth recording as dead: the head is not floored by progression arithmetic. progressed() takes no history and no plan argument and the dose is a pure function of the week's ordinal, so 68.3% of (block, exercise) pairs appear in exactly one week of their block. Nothing requires a row to repeat.

What ruling 55 keeps

PR #120 fixed a real monoculture at its cause, and nothing pinned the result — no test in the repo asserted a per-plan single-exercise share, so a library or ranking edit could have walked it back silently.

test_no_single_exercise_DOMINATES_a_plan asserts a per-plan ceiling on the single largest exercise over the existing twelve-row sweep × six session counts × three weaknesses = 216 plans: 17% of blocks, 23% of seconds. Both halves, because #120 stated its result in minutes while #89's metric was blocks. OPEN_CLIMBING_KEYS is out of numerator and denominator — those blocks arrive as ruling 27's length fill by ruling 29's decision.

Shown to fail

Narrowing prescribable() to one row per cell — the generalised pre-#120 condition — puts limit_boulders at 17.50% of blocks and 30.78% of minutes, over both ceilings, on all twelve rows. Freezing the rotation instead stays green, which is the useful negative: pool narrowness makes a monoculture, rotation order does not. The worst case in both eras is the narrow-equipment column, so a full-vocabulary-only sweep would have been green for the wrong reason.

Known limit, accepted deliberately: on the blocks half the window is narrow (14.85% today, 17.50% under total collapse, ceiling 17%), so that half fires only on near-total collapse and the detection headroom lives in the minutes half. Tightening it would turn red on a benign re-dose, which is why the measured maxima are narrated in the docstring rather than asserted.

Scope

Tests only. No product code, and no new sweep, plan builder or minutes helper — both arms read generate() output through the file's own _input and _block_seconds. npm run check:server green, 1451 passed.

🤖 Generated with Claude Code

…lose #89

Issue #89 tracked "~36 exercises carry ~80% of every plan" as a library
concentration defect. Measured over 144 plans, that metric is not one: no
exercise exceeds 15% of a plan's blocks or 14% of its minutes, 80% of the
blocks sit on 55% of the rows a plan uses where an even spread reads 80%, and
the head count is mostly set by the eligible pool — 94 rows with full gear
against 38 on a bare bouldering wall — so it moves on a purchase rather than
on a defect. Ruling 47 had already priced the one route to moving it.

Closed as a non-defect by ruling 55, which keeps the part that IS owed: PR
#120 fixed a real monoculture at its cause and nothing pinned the result, so a
library or ranking edit could have walked it back silently.

The guard asserts a per-plan ceiling on the single largest exercise over the
existing twelve-row sweep at six session counts and three weaknesses, 216
plans: 17% of a plan's blocks and 23% of its seconds. Both halves, because
#120 stated its result in minutes while #89's metric was blocks, and a ceiling
on one leaves the other free to regress. `OPEN_CLIMBING_KEYS` is out of both
numerator and denominator — those blocks arrive as ruling 27's length fill by
ruling 29's decision, so counting them would measure a ruling, not a defect.

Shown to fail, not assumed to: narrowing `prescribable()` to one row per cell
— the generalised pre-#120 condition — puts `limit_boulders` at 17.50% of
blocks and 30.78% of minutes, over both ceilings, on all twelve rows. Freezing
the rotation instead stays green, which is the useful negative: pool narrowness
makes a monoculture, rotation order does not. The worst case in both eras is
the narrow-equipment column, so a full-vocabulary-only sweep would have been
green for the wrong reason.

Tests only — no product code changes, and no new sweep, plan builder or minutes
helper: both arms read `generate()` output through the file's own `_input` and
`_block_seconds`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
climb-trainer Ready Ready Preview Sep 10, 2026 8:00pm UTC

@kilianmc
kilianmc merged commit 3e8c951 into dev Sep 10, 2026
5 checks passed
@kilianmc
kilianmc deleted the chore/89-monoculture-guard branch September 10, 2026 20:02

This branch was successfully deployed

1 active deployment
Preview — 8c2d6748 Deployed Sep 10, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant