release: v11.2.0 — per-aspect volume, the monoculture guard, and Dependabot for security only - #155
Merged
Merged
Conversation
chore: back-merge v11.0.0 into dev
Closes the surviving half of planned PR #17. The send pyramid died with ascent logging and the sRPE trend dies with the pending RPE removal, so per-aspect volume is the one progress view left. `GET /api/sessions/volume` counts `logged_set` rows per (training day x aspect) in one statement and folds them server-side to ten totals. The per-day rows never reach the wire: a series with no reader is the orphaned-wire-field shape the register already tracks. Two things it deliberately does not do: - It reports SETS, not minutes. `activity.duration_minutes` is session-level over a session that mixes aspects, `session_block` snapshots no aspect, and `logged_set.actual_work_seconds` is nullable, so summing seconds would undercount every rep-based exercise while looking like a total. - Bars are shares of the busiest aspect, never of a target. Nothing prescribes an aspect's volume, so reusing `ProfileProgress` and its `aria-valuemax` would assert a goal the generator never made. The read adopts `server/journal`'s settled cap pattern — `LIMIT cap + 1` and a strict `>` — so `truncated` is exact rather than a false positive on a window holding exactly the cap. It goes one step further than `_fold_sessions`: a day the cap split is dropped WHOLE, because `truncated` promises "older training is missing" and cannot say "one of these totals is short". Ten aspects is past where a colour per series stays legible, so they are table rows with one hue and the count as text in every row. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
feat(progress): count logged sets per climbing aspect on the dashboard
…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>
chore(test): guard a plan against a single-exercise monoculture, and close #89
…t version the mount survives #144's bump is a version update with no advisory behind it, and its `web` job fails: `@tanstack/react-router` 1.170.33 retypes a boundary's `error` as `unknown` (TanStack #8209), which `RouteError` declared as `Error`. Two things came out of taking it seriously. The error component was lying about what it receives. The router preserves falsy throws, so `0`, `false`, `''`, `null` and a plain object all reach the boundary; the old `{error.message}` crashed outright on `null` and rendered an empty line for the rest. `errorText()` narrows for real — no cast, no `any` — and falls back to a sentence a user can read. Nine cases in `web/src/ui/routeError.test.tsx` go through the render, not the helper: eight of them fail against the previous `(error as Error).message`. The pin is the other half, and it is NOT what dependabot proposed. Latest stable is 1.170.35 / 1.168.37, verified against the registry, and the pair cannot be split: router-plugin 1.168.37 peers `^1.170.34`. From 1.170.34 (TanStack #8308) the router classifies any href carrying a scheme as an external link and returns a bare anchor with no `onClick` — and `createRemoteHistory` sets `createHref` to an absolute standalone URL by construction (issue #16), so every left-click in the federated mount would leave kilianmc.com instead of navigating in place. `remote.guard.test.tsx` catches it: 1.170.33 green, 1.170.34 red. So both packages are pinned EXACTLY rather than with a caret, because `^1.170.33` permits the version that breaks the mount. The prohibition sits on the `createHref` assignment that causes it, the guard test points at that line, and the docstring's claim that left-clicks are unaffected is now bounded by the version it stops being true at. Reworking issue #16's absolute-href mechanism is what would unblock 1.170.35. That is not this PR. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
chore(deps): supersede dependabot #144, pinning the router at the last version the mount survives
…y only Kilian believed every Dependabot PR was a security alert. They were not: this config scheduled weekly VERSION updates across three ecosystems, and that is where #137, #138 and #144 came from. #144 carried no advisory and broke the web build. Alerts and security PRs are a repo-level setting, already enabled and untouched by this change, so advisories still arrive automatically. There is no version-updates opt-out short of removing the config, so the file goes. It is read from the default branch only, so this takes effect when `dev` is next promoted. Deleting it would have left two lines in `CLAUDE.md` false: - one cited the config as a path, which the path arm of `test_claude_md_claims.py` would have caught. Its subject — a class of file read only from `main` — is still true, and `workflow_dispatch` registration is another member, so the line keeps the doctrine and drops the example. - "SOME pinned action SHAs Dependabot can never bump" implied the rest were handled. Nothing is now bumped on a schedule, and only an advisory can move an action pin, so the line says every pin is checked by hand. The config's two `ignore` rules were holds, and a prohibition may not be deleted with the file that carried it. The `typescript` hold is already stated at `CLAUDE.md:64` and needed nothing. The `@types/node` hold had no home in the tree — only PR #6's commit body and an archived reason — so it becomes `tests/test_node_types_pin.py`, which asserts the `@types/node` major equals the `.nvmrc` runtime major. A guard rather than a tripwire line, because the claim is executable: staleness is the correct state here, nothing else in the repo objects to a newer major, and a hold nothing enforces is one the next reader "fixes". Shown to fail at `^26.0.0`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
chore: stop scheduled version updates, keeping Dependabot for security only
…ndabot for security only A minor rather than a major: one user-visible feature and two pieces of housekeeping, which is what the bump is meant to track. - the dashboard counts logged sets per climbing aspect (#151) - issue #89 closes as a non-defect, and ruling 55 pins what PR #120 actually won: no single exercise may take more than 17% of a plan's blocks or 23% of its minutes (#152) - `@tanstack/react-router` is pinned exactly at 1.170.33, the last version where the federated mount still navigates in place, and the error boundary now handles a non-`Error` throw instead of crashing on it (#153) - Dependabot no longer opens scheduled version-update PRs; alerts and security updates are a repo setting and are unaffected. This is the promotion that makes that live, since the config is read from `main` (#154) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promotes
devto production. v11.0.0 → v11.2.0, a minor: one user-visible feature plus housekeeping, which is what the bump is meant to track rather than defaulting to major.What ships
Dashboard: logged sets per climbing aspect (#151) — the per-aspect volume view.
Issue #89 closes as a non-defect, and ruling 55 pins what PR #120 won (#152). "~36 exercises carry ~80% of every plan" turned out not to be a defect: measured over 144 plans there is no concentrated head (80% of 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, which the climber's equipment decides. What was unguarded is that #120's monoculture fix could regress silently — so no single exercise may now exceed 17% of a plan's blocks or 23% of its minutes, shown to fail by narrowing the candidate pool.
Router pinned at the last version the federated mount survives (#153). From
@tanstack/react-router1.170.34 the router treats a scheme-carrying href as external and drops itsonClick;createRemoteHistoryproduces exactly such hrefs by construction (issue #16), so the mount would leave kilianmc.com on every left-click. Pinned exactly at 1.170.33 — a caret permits the breaking version. The same release retyped boundary errors asunknown, which surfaced a real bug: the error component crashed on anullthrow and rendered blank for anything that was not anError.Dependabot stops opening scheduled version-update PRs (#154). Alerts and security updates are a repo-level setting and are untouched — advisories still arrive automatically. This promotion is what makes it live, since the config is read from the default branch.
Verification
CI green on each PR into
devindividually, and green on this branch. No migration owed — DB0008is unchanged.GENERATOR_VERSIONunchanged at 9.0.0: nothing here alters plan generation, and the monoculture arm only measures it.Known limits, carried deliberately
🤖 Generated with Claude Code