Role-split scarcity blend and advisory short-window floor (issue #71, D-037) #72

Merged
adrian.tkacz merged 1 commit from feature/role-split-scarcity-blend into develop 2026-09-13 10:20:16 +00:00
Member

Closes #71. Implements decision D-037 (docs/decisions.md).

What changed

The D-026 aggregation merged all applicable windows with one most-restrictive rule (effective = min(remaining)), so 5h=80%/weekly=20% and 5h=20%/weekly=80% tied artificially, and a drained short window hid a healthy weekly one. D-037 splits windows into frozen roles and blends them:

  • Strategic (long-horizon health): kind: weekly, plus unknown-kind token windows conservatively.
  • Tactical (work-right-now): kind: five_hour and resource: time (Z.ai TIME_LIMIT).

Each role is represented by its most restrictive remaining across bound scopes; the blend uses the owner's frozen planning assumption weekly = 5 × five-hour:

effective_remaining_percent = (tactical + 5 * strategic) // 6
penalty_units               = (100 - effective)^2   # scale 10000, unchanged

Missing roles default to the other role's value (single-role candidates blend to exactly their own percentage).

Owner case table (pinned by tests):

tactical / strategic effective penalty
80 / 20 30 4900
20 / 80 70 900
5 / 95 80 400 — preferred ✓
95 / 5 20 6400

Plus the advisory short-window floor: SelectorPolicy.short_window_floor_percent (additive optional, default 10, 0 disables) flags eligible known-capacity candidates whose tactical representative is below the floor (short_window_below_floor, serialized only when true) with a human warning. Advisory only — it never demotes, excludes or rewrites ranking.

Unchanged

  • Ranking key order (knowledge class → happy-hour → penalty → margin → effort → preference → identity).
  • 0% exhaustion excludes in every role; unknown telemetry stays non-numeric; reservations, replenishment, blackouts, happy hours untouched.
  • Provider adapters (roles derive from already-normalized resource/kind), catalog ratings, REST/MCP schema versions.

Compatibility (D-032 discipline)

  • ScarcityAssessment gains additive strategic_window/tactical_window evidence; governing window = strategic representative when present, else tactical; blend consistency replaces governing-equality for known states. A serialized known assessment without role evidence fails loudly on the new reader — accepted per D-037 because decision deserialization is not an input boundary.
  • SelectorPolicy.short_window_floor_percent and the candidate flag serialize only when set; documents without them round-trip byte-identically.

Validation

  • uv sync --only-dev, make check (1006 tests + basedpyright 0 errors/warnings), git diff --check — all pass.
  • origin/develop..HEAD contains exactly one commit with this issue's change; no merge commits.

Human merge gate applies — do not merge before the bounded review lifecycle completes.

Closes #71. Implements decision **D-037** (`docs/decisions.md`). ## What changed The D-026 aggregation merged all applicable windows with one most-restrictive rule (`effective = min(remaining)`), so `5h=80%/weekly=20%` and `5h=20%/weekly=80%` tied artificially, and a drained short window hid a healthy weekly one. D-037 splits windows into frozen roles and blends them: - **Strategic** (long-horizon health): `kind: weekly`, plus unknown-kind token windows conservatively. - **Tactical** (work-right-now): `kind: five_hour` and `resource: time` (Z.ai `TIME_LIMIT`). Each role is represented by its most restrictive remaining across bound scopes; the blend uses the owner's frozen planning assumption **weekly = 5 × five-hour**: ```text effective_remaining_percent = (tactical + 5 * strategic) // 6 penalty_units = (100 - effective)^2 # scale 10000, unchanged ``` Missing roles default to the other role's value (single-role candidates blend to exactly their own percentage). Owner case table (pinned by tests): | tactical / strategic | effective | penalty | |---|---|---| | 80 / 20 | 30 | 4900 | | 20 / 80 | 70 | 900 | | 5 / 95 | 80 | 400 — preferred ✓ | | 95 / 5 | 20 | 6400 | Plus the **advisory short-window floor**: `SelectorPolicy.short_window_floor_percent` (additive optional, default 10, `0` disables) flags eligible known-capacity candidates whose tactical representative is below the floor (`short_window_below_floor`, serialized only when true) with a human warning. Advisory only — it never demotes, excludes or rewrites ranking. ## Unchanged - Ranking key order (knowledge class → happy-hour → penalty → margin → effort → preference → identity). - 0% exhaustion excludes in every role; unknown telemetry stays non-numeric; reservations, replenishment, blackouts, happy hours untouched. - Provider adapters (roles derive from already-normalized `resource`/`kind`), catalog ratings, REST/MCP schema versions. ## Compatibility (D-032 discipline) - `ScarcityAssessment` gains additive `strategic_window`/`tactical_window` evidence; governing window = strategic representative when present, else tactical; blend consistency replaces governing-equality for known states. A serialized known assessment without role evidence fails loudly on the new reader — accepted per D-037 because decision deserialization is not an input boundary. - `SelectorPolicy.short_window_floor_percent` and the candidate flag serialize only when set; documents without them round-trip byte-identically. ## Validation - `uv sync --only-dev`, `make check` (1006 tests + basedpyright 0 errors/warnings), `git diff --check` — all pass. - `origin/develop..HEAD` contains exactly one commit with this issue's change; no merge commits. Human merge gate applies — do not merge before the bounded review lifecycle completes.
Amends the D-026 aggregation: applicable windows are classified into
strategic (weekly, conservatively unknown-kind tokens) and tactical
(five_hour, resource time) roles, each represented by its most
restrictive remaining, and blended with the owner's frozen weekly =
5 x five-hour planning assumption:

    effective = (tactical + 5 * strategic) // 6   (integer, 0..100)

penalty/label remain the frozen pure functions of the blended effective.
A role with no known windows defaults its slot to the other role's
value, so single-role candidates blend to exactly their own percentage.
Owner cases pinned by test: 5h/w 80/20 -> 30 (4900), 20/80 -> 70 (900),
5/95 -> 80 (400, preferred), 95/5 -> 20 (6400).

SelectorPolicy gains the additive optional short_window_floor_percent
(default 10, 0 disables): eligible known-capacity candidates whose
tactical representative is below the floor carry the advisory
short_window_below_floor flag (serialized only when true) with a human
warning. The flag never demotes, excludes or rewrites ranking; 0%
exhaustion still excludes in every role; unknown telemetry stays
non-numeric. ScarcityAssessment gains additive strategic_window /
tactical_window evidence; the governing window is the strategic
representative when one exists, else the tactical one. Ranking key
order is unchanged. Known serialized assessments without role evidence
fail loudly on the new reader (accepted per D-037: decision
deserialization is not an input boundary).
Author
Member

Independent review — glm-5.3-max (bounded review lifecycle, one pass)

Reviewed commit d618fdc (git diff e3664c6..d618fdc) against the frozen scope of issue #71 / decision D-037. Ran independently on the review head: full test suite (1006 tests OK), uv run basedpyright (0 errors/0 warnings), git diff --check (clean), and an independent public-API re-derivation of the owner case table (80/20 → 30/4900, 20/80 → 70/900, 5/95 → 80/400, 95/5 → 20/6400 — all exact).

Findings:

  • [DEFER] scarcity_router/scarcity.py:654 — the known-state governing-equality rule is expressed as a pass-armed branch; style only, behavior verified correct (blend consistency validated separately; the legacy equality still guards the tactical-only and unavailable paths). No action this round.

No MERGE_BLOCKERs. Verified additionally: ranking-key isolation of the advisory flag (flag toggle alone leaves _ranking_key identical), additive byte-identical round-trips for documents without the new keys, role-evidence contract validation, purity of the diff (no new imports, no network/subprocess/credential patterns), and docs/decision-record consistency with the implementation.

VERDICT: APPROVE (0 blockers). Proceeding to the human merge gate; the PR stays open and is not merged by workers, reviewers or orchestrators.

**Independent review — glm-5.3-max (bounded review lifecycle, one pass)** Reviewed commit `d618fdc` (`git diff e3664c6..d618fdc`) against the frozen scope of issue #71 / decision D-037. Ran independently on the review head: full test suite (1006 tests OK), `uv run basedpyright` (0 errors/0 warnings), `git diff --check` (clean), and an independent public-API re-derivation of the owner case table (80/20 → 30/4900, 20/80 → 70/900, 5/95 → 80/400, 95/5 → 20/6400 — all exact). Findings: - [DEFER] `scarcity_router/scarcity.py:654` — the known-state governing-equality rule is expressed as a `pass`-armed branch; style only, behavior verified correct (blend consistency validated separately; the legacy equality still guards the tactical-only and unavailable paths). No action this round. No MERGE_BLOCKERs. Verified additionally: ranking-key isolation of the advisory flag (flag toggle alone leaves `_ranking_key` identical), additive byte-identical round-trips for documents without the new keys, role-evidence contract validation, purity of the diff (no new imports, no network/subprocess/credential patterns), and docs/decision-record consistency with the implementation. **VERDICT: APPROVE (0 blockers).** Proceeding to the human merge gate; the PR stays open and is not merged by workers, reviewers or orchestrators.
adrian.tkacz deleted branch feature/role-split-scarcity-blend 2026-09-13 10:20:16 +00:00
Sign in to join this conversation.
No description provided.