portfolio-optimiser/src/portfolio_optimiser/shared_root.py
Kjell Tore Guttormsen f5ec8c84f6 feat(4a): wheelen bærer shared/ som pakkede data — arbeidstreet er overstyringen
README:24 sa det rett ut: shared/ ble lest fra arbeidstreet ved kjøretid, og
derfor kunne repoet verken publiseres som wheel eller kjøre i container. Målt
før endringen: 1.0.0-wheelen bar 58 filer, null under shared/.

Endringen er én søm + én pakkelinje:
- hatchling force-include speiler shared/ byte-identisk til
  portfolio_optimiser/_shared/ (wheel 122 filer, 64 under _shared/; sdist
  bærer treet, målt via uv build sdist→wheel)
- shared_root() løser ved kall-tid: PORTFOLIO_SHARED_ROOT → arbeidstreets
  shared/ når det finnes (en checkout er autoritativ — det holder pull-only-
  subtree-kontrakten og goldenene urørt) → pakket kopi

Iron Law fulgt: tests/test_shared_packaged_data_loadbearing.py skrevet FØRST,
alle tre røde mot dagens kode (ordnings-testen felt av sin egen kontroll på at
pakket kopi finnes). Deretter fiks, deretter MÅLT mutasjon mot hele suiten:
- detach fallbacken → 1 rød (resolusjons-testen)
- detach force-include → 3 røde
- snu rekkefølgen (pakket før arbeidstre) → 1 rød (ordnings-testen, som var
  grønn før fiksen — flip-mutasjonen er beviset på at den diskriminerer)
Kontroll grønn: 813 passed / 4 skipped (baseline 810/4 målt på 142bfa9 samme
økt). Goldenene byte-uendret før og etter (shasum -c på demo-transkript +
begge nav-goldens). shared/ selv er urørt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018hfm6sWTk17Cbh6ZHYhvCu
2026-08-13 21:13:08 +02:00

38 lines
1.9 KiB
Python

"""Resolver for the location of the shared framework-neutral core (S3, R1-forberedelse; 4a pakket).
``shared/`` is a pull-only subtree of the commons repo at the repository root. Every MAF-side
runtime consumer (``persona``, ``simulation``) resolves its location through this ONE seam, so a
re-point is an env var, not a code change. Since Fase 4a the wheel also carries a byte-identical
mirror of the tree as packaged data (``portfolio_optimiser/_shared/``, hatchling force-include in
pyproject.toml), so an installed distribution — and a container built from it — works without a
checkout. Resolution order at CALL time: explicit env override → the working tree's ``shared/``
when present (a repo checkout stays authoritative, which is what keeps the subtree contract and
the byte-level goldens untouched) → the packaged copy. Test fixtures pointing at the real in-repo
bundle hardcode the path deliberately — they must not be redirected by a production env var. Pure
stdlib — the shared core itself stays framework-free.
"""
from __future__ import annotations
import os
from pathlib import Path
ENV_VAR = "PORTFOLIO_SHARED_ROOT"
_WORKTREE = Path(__file__).resolve().parents[2] / "shared"
_PACKAGED = Path(__file__).resolve().parent / "_shared"
def shared_root() -> Path:
"""Resolve the shared-core root at CALL time: ``PORTFOLIO_SHARED_ROOT`` if set (non-empty),
else the working tree's ``shared/`` when it exists (a checkout), else the packaged copy
shipped inside the distribution. The call-time read is what keeps the override testable and
the ordering observable; when neither directory exists the packaged path is returned so the
consumer's own fail-fast names the installed distribution's gap, not a checkout that was
never there."""
override = os.environ.get(ENV_VAR)
if override:
return Path(override)
if _WORKTREE.is_dir():
return _WORKTREE
return _PACKAGED