Skip to content

Release → main: v1.0.2 — restore all 29 baseline models (#85) - #96

Merged
Polichinel merged 10 commits into
mainfrom
development
Sep 9, 2026
Merged

Polichinel merged 10 commits into
mainfrom
development

Conversation

@Polichinel

Copy link
Copy Markdown
Contributor

Release PR for v1.0.2. 9 commits, development → main.

Why this release exists

Every baseline model in views-models has been unrunnable since 2026-08-02. views-pipeline-core retired the synthesised targets config key (#380); catalog.py kept reading it; every get_model() raised KeyError: 'targets'. All 29 models. views-models installs views-baseline from PyPI, so nothing reaches the team until this publishes.

What is in it

Stories S1–S6 of epic #85 (PR #94), plus the version bump:

  • catalog.py reads regression_targets, derived once behind a property
  • regression_targets and level promoted to CORE_GENOME; empty values now rejected
  • New conformance suite building all 7 models from configs verified against pipeline-core's own CoreConfigSniffer
  • CI resolves again ([tool.uv] environments) — first green Lint and Test since 2026-08-02
  • ADR-009, three CICs and the risk register reconciled

248 → 295 tests passing. ruff clean. validate_docs.sh green. A /code-review max pass ran before merge; 11 findings fixed, 5 registered (C-48…C-52).

Also the first installable release

1.0.0 and 1.0.1 were published while views-pipeline-core>=3.0.0 had no PyPI release, so they resolved for nobody (C-38). pipeline-core reached PyPI 2026-08-03. The clean-room install-back in docs/guides/publishing-to-pypi.md §A has therefore never been exercised — it will be, as part of this release.

Known and deliberate

  • Python 3.12/3.13 are not installable (viewser → pandas<2, no wheels above cp311). Pre-existing, not a regression; CI matrix narrowed to 3.11 and registered as C-47. requires-python metadata deliberately left alone.
  • views-models#459 (floor bump ×29 + smoke-test fix) lands after this publishes.

After merge

gh release create v1.0.2 --target main triggers the publish workflow (Trusted Publishing, OIDC).

🤖 Generated with Claude Code

https://claude.ai/code/session_01PoczAeeAcC81UVMGMSiAvS

Polichinel and others added 10 commits September 9, 2026 11:09
…CORE_GENOME

views-pipeline-core retired the synthesised `targets` config key on 2026-08-02
(507ae11, refs #380/#381, shipped in 3.0.0) and migrated its own 13 read sites.
views-baseline was never swept, so catalog.py kept reading config["targets"] at
seven sites and every get_model() raised KeyError. All 29 baseline models in
views-models have been unrunnable since that date.

The suite could not catch it: tests/conftest.py manufactured the retired key, so
248 tests passed against a config shape that cannot exist in production — and
which pipeline-core's combined_targets() now actively raises on. The fixture, not
the dependency, defined the contract. Migrating the fixtures first turns 34 tests
red with the production KeyError; the catalog fix turns them green.

The target list is derived once in __init__ rather than re-read at each of the
seven factory sites, so the next rename of the platform's target vocabulary is one
edit. combined_targets() is deliberately not called: catalog.py sits under model/,
which ADR-013 forbids from importing views-pipeline-core at module level, and
passing targets down from the manager would leave one of seven config keys
arriving by a different mechanism than the other six. classification_targets is
not read — 0 of 29 baseline configs declare one, and the decision when one does is
per-model, not catalog-wide.

regression_targets and level are promoted to CORE_GENOME so their absence is a
named contract violation at the boundary rather than a bare KeyError deeper in.
ADR-009 recorded this exact gap as accepted debt in March 2026; it is what the
outage was made of. Verified against all 29 shipped configs before promoting
(29/29 declare both), so no coordinated views-models change is required — unlike
the C-24 seed promotion.

Two guards added after the #89 mutation audit found that deleting either new key
from CORE_GENOME left the whole suite green. They assert the keys by name:
a test parametrized over CORE_GENOME cannot catch a key being removed from it,
because the parametrize list simply shrinks.

Tightening two loose `match="steps"` assertions exposed a pre-existing defect: one
config omitted prediction_format while its own comment claimed only steps was
missing. The substring match had concealed that.

Refs #85. Closes #84, #86, #87, #89.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoczAeeAcC81UVMGMSiAvS
The conformance check that did not exist on 2026-08-02, and whose absence let
every baseline model stay dead for five weeks.

Seven configs copied from the shipped views-models baselines — zero_pgmbaseline,
locf_pgmbaseline, average_pgmbaseline, light_strider, black_ranger,
doctorish_dwarf (nb/none), bashful_dwarf (gamma/log1p) — merged the way
get_combined_config merges them, with provenance and a refresh note in the
docstring. Copied, never imported: nothing here reads across the views-models
boundary.

Per algorithm: audit_manifest accepts it, get_model constructs the right class,
model.targets matches regression_targets, the target list is not aliased from the
config, and the fixture carries no retired evaluation key — the property the old
conftest fixture violated, and the reason a guard built on it proved nothing.
test_every_catalogued_algorithm_has_a_conformance_fixture fails if an algorithm is
added without a real config, so the guard cannot silently shrink as the catalog
grows.

Verified by reverting the catalog fix: 15 of 29 tests fail.

No importorskip. The story proposed following the test_ensemble_consumption idiom,
but this needs only the catalog and the gate, both numpy-only at import; skipping
it where views_frames is absent would make it a no-op in exactly the environment
(CI) where it matters most.

Known limitation, stated in the docstring: a checked-in copy can drift. It catches
a key rename — the failure that happened — not a value change.

pipeline-core's own governance puts this check here: it registered the blindness
(C-289, "cannot see a consumer") and its conformance suite explicitly exempts
views-baseline.

Refs #85. Closes #88.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoczAeeAcC81UVMGMSiAvS
CI has been red since 2026-08-02. The header note in run_tests.yml blamed
views-pipeline-core not being on PyPI, and said the workflow was expected red
until it published. pipeline-core 3.0.0 published on 2026-08-03 — the day after —
and the workflow was never re-run, so the note went stale and the real cause went
unseen. Re-running it now (run 34331888893) takes 2m22s instead of the old 13s:
lint and build pass, and check fails for a different reason entirely.

  Because pywin32{sys_platform == 'win32'}==227 has no wheels with a matching
  Python version tag (e.g. cp311) and docker>=5.0.0,<=5.0.3 depends on
  pywin32==227 ... and viewser>=6.6.4 depends on docker>=5.0.0,<6.0.0 ...
  and views-pipeline-core>=3.0.0 depends on viewser>=6.6.4 ...
  your project's requirements are unsatisfiable.

uv resolves a universal lockfile across every platform its markers admit,
including win32, so the win32 split fails on Linux CI for a platform CI never
runs on. Publishing pipeline-core would not have fixed this; the workflow would
have stayed red and nobody would have known, which is the same silence that hid
the retired-key outage.

[tool.uv] environments = ["sys_platform == 'linux'"] is uv's own documented remedy
— it is the hint uv emits. Verified locally: uv lock --python 3.11 resolves 118
packages in 1.32s, previously unsatisfiable. The published wheel is unaffected: it
stays py3-none-any. This bounds the dev/CI resolution, not the distribution.

No lockfile is committed. That would make CI deterministic and is arguably worth
doing, but it is a separate decision with its own maintenance cost and belongs to
#26.

Refs #85. Closes #90.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoczAeeAcC81UVMGMSiAvS
…igration

ADR-009's "what is not validated" bullet is struck through rather than deleted.
What it recorded is the most useful thing in the document: in March 2026 it
predicted, precisely, the failure that arrived in August — a KeyError from inside
a factory method rather than from the validation check, with the audit reporting
success one line earlier. Accepted debt in a boundary contract is a prediction,
not an observation. Deleting it would erase the evidence that the register worked
and the follow-through did not.

Also in ADR-009: the MODEL_GENOMES snippet was stale twice over (it predated seed
and both parametric algorithms), Boundary 2's mapping now reads regression_targets,
and the gap table narrows to value-ranges.

CICs: BaselineModelCatalog (parameter and error tables, all usage examples,
evolution notes, known deviations), ReproducibilityGate (CORE_GENOME verbatim, and
four examples that were wrong — the "passes silently" one omitted
prediction_format and would have raised), BaselineForecastingModelManager (three
configs and the self.config contract row). One deviation is now partly fixed and
the CIC says exactly how much: post-construction config mutation still reaches the
model-specific keys read lazily in get_model(), but no longer reaches targets,
which are copied in __init__. Documented as partial rather than quietly upgraded.

Register: C-42's tier is corrected in public. It was registered hours earlier as
Tier 3 "diagnostics" with a hypothetical trigger; it was a live outage whose
trigger had fired five weeks before. The entry records why it was mis-read —
presence was assumed because the fixture supplied it, which is the trap C-44
describes one entry earlier. C-38's discharge condition is met (pipeline-core
3.0.0 on 2026-08-03 through 3.2.0 on 09-08). C-44 gains the confirmed instance.

publishing-to-pypi.md: the dependency-not-on-PyPI warning is now historical, and
the pending-publisher setup step is marked as done — views-baseline has been on
PyPI since 2026-07-31.

Noted, not fixed: docs/validate_docs.sh still never checks that a source path
cited by a doc exists on disk. That is why the epic #47 reorg left eight ADRs
pointing at deleted files. It stays C-40's job.

Refs #85. Closes #91.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoczAeeAcC81UVMGMSiAvS
…ort claim

The first CI run of the #85 branch got far enough to resolve dependencies and
revealed a second, unrelated blocker: views-pipeline-core -> viewser 6.6.4 pins
pandas<2.0.0, and pandas 1.5.3 (the last 1.x) publishes wheels for cp38-cp311
only. On 3.12/3.13 the resolver must build pandas from source and fails with
ModuleNotFoundError: No module named 'pkg_resources'.

views-baseline therefore cannot be installed on Python 3.12 or 3.13 at all. This
is not a regression from this epic — it has been true since the >=3.0.0
pipeline-core floor was adopted, and only became visible now that CI resolves far
enough to hit it.

pyproject.toml still declares requires-python = ">=3.11,<3.14" and 3.12/3.13
classifiers. That claim is false, and it is registered as C-47 rather than quietly
narrowed: what a distribution claims to support is a release decision with
downstream visibility, the constraint lives two hops upstream, and narrowing then
re-widening requires-python across releases is worse than stating the gap once.

The matrix is narrowed instead, so CI is honestly green rather than permanently
two-thirds red — a permanently-red pipeline being the exact condition that let the
retired-key outage survive five weeks unnoticed. Restore the full matrix when
viewser drops the pandas<2 pin.

Refs #85, #90.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoczAeeAcC81UVMGMSiAvS
…value holes

Review of #94 found that the rename silently disabled the guard that exists to
catch exactly this class of bug, plus two validation holes the PR's own ADR-009
edit declares closed.

1. The C-10 forwarding guard stopped checking `targets` (finding 1). It skips any
   constructor param whose name is not a config key, and the config key had just
   been renamed, so `targets` fell out of the loop while the test stayed green —
   a test whose own failure message names "a silently dropped parameter (C-10
   class)". Fixed with an explicit param->config-key map. Verified by mutation:
   dropping targets from a builder now fails the guard.

2. `regression_targets: []` passed the whole gate (finding 2). Presence yes,
   non-None yes — so every model was built with no targets and the run reported
   success having written no PredictionFrames. It is reachable in production
   precisely because check 4 is not: pipeline-core's `get_combined_config`
   rewrites `regression_targets: None` to `[]` before the manager sees it. The
   gate now rejects empty values for every required key; scalars have no length
   and are skipped.

3. `regression_targets: "lr_ged_sb"` was laundered into nine one-character
   targets (finding 11). The catalog now rejects a bare string.

4. Deriving targets in `__init__` broke `list_models()` (finding 3/A3), which
   ADR-004 declares Stable and the CIC declares side-effect-free — enumerating
   the catalog must not require a config carrying targets. It is a property now.

5. `match=re.escape(missing_key)` re-introduced the substring looseness this same
   commit removed 100 lines below: "steps" matches a message naming only
   "time_steps" (finding 5). Tightened to the exact list.

6. The conformance fixtures were not configs pipeline-core would accept (finding
   7), falsifying the module docstring: `CoreConfigSniffer` rejected all seven for
   missing name/creator/rolling_origin_stride/deployment_status/metrics and
   skip_predictions_delivery. They are complete now, and a new test hands each to
   the sniffer so the claim is enforced rather than asserted in prose.

7. The retired-key guard never covered `MANAGER_BASE_CONFIG` (finding 9) — the
   fixture that actually caused #84. It does now.

8. `_KEYS_DEREFERENCED_ON_EVERY_RUN` claimed a uniform justification that is not
   uniform (finding 3, addendum A1): `prediction_format` is never dereferenced in
   this package and pipeline-core reads it as `.get(..., "dataframe")`, so its
   absence is a silent fallback, not a KeyError. Corrected, and `run_type`'s
   deliberate exclusion is now recorded there rather than left implicit (C-48).

295 passed (was 283), ruff clean.

Refs #85, #94.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoczAeeAcC81UVMGMSiAvS
… short

The sweep in e406920 missed four contributor-facing files and left two register
rows contradicting entry bodies edited in the same commit — the same incomplete-
sweep failure mode this epic is about.

- README.md:154 still told readers the input "must contain target columns
  specified in config['targets']" — on the file pyproject ships as the PyPI front
  page, advising a key that now makes combined_targets() raise.
- publish_package.yml carried the third copy of the "views-pipeline-core is not
  yet on PyPI" claim; the same PR rewrote the other two to say the opposite and
  to instruct the releaser to exercise the install-back.
- hardened_protocol_template.md told contributors `targets` is "a known gap
  documented in ADR-009", citing an ADR this PR rewrote to say it is closed.
- The manager CIC's usage examples were executably false: they omitted the core
  keys, so they raise MissingHyperparameterError, not the documented ValueError.
- ADR-012 still said "beyond `targets`".
- The ReproducibilityGate CIC ships the downstream static check as
  `CORE_PARAMS - set(hp.keys())`. With `level` and `prediction_format` in the
  genome and living in config_meta.py, that now reports all 29 healthy models as
  broken. Corrected to validate the merged config.
- Register K5/K7 cluster rows still said the gate omits level/targets and that
  C-38 is live and gating the suite — both contradicted by their own entry bodies.

The workflow header's "REAL merge gate" claim is also removed: the jobs run and
pass, but neither branch declares required status checks, so red still does not
block a merge. Registered as C-49 rather than silently overstated.

C-41's trigger is corrected: it claimed a clean install raises ModuleNotFoundError
because pipeline-core declares no scipy. Directly true and misleading —
views-baseline -> views-pipeline-core -> views-evaluation requires scipy>=1.11,<2,
so scipy is installed on any real install (verified at 1.15.1). The residual
defect is smaller and different: we import scipy directly while declaring nothing.

New: C-48 (run_type read past the gate), C-49 (CI not a required check), C-50
(catalog reimplements the platform's target vocabulary — a recorded consequence of
the ADR-013 decision, including that the new conformance guard cannot detect the
failure it was built for), C-51 (unpinned ruff), C-52 (fixture keyed by algorithm).

Refs #85, #94.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoczAeeAcC81UVMGMSiAvS
…-key

Fix the retired `targets` config key — restore all 29 baseline models (S1–S6 of #85)
Fixes the retired `targets` config key (#84, #85). Every baseline model in
views-models has been unrunnable since 2026-08-02; this is the release that
carries the fix to them.

1.0.2 is also the first views-baseline release that can actually be installed.
1.0.0 and 1.0.1 were published while views-pipeline-core >=3.0.0 had no PyPI
release, so they resolved for nobody (C-38). pipeline-core reached PyPI on
2026-08-03, so the clean-room install-back in docs/guides/publishing-to-pypi.md
§A is worth running for the first time as part of this release.

Refs #85. Closes #92.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoczAeeAcC81UVMGMSiAvS
@Polichinel
Polichinel merged commit 6c43f6d into main Sep 9, 2026
6 of 7 checks passed
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