strathmark 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- strathmark-2.0.0/.gitattributes +8 -0
- strathmark-2.0.0/.github/REPO_METADATA.md +64 -0
- strathmark-2.0.0/.github/workflows/ci.yml +250 -0
- strathmark-2.0.0/.github/workflows/publish.yml +39 -0
- strathmark-2.0.0/.gitignore +52 -0
- strathmark-2.0.0/CHANGELOG.md +194 -0
- strathmark-2.0.0/CONTRIBUTING.md +64 -0
- strathmark-2.0.0/LICENSE +203 -0
- strathmark-2.0.0/ONBOARDING.md +127 -0
- strathmark-2.0.0/PKG-INFO +243 -0
- strathmark-2.0.0/README.md +190 -0
- strathmark-2.0.0/TODOS.md +51 -0
- strathmark-2.0.0/assets/sTRATHMARK.png +0 -0
- strathmark-2.0.0/assets/strathmark_logo.png +0 -0
- strathmark-2.0.0/benchmarks/mark_optimizer_capacity.json +23 -0
- strathmark-2.0.0/benchmarks/prediction_v2_golden.json +69 -0
- strathmark-2.0.0/benchmarks/prediction_v2_manifest.json +50 -0
- strathmark-2.0.0/benchmarks/prediction_v2_prelock.json +259 -0
- strathmark-2.0.0/benchmarks/prediction_v2_release_attestation.json +10 -0
- strathmark-2.0.0/benchmarks/prediction_v2_report.json +441 -0
- strathmark-2.0.0/benchmarks/prediction_v2_report.md +19 -0
- strathmark-2.0.0/docs/ARCHITECTURE.md +156 -0
- strathmark-2.0.0/docs/DEPLOYMENT.md +170 -0
- strathmark-2.0.0/docs/OFFLINE_EVIDENCE_SNAPSHOT.md +171 -0
- strathmark-2.0.0/docs/PREDICTION_ENGINE_V2.md +280 -0
- strathmark-2.0.0/docs/SHADOW_CONSUMER_CONTRACT.md +176 -0
- strathmark-2.0.0/docs/STRATHEX_CONSUMER_MIGRATION.md +80 -0
- strathmark-2.0.0/docs/cleanup-candidates-2026-05-04.md +47 -0
- strathmark-2.0.0/docs/ml-persistence-policy.md +143 -0
- strathmark-2.0.0/docs/ml-research-questions.md +12 -0
- strathmark-2.0.0/docs/plans/2026-08-11-001-feat-prediction-engine-v2-plan.md +738 -0
- strathmark-2.0.0/docs/plans/2026-08-13-001-fix-prediction-v2-hardening-plan.md +683 -0
- strathmark-2.0.0/docs/plans/2026-08-13-002-feat-shadow-handicap-operations-plan.md +1059 -0
- strathmark-2.0.0/docs/prediction-v2-migration-rehearsal.md +89 -0
- strathmark-2.0.0/docs/schema-reality-2026-05-04.md +205 -0
- strathmark-2.0.0/docs/solutions/architecture-decisions/absolute-variance-only.md +49 -0
- strathmark-2.0.0/docs/solutions/architecture-decisions/dual-store-sqlite-supabase-split.md +154 -0
- strathmark-2.0.0/docs/solutions/architecture-decisions/ensemble-predictor-design-decisions.md +80 -0
- strathmark-2.0.0/docs/solutions/architecture-decisions/mark-floor-ceiling-invariants.md +42 -0
- strathmark-2.0.0/docs/solutions/architecture-decisions/prediction-cascade-order.md +23 -0
- strathmark-2.0.0/docs/solutions/architecture-decisions/tournament-weighting-and-decay.md +22 -0
- strathmark-2.0.0/docs/solutions/architecture-decisions/tournament-weighting-audit-todo-011.md +20 -0
- strathmark-2.0.0/docs/solutions/best-practices/config-env-vars-importlib-reload-pattern.md +92 -0
- strathmark-2.0.0/docs/solutions/best-practices/llm-cascade-and-monte-carlo-tuning-2026-04-21.md +21 -0
- strathmark-2.0.0/docs/solutions/best-practices/optional-dependency-gating-importorskip.md +93 -0
- strathmark-2.0.0/docs/solutions/best-practices/plain-text-output-no-emojis.md +44 -0
- strathmark-2.0.0/docs/solutions/best-practices/test-isolation-no-prod-db.md +35 -0
- strathmark-2.0.0/docs/solutions/best-practices/workspace-project-disambiguation.md +34 -0
- strathmark-2.0.0/docs/solutions/configuration-issues/api-input-validation-gaps.md +38 -0
- strathmark-2.0.0/docs/solutions/configuration-issues/env-vars-resolved-at-import-time.md +37 -0
- strathmark-2.0.0/docs/solutions/data-integrity/decay-weights-silently-default-to-one.md +36 -0
- strathmark-2.0.0/docs/solutions/data-integrity/timeout-results-pollute-baseline.md +36 -0
- strathmark-2.0.0/docs/solutions/performance-issues/ollama-cascade-hang-on-unreachable-host.md +43 -0
- strathmark-2.0.0/docs/solutions/runtime-errors/ollama-status-cache-race-condition.md +32 -0
- strathmark-2.0.0/docs/solutions/test-failures/integration-test-fixture-silent-typeerror.md +37 -0
- strathmark-2.0.0/docs/solutions/test-failures/mocking-wrong-import-target.md +32 -0
- strathmark-2.0.0/docs/solutions/test-failures/regression-test-must-include-triggering-input.md +69 -0
- strathmark-2.0.0/docs/solutions/workflow-patterns/eng-review-cycle-and-todos-handoff.md +80 -0
- strathmark-2.0.0/docs/solutions/workflow-patterns/prepare-for-commit-protocol.md +42 -0
- strathmark-2.0.0/docs/solutions/workflow-patterns/stale-pycache-diagnostic.md +40 -0
- strathmark-2.0.0/docs/wiki/Architecture-Overview.md +32 -0
- strathmark-2.0.0/docs/wiki/Deployment.md +55 -0
- strathmark-2.0.0/docs/wiki/FAQ.md +61 -0
- strathmark-2.0.0/docs/wiki/Fairness-Assessment.md +26 -0
- strathmark-2.0.0/docs/wiki/Handicap-Mark-Math.md +30 -0
- strathmark-2.0.0/docs/wiki/Home.md +35 -0
- strathmark-2.0.0/docs/wiki/Installation.md +35 -0
- strathmark-2.0.0/docs/wiki/LLM-Integration.md +22 -0
- strathmark-2.0.0/docs/wiki/Persistence-and-Database.md +53 -0
- strathmark-2.0.0/docs/wiki/Prediction-Cascade.md +26 -0
- strathmark-2.0.0/docs/wiki/Prediction-Engine-V2.md +90 -0
- strathmark-2.0.0/docs/wiki/Quick-Start.md +44 -0
- strathmark-2.0.0/docs/wiki/README.md +24 -0
- strathmark-2.0.0/docs/wiki/REST-API.md +73 -0
- strathmark-2.0.0/docs/wiki/Rulebook-Comparison.md +30 -0
- strathmark-2.0.0/docs/wiki/STRATHEX-Consumer.md +35 -0
- strathmark-2.0.0/docs/wiki/Testing.md +35 -0
- strathmark-2.0.0/docs/wiki/Time-Decay-Weighting.md +17 -0
- strathmark-2.0.0/docs/wiki/Variance-and-Monte-Carlo.md +21 -0
- strathmark-2.0.0/docs/wiki/Wood-and-Diameter-Scaling.md +18 -0
- strathmark-2.0.0/docs/wiki/_Footer.md +1 -0
- strathmark-2.0.0/docs/wiki/_Sidebar.md +30 -0
- strathmark-2.0.0/evaluate_llm_prompts.py +419 -0
- strathmark-2.0.0/import_legacy.py +534 -0
- strathmark-2.0.0/pyproject.toml +114 -0
- strathmark-2.0.0/requirements/api-current.txt +5 -0
- strathmark-2.0.0/requirements/api-oldest.txt +5 -0
- strathmark-2.0.0/scripts/__init__.py +0 -0
- strathmark-2.0.0/scripts/benchmark_mark_optimizer.py +149 -0
- strathmark-2.0.0/scripts/freeze_shadow_consumer_contract.py +1475 -0
- strathmark-2.0.0/scripts/ingest_proam_results.py +211 -0
- strathmark-2.0.0/scripts/measure_baseline_mae.py +161 -0
- strathmark-2.0.0/scripts/rekey_against_mnemex.py +323 -0
- strathmark-2.0.0/scripts/smoke_installed_distribution.py +243 -0
- strathmark-2.0.0/scripts/validate_deployment.py +384 -0
- strathmark-2.0.0/scripts/validate_v2.py +702 -0
- strathmark-2.0.0/scripts/verify_v2_golden.py +130 -0
- strathmark-2.0.0/strathmark/__init__.py +335 -0
- strathmark-2.0.0/strathmark/analytics.py +267 -0
- strathmark-2.0.0/strathmark/api.py +1789 -0
- strathmark-2.0.0/strathmark/auth.py +457 -0
- strathmark-2.0.0/strathmark/calculator.py +1288 -0
- strathmark-2.0.0/strathmark/config.py +761 -0
- strathmark-2.0.0/strathmark/consumer_contract.py +105 -0
- strathmark-2.0.0/strathmark/contracts/shadow_consumer_v1.openapi.json +1 -0
- strathmark-2.0.0/strathmark/contracts/shadow_consumer_v1.openapi.sha256 +1 -0
- strathmark-2.0.0/strathmark/db.py +2139 -0
- strathmark-2.0.0/strathmark/decay.py +355 -0
- strathmark-2.0.0/strathmark/drift.py +476 -0
- strathmark-2.0.0/strathmark/fairness.py +674 -0
- strathmark-2.0.0/strathmark/fallback.py +500 -0
- strathmark-2.0.0/strathmark/features.py +386 -0
- strathmark-2.0.0/strathmark/identity.py +29 -0
- strathmark-2.0.0/strathmark/ledger.py +2950 -0
- strathmark-2.0.0/strathmark/llm.py +364 -0
- strathmark-2.0.0/strathmark/llm_roles.py +244 -0
- strathmark-2.0.0/strathmark/loader.py +181 -0
- strathmark-2.0.0/strathmark/mark_optimizer.py +359 -0
- strathmark-2.0.0/strathmark/migrations/20260504_001_add_source_tracking.sql +100 -0
- strathmark-2.0.0/strathmark/migrations/20260504_002_ml_state_tables.sql +206 -0
- strathmark-2.0.0/strathmark/migrations/20260504_003_rls_reframe.sql +249 -0
- strathmark-2.0.0/strathmark/migrations/20260508_004_atomic_model_swap_and_residual_dedup.sql +88 -0
- strathmark-2.0.0/strathmark/migrations/20260811_005_prediction_v2.sql +810 -0
- strathmark-2.0.0/strathmark/migrations/20260813_006_prediction_hash_algorithm.down.sql +638 -0
- strathmark-2.0.0/strathmark/migrations/20260813_006_prediction_hash_algorithm.sql +649 -0
- strathmark-2.0.0/strathmark/migrations/20260813_007_shadow_mirror_contract.down.sql +35 -0
- strathmark-2.0.0/strathmark/migrations/20260813_007_shadow_mirror_contract.sql +1688 -0
- strathmark-2.0.0/strathmark/migrations/README.md +188 -0
- strathmark-2.0.0/strathmark/migrations/prerequisites/prediction_rpc_owner.sql +48 -0
- strathmark-2.0.0/strathmark/mirror_contract.py +6 -0
- strathmark-2.0.0/strathmark/mnemex.py +348 -0
- strathmark-2.0.0/strathmark/models/prediction_v2_core.json +1 -0
- strathmark-2.0.0/strathmark/prediction_v2.py +1458 -0
- strathmark-2.0.0/strathmark/predictor.py +2868 -0
- strathmark-2.0.0/strathmark/provenance.py +24 -0
- strathmark-2.0.0/strathmark/residual.py +752 -0
- strathmark-2.0.0/strathmark/shadow.py +498 -0
- strathmark-2.0.0/strathmark/sqlite_utils.py +25 -0
- strathmark-2.0.0/strathmark/store.py +1744 -0
- strathmark-2.0.0/strathmark/sync.py +492 -0
- strathmark-2.0.0/strathmark/utils.py +185 -0
- strathmark-2.0.0/strathmark/validation.py +417 -0
- strathmark-2.0.0/strathmark/variance.py +770 -0
- strathmark-2.0.0/strathmark/visualization.py +129 -0
- strathmark-2.0.0/strathmark/wood.py +672 -0
- strathmark-2.0.0/tests/__init__.py +8 -0
- strathmark-2.0.0/tests/conftest.py +41 -0
- strathmark-2.0.0/tests/installed_wheel_shadow_smoke.py +35 -0
- strathmark-2.0.0/tests/postgres_rehearsal.py +2465 -0
- strathmark-2.0.0/tests/test_analytics.py +80 -0
- strathmark-2.0.0/tests/test_analytics_extended.py +231 -0
- strathmark-2.0.0/tests/test_api.py +716 -0
- strathmark-2.0.0/tests/test_boundary.py +348 -0
- strathmark-2.0.0/tests/test_calculator.py +755 -0
- strathmark-2.0.0/tests/test_calculator_extended.py +405 -0
- strathmark-2.0.0/tests/test_circuit_breaker.py +190 -0
- strathmark-2.0.0/tests/test_config.py +203 -0
- strathmark-2.0.0/tests/test_config_invariants.py +215 -0
- strathmark-2.0.0/tests/test_db.py +243 -0
- strathmark-2.0.0/tests/test_db_extended.py +43 -0
- strathmark-2.0.0/tests/test_decay.py +91 -0
- strathmark-2.0.0/tests/test_decay_extended.py +236 -0
- strathmark-2.0.0/tests/test_deployment_fallbacks.py +330 -0
- strathmark-2.0.0/tests/test_drift.py +508 -0
- strathmark-2.0.0/tests/test_fairness.py +44 -0
- strathmark-2.0.0/tests/test_fairness_extended.py +351 -0
- strathmark-2.0.0/tests/test_fallback.py +32 -0
- strathmark-2.0.0/tests/test_fallback_extended.py +415 -0
- strathmark-2.0.0/tests/test_features.py +161 -0
- strathmark-2.0.0/tests/test_integration.py +171 -0
- strathmark-2.0.0/tests/test_integration_extended.py +363 -0
- strathmark-2.0.0/tests/test_ledger.py +1033 -0
- strathmark-2.0.0/tests/test_llm.py +217 -0
- strathmark-2.0.0/tests/test_llm_roles.py +58 -0
- strathmark-2.0.0/tests/test_llm_roles_extended.py +267 -0
- strathmark-2.0.0/tests/test_loader.py +30 -0
- strathmark-2.0.0/tests/test_loader_extended.py +242 -0
- strathmark-2.0.0/tests/test_mark_optimizer.py +243 -0
- strathmark-2.0.0/tests/test_ml_state.py +764 -0
- strathmark-2.0.0/tests/test_mnemex.py +114 -0
- strathmark-2.0.0/tests/test_offline_evidence_snapshot.py +977 -0
- strathmark-2.0.0/tests/test_postgres_rehearsal.py +211 -0
- strathmark-2.0.0/tests/test_prediction_v2.py +490 -0
- strathmark-2.0.0/tests/test_predictor.py +524 -0
- strathmark-2.0.0/tests/test_predictor_extended.py +440 -0
- strathmark-2.0.0/tests/test_predictor_regression.py +256 -0
- strathmark-2.0.0/tests/test_regression.py +289 -0
- strathmark-2.0.0/tests/test_residual.py +354 -0
- strathmark-2.0.0/tests/test_settlement_revisions.py +1347 -0
- strathmark-2.0.0/tests/test_shadow_api.py +2373 -0
- strathmark-2.0.0/tests/test_shadow_consumer_contract.py +896 -0
- strathmark-2.0.0/tests/test_shadow_mirror_contract.py +563 -0
- strathmark-2.0.0/tests/test_shadow_receipts.py +654 -0
- strathmark-2.0.0/tests/test_store.py +168 -0
- strathmark-2.0.0/tests/test_store_extended.py +337 -0
- strathmark-2.0.0/tests/test_sync.py +150 -0
- strathmark-2.0.0/tests/test_utils.py +33 -0
- strathmark-2.0.0/tests/test_utils_extended.py +234 -0
- strathmark-2.0.0/tests/test_validate_v2.py +175 -0
- strathmark-2.0.0/tests/test_validation.py +248 -0
- strathmark-2.0.0/tests/test_variance.py +256 -0
- strathmark-2.0.0/tests/test_variance_extended.py +344 -0
- strathmark-2.0.0/tests/test_visualization.py +64 -0
- strathmark-2.0.0/tests/test_visualization_extended.py +208 -0
- strathmark-2.0.0/tests/test_wood.py +98 -0
- strathmark-2.0.0/tests/test_wood_boundary.py +191 -0
- strathmark-2.0.0/tests/test_wood_extended.py +351 -0
- strathmark-2.0.0/train_model.py +32 -0
- strathmark-2.0.0/woodchopping_clean.xlsx +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# GitHub Repository Metadata
|
|
2
|
+
|
|
3
|
+
Paste the following into the repository **About** panel on GitHub
|
|
4
|
+
(Settings tab is not required — use the cog icon next to *About* on the
|
|
5
|
+
repo home page).
|
|
6
|
+
|
|
7
|
+
## Repository description (one line, 350 char limit)
|
|
8
|
+
|
|
9
|
+
> Woodchopping handicap engine — pip-installable calculation core for
|
|
10
|
+
> timbersports tournaments. Computes Standing Block and Underhand marks
|
|
11
|
+
> with a Manual > LLM > ML > Baseline > Panel cascade, 2-year time-decay
|
|
12
|
+
> weighting, absolute ±3 s variance, and Monte Carlo fairness validation.
|
|
13
|
+
> Extracted from STRATHEX.
|
|
14
|
+
|
|
15
|
+
## Website
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
https://pypi.org/project/strathmark/
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
(leave blank until the first PyPI release; the source URL in
|
|
22
|
+
`pyproject.toml` already points at the GitHub repo)
|
|
23
|
+
|
|
24
|
+
## Topics / tags
|
|
25
|
+
|
|
26
|
+
Apply these topic tags via the repo **About -> ⚙** settings. GitHub
|
|
27
|
+
topics are lowercase, hyphen-separated, max 50 per repo. These are the
|
|
28
|
+
tags that keep STRATHMARK discoverable to both the timbersports
|
|
29
|
+
community and the Python/ML community:
|
|
30
|
+
|
|
31
|
+
### Sport-domain tags
|
|
32
|
+
|
|
33
|
+
- `timbersports`
|
|
34
|
+
- `woodchopping`
|
|
35
|
+
- `lumberjack`
|
|
36
|
+
- `axemen`
|
|
37
|
+
- `axe`
|
|
38
|
+
- `chainsaw`
|
|
39
|
+
- `tournament`
|
|
40
|
+
- `handicap`
|
|
41
|
+
- `handicapping`
|
|
42
|
+
|
|
43
|
+
### Technical / discovery tags
|
|
44
|
+
|
|
45
|
+
- `python`
|
|
46
|
+
- `pandas`
|
|
47
|
+
- `numpy`
|
|
48
|
+
- `xgboost`
|
|
49
|
+
- `machine-learning`
|
|
50
|
+
- `monte-carlo`
|
|
51
|
+
- `monte-carlo-simulation`
|
|
52
|
+
- `fastapi`
|
|
53
|
+
- `ollama`
|
|
54
|
+
- `llm`
|
|
55
|
+
- `sports-analytics`
|
|
56
|
+
- `fairness`
|
|
57
|
+
- `pip-package`
|
|
58
|
+
- `calculation-engine`
|
|
59
|
+
|
|
60
|
+
## Social preview image
|
|
61
|
+
|
|
62
|
+
Use `assets/strathmark_logo.png` (already checked into the repo) as the
|
|
63
|
+
social preview image under **Settings -> Social preview**. Recommended
|
|
64
|
+
upload size is 1280x640; the current logo can be padded to that canvas.
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
name: Lint (ruff)
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
|
|
21
|
+
- name: Install ruff
|
|
22
|
+
run: pip install ruff
|
|
23
|
+
|
|
24
|
+
- name: Ruff check
|
|
25
|
+
run: ruff check .
|
|
26
|
+
|
|
27
|
+
- name: Ruff format check
|
|
28
|
+
run: ruff format --check .
|
|
29
|
+
|
|
30
|
+
test:
|
|
31
|
+
name: Test (${{ matrix.os }} / Python ${{ matrix.python-version }})
|
|
32
|
+
runs-on: ${{ matrix.os }}
|
|
33
|
+
strategy:
|
|
34
|
+
fail-fast: false
|
|
35
|
+
matrix:
|
|
36
|
+
os: [ubuntu-latest, windows-latest]
|
|
37
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
|
|
41
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
42
|
+
uses: actions/setup-python@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: ${{ matrix.python-version }}
|
|
45
|
+
|
|
46
|
+
- name: Install package with dev extras
|
|
47
|
+
run: pip install -e ".[dev]"
|
|
48
|
+
|
|
49
|
+
- name: Check dependency consistency
|
|
50
|
+
run: pip check
|
|
51
|
+
|
|
52
|
+
- name: Run pytest with coverage
|
|
53
|
+
# Supabase-backed db tests are gated behind STRATHMARK_TEST_DB and
|
|
54
|
+
# skip by default. ML predictor paths fall back to baseline when
|
|
55
|
+
# xgboost/lightgbm/sklearn are not installed (they live in the [ml]
|
|
56
|
+
# extra and are not pulled in by [dev]).
|
|
57
|
+
run: pytest tests/ -v --tb=short --cov=strathmark --cov-report=term-missing
|
|
58
|
+
|
|
59
|
+
api:
|
|
60
|
+
name: API contract (${{ matrix.compatible-set }})
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
needs: lint
|
|
63
|
+
strategy:
|
|
64
|
+
fail-fast: false
|
|
65
|
+
matrix:
|
|
66
|
+
compatible-set: [oldest, current]
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
|
|
70
|
+
- name: Set up Python
|
|
71
|
+
uses: actions/setup-python@v5
|
|
72
|
+
with:
|
|
73
|
+
python-version: "3.12"
|
|
74
|
+
|
|
75
|
+
- name: Install oldest compatible API dependency set
|
|
76
|
+
if: matrix.compatible-set == 'oldest'
|
|
77
|
+
run: pip install -e ".[dev,api]" -r requirements/api-oldest.txt
|
|
78
|
+
|
|
79
|
+
- name: Install current compatible API dependency set
|
|
80
|
+
if: matrix.compatible-set == 'current'
|
|
81
|
+
run: pip install -e ".[dev,api]" -r requirements/api-current.txt
|
|
82
|
+
|
|
83
|
+
- name: Check dependency consistency
|
|
84
|
+
run: pip check
|
|
85
|
+
|
|
86
|
+
- name: Run API contract tests
|
|
87
|
+
run: pytest tests/test_api.py tests/test_shadow_api.py tests/test_shadow_consumer_contract.py -v --tb=short
|
|
88
|
+
|
|
89
|
+
optional-ml:
|
|
90
|
+
name: Optional ML artifact and promotion gates (Ubuntu / Python 3.12)
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
needs: lint
|
|
93
|
+
steps:
|
|
94
|
+
- uses: actions/checkout@v4
|
|
95
|
+
|
|
96
|
+
- name: Set up Python
|
|
97
|
+
uses: actions/setup-python@v5
|
|
98
|
+
with:
|
|
99
|
+
python-version: "3.12"
|
|
100
|
+
|
|
101
|
+
- name: Install package with optional ML dependencies
|
|
102
|
+
run: pip install -e ".[dev,ml]"
|
|
103
|
+
|
|
104
|
+
- name: Check dependency consistency
|
|
105
|
+
run: pip check
|
|
106
|
+
|
|
107
|
+
- name: Run residual artifact and temporal validation tests
|
|
108
|
+
run: pytest tests/test_residual.py tests/test_validation.py -v --tb=short
|
|
109
|
+
|
|
110
|
+
validation-artifact:
|
|
111
|
+
name: Verify Prediction V2 release evidence (Ubuntu / Python 3.12)
|
|
112
|
+
runs-on: ubuntu-latest
|
|
113
|
+
needs: lint
|
|
114
|
+
steps:
|
|
115
|
+
- uses: actions/checkout@v4
|
|
116
|
+
|
|
117
|
+
- name: Set up Python
|
|
118
|
+
uses: actions/setup-python@v5
|
|
119
|
+
with:
|
|
120
|
+
python-version: "3.12"
|
|
121
|
+
|
|
122
|
+
- name: Install core validation dependencies
|
|
123
|
+
run: pip install -e ".[dev]"
|
|
124
|
+
|
|
125
|
+
- name: Check dependency consistency
|
|
126
|
+
run: pip check
|
|
127
|
+
|
|
128
|
+
- name: Verify persisted report and checksummed artifact
|
|
129
|
+
run: python scripts/validate_v2.py --verify-release
|
|
130
|
+
|
|
131
|
+
- name: Exercise release-gate contracts
|
|
132
|
+
run: pytest tests/test_validate_v2.py tests/test_validation.py -v --tb=short
|
|
133
|
+
|
|
134
|
+
- name: Verify runtime provider loads the packaged core
|
|
135
|
+
run: python -c "from datetime import date; from strathmark.predictor import FilePredictionProvider; b=FilePredictionProvider().snapshot(date(2026,8,11)); assert b.core is not None and b.source == 'package' and b.core.model_version == 'prediction-v2-core-20260207'"
|
|
136
|
+
|
|
137
|
+
golden:
|
|
138
|
+
name: Prediction V2 golden (${{ matrix.os }} / Python 3.12)
|
|
139
|
+
runs-on: ${{ matrix.os }}
|
|
140
|
+
needs: lint
|
|
141
|
+
strategy:
|
|
142
|
+
fail-fast: false
|
|
143
|
+
matrix:
|
|
144
|
+
os: [ubuntu-latest, windows-latest]
|
|
145
|
+
steps:
|
|
146
|
+
- uses: actions/checkout@v4
|
|
147
|
+
|
|
148
|
+
- name: Set up Python
|
|
149
|
+
uses: actions/setup-python@v5
|
|
150
|
+
with:
|
|
151
|
+
python-version: "3.12"
|
|
152
|
+
|
|
153
|
+
- name: Install core test dependencies
|
|
154
|
+
run: pip install -e ".[dev]"
|
|
155
|
+
|
|
156
|
+
- name: Check dependency consistency
|
|
157
|
+
run: pip check
|
|
158
|
+
|
|
159
|
+
- name: Verify normalized public audit output
|
|
160
|
+
run: python scripts/verify_v2_golden.py
|
|
161
|
+
|
|
162
|
+
optimizer-capacity:
|
|
163
|
+
name: Optimizer capacity (Ubuntu / Python 3.12)
|
|
164
|
+
runs-on: ubuntu-latest
|
|
165
|
+
needs: lint
|
|
166
|
+
steps:
|
|
167
|
+
- uses: actions/checkout@v4
|
|
168
|
+
|
|
169
|
+
- name: Set up Python
|
|
170
|
+
uses: actions/setup-python@v5
|
|
171
|
+
with:
|
|
172
|
+
python-version: "3.12"
|
|
173
|
+
|
|
174
|
+
- name: Install core dependencies
|
|
175
|
+
run: pip install -e .
|
|
176
|
+
|
|
177
|
+
- name: Check dependency consistency
|
|
178
|
+
run: pip check
|
|
179
|
+
|
|
180
|
+
- name: Enforce 64-competitor optimizer budget
|
|
181
|
+
run: python scripts/benchmark_mark_optimizer.py --output optimizer-capacity-ci.json
|
|
182
|
+
|
|
183
|
+
- name: Upload capacity measurement
|
|
184
|
+
uses: actions/upload-artifact@v4
|
|
185
|
+
with:
|
|
186
|
+
name: optimizer-capacity-ubuntu-python312
|
|
187
|
+
path: optimizer-capacity-ci.json
|
|
188
|
+
|
|
189
|
+
postgres-migration-rehearsal:
|
|
190
|
+
name: Disposable PostgreSQL migration rehearsal
|
|
191
|
+
runs-on: ubuntu-latest
|
|
192
|
+
services:
|
|
193
|
+
postgres:
|
|
194
|
+
image: postgres:18
|
|
195
|
+
env:
|
|
196
|
+
POSTGRES_USER: rehearsal
|
|
197
|
+
POSTGRES_PASSWORD: rehearsal-ci-only
|
|
198
|
+
POSTGRES_DB: strathmark_rehearsal_controller
|
|
199
|
+
ports:
|
|
200
|
+
- 5432:5432
|
|
201
|
+
options: >-
|
|
202
|
+
--health-cmd "pg_isready -U rehearsal -d strathmark_rehearsal_controller"
|
|
203
|
+
--health-interval 5s
|
|
204
|
+
--health-timeout 5s
|
|
205
|
+
--health-retries 12
|
|
206
|
+
env:
|
|
207
|
+
STRATHMARK_RUN_POSTGRES_REHEARSAL: "1"
|
|
208
|
+
STRATHMARK_REHEARSAL_DSN: postgresql://rehearsal:rehearsal-ci-only@127.0.0.1:5432/strathmark_rehearsal_controller
|
|
209
|
+
steps:
|
|
210
|
+
- uses: actions/checkout@v4
|
|
211
|
+
|
|
212
|
+
- name: Set up Python
|
|
213
|
+
uses: actions/setup-python@v5
|
|
214
|
+
with:
|
|
215
|
+
python-version: "3.12"
|
|
216
|
+
|
|
217
|
+
- name: Install test dependencies and PostgreSQL client
|
|
218
|
+
run: |
|
|
219
|
+
pip install -e ".[dev]"
|
|
220
|
+
sudo apt-get update
|
|
221
|
+
sudo apt-get install --yes postgresql-client
|
|
222
|
+
|
|
223
|
+
- name: Exercise migrations 005 and 006 against disposable PostgreSQL
|
|
224
|
+
run: pytest tests/test_postgres_rehearsal.py -v --tb=short
|
|
225
|
+
|
|
226
|
+
build:
|
|
227
|
+
name: Installed ${{ matrix.kind }} (${{ matrix.os }} / Python 3.12)
|
|
228
|
+
runs-on: ${{ matrix.os }}
|
|
229
|
+
needs: [lint, test, api, optional-ml, validation-artifact, golden, optimizer-capacity, postgres-migration-rehearsal]
|
|
230
|
+
strategy:
|
|
231
|
+
fail-fast: false
|
|
232
|
+
matrix:
|
|
233
|
+
os: [ubuntu-latest, windows-latest]
|
|
234
|
+
kind: [wheel, sdist]
|
|
235
|
+
steps:
|
|
236
|
+
- uses: actions/checkout@v4
|
|
237
|
+
|
|
238
|
+
- name: Set up Python
|
|
239
|
+
uses: actions/setup-python@v5
|
|
240
|
+
with:
|
|
241
|
+
python-version: "3.12"
|
|
242
|
+
|
|
243
|
+
- name: Install build tools
|
|
244
|
+
run: pip install build
|
|
245
|
+
|
|
246
|
+
- name: Build sdist and wheel
|
|
247
|
+
run: python -m build
|
|
248
|
+
|
|
249
|
+
- name: Verify installed distribution outside checkout
|
|
250
|
+
run: python scripts/smoke_installed_distribution.py --kind ${{ matrix.kind }}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Manual-only for now. Alex triggers releases from the Actions tab.
|
|
4
|
+
# To enable automatic publishing on tag push, uncomment the `push` block.
|
|
5
|
+
on:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
# push:
|
|
8
|
+
# tags:
|
|
9
|
+
# - "v*"
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
name: Build and publish
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
# PyPI trusted publishing requires this environment to be configured
|
|
16
|
+
# in the repo settings AND a matching publisher to be registered on
|
|
17
|
+
# PyPI for the strathmark project. See:
|
|
18
|
+
# https://docs.pypi.org/trusted-publishers/
|
|
19
|
+
# Until that is wired up, this workflow will fail at the upload step.
|
|
20
|
+
environment: pypi
|
|
21
|
+
permissions:
|
|
22
|
+
# Required for PyPI trusted publishing (OIDC token exchange)
|
|
23
|
+
id-token: write
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
|
|
27
|
+
- name: Set up Python
|
|
28
|
+
uses: actions/setup-python@v5
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.12"
|
|
31
|
+
|
|
32
|
+
- name: Install build tools
|
|
33
|
+
run: pip install build
|
|
34
|
+
|
|
35
|
+
- name: Build sdist and wheel
|
|
36
|
+
run: python -m build
|
|
37
|
+
|
|
38
|
+
- name: Publish to PyPI
|
|
39
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
.Python
|
|
7
|
+
*.egg
|
|
8
|
+
*.egg-info/
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
eggs/
|
|
12
|
+
parts/
|
|
13
|
+
var/
|
|
14
|
+
sdist/
|
|
15
|
+
develop-eggs/
|
|
16
|
+
.installed.cfg
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
|
|
20
|
+
# Virtual environments
|
|
21
|
+
.env
|
|
22
|
+
.venv
|
|
23
|
+
.venv*/
|
|
24
|
+
env/
|
|
25
|
+
venv/
|
|
26
|
+
ENV/
|
|
27
|
+
|
|
28
|
+
# Testing
|
|
29
|
+
.pytest_cache/
|
|
30
|
+
.coverage
|
|
31
|
+
htmlcov/
|
|
32
|
+
.tox/
|
|
33
|
+
.ruff_cache/
|
|
34
|
+
|
|
35
|
+
# IDE
|
|
36
|
+
.vscode/
|
|
37
|
+
.idea/
|
|
38
|
+
*.swp
|
|
39
|
+
|
|
40
|
+
# Distribution
|
|
41
|
+
*.whl
|
|
42
|
+
*.tar.gz
|
|
43
|
+
.gstack/
|
|
44
|
+
|
|
45
|
+
# Local secrets (env-var exports for Supabase, etc.) — never commit
|
|
46
|
+
STRATHMARK API.txt
|
|
47
|
+
*.secrets.txt
|
|
48
|
+
|
|
49
|
+
# Local agent / editor config (per-developer, not portfolio content)
|
|
50
|
+
CLAUDE.md
|
|
51
|
+
.claude/
|
|
52
|
+
AGENTS.md
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to STRATHMARK will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [2.0.0] - 2026-08-18
|
|
8
|
+
|
|
9
|
+
Prediction Engine V2 replaces the numeric Manual/LLM/ML/baseline cascade with one
|
|
10
|
+
reproducible, prior-only prediction system while retaining the five legacy result keys
|
|
11
|
+
for compatibility.
|
|
12
|
+
|
|
13
|
+
### Hardening
|
|
14
|
+
|
|
15
|
+
- Added adversarial causal and artifact validation, trusted-ledger admission and
|
|
16
|
+
interval-aware drift checks, bounded mirror delivery, optimizer oracle/capacity
|
|
17
|
+
evidence, and stronger package/release verification.
|
|
18
|
+
- Drift coverage for V2 is measured from each settled prediction's issued interval;
|
|
19
|
+
residual-quantile reconstruction remains historical behavior only.
|
|
20
|
+
- Reconciled the retired pre-2.0 ensemble TODOs and corrected rounded-gap wording to
|
|
21
|
+
the implemented half-to-even behavior.
|
|
22
|
+
- Excluded undated calibration rows and numeric pseudo-dates, normalized equivalent
|
|
23
|
+
species/gender identities before idempotency hashing, and kept an intentionally
|
|
24
|
+
inactive optional residual from degrading the promoted core.
|
|
25
|
+
- Made active-v2 cloud payloads version-explicit, restored overflow/restart outbox
|
|
26
|
+
recovery, added a historical health cutoff, and guarded the 005-to-006 deploy window
|
|
27
|
+
plus rollback.
|
|
28
|
+
- Preserved the public fairness-simulation admission limit at 4,000,000 cells and
|
|
29
|
+
limited it to one concurrent request per process pending a bounded-batch simulator.
|
|
30
|
+
- Added migration 007's versioned, append-only shadow mirror for immutable receipt
|
|
31
|
+
cores and eligible numeric settle/void revisions. The cloud copy remains optional,
|
|
32
|
+
non-authoritative, stable-ID-only, and excludes operational context and free text.
|
|
33
|
+
The RPC recomputes each delivery digest from an explicit JSON body, validates the
|
|
34
|
+
frozen nested receipt contract, and requires receipt prediction identities to exactly
|
|
35
|
+
match the embedded ledger without duplicates.
|
|
36
|
+
- Published the STRATHEX 7 consumer migration contract and reconciled maintained
|
|
37
|
+
deployment, REST, architecture, installation, and wiki guidance.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- Robust hierarchical log-time core with event and diameter effects, six species
|
|
42
|
+
physical properties, gender/missingness, recency-weighted competitor state, bounded
|
|
43
|
+
trend, cross-event borrowing, and partial pooling for zero/sparse history.
|
|
44
|
+
- Chronological split-conformal 90% prediction intervals with calibration state and
|
|
45
|
+
scope, kept separate from race-performance `std_dev`.
|
|
46
|
+
- Safe checksummed JSON core artifact with its canonical species-property lookup,
|
|
47
|
+
packaged with the wheel and one immutable
|
|
48
|
+
`PredictionBundle` snapshot per request.
|
|
49
|
+
- Optional CatBoost residual artifact and strict rolling-origin promotion gate. No
|
|
50
|
+
residual candidate is promoted in the 2.0.0 release.
|
|
51
|
+
- Deterministic joint mark optimizer using 2,048 common-random samples, exhaustive
|
|
52
|
+
global search for tractable small fields, and at most eight coordinate passes for
|
|
53
|
+
larger fields, with a bounded rounded-gap fallback.
|
|
54
|
+
- Append-only local SQLite prediction ledger, authenticated REST ledger routes,
|
|
55
|
+
immutable settlement revisions, a replayable sanitized mirror outbox, and optional
|
|
56
|
+
best-effort Supabase mirroring through migrations
|
|
57
|
+
`20260811_005_prediction_v2.sql` and `20260813_006_prediction_hash_algorithm.sql`.
|
|
58
|
+
- Frozen release evidence and a verify-only operator command: `python train_model.py`.
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- Numeric evidence is now restricted to stable identity/history, event, strictly prior
|
|
63
|
+
dated results, diameter, species physical properties, and gender including missing.
|
|
64
|
+
- `get_all_predictions()` maps `baseline` to the V2 core, `ml` to a promoted residual
|
|
65
|
+
only, `panel` to the broad fallback, and `llm` to `None`.
|
|
66
|
+
- `HandicapCalculator.calculate()` snapshots the engine once and chooses marks jointly.
|
|
67
|
+
- REST responses include interval, engine/model/calibration, warning, optimizer,
|
|
68
|
+
prediction-ID, degradation, and ledger-state fields.
|
|
69
|
+
- Public `/calculate` and `/predict` remain stateless. Trusted writes use
|
|
70
|
+
`/ledger/calculate` and require stable IDs, bearer authentication, and `request_id`.
|
|
71
|
+
|
|
72
|
+
### Retired
|
|
73
|
+
|
|
74
|
+
- Numeric LLM generation, selection, and adjustment. LLMs remain available only for
|
|
75
|
+
narrative features.
|
|
76
|
+
- Numeric use of division, round/heat, venue, lane/stand, run order, exact material
|
|
77
|
+
identity, wood quality/moisture, weather, equipment, fatigue, penalty/DNF state,
|
|
78
|
+
same-tournament weighting, and field strength. Legacy inputs remain accepted as
|
|
79
|
+
documented no-ops for one migration release.
|
|
80
|
+
|
|
81
|
+
### Validation
|
|
82
|
+
|
|
83
|
+
- Frozen 128-row temporal test: MAE 16.1301 vs 20.5172 for the strict prior-only
|
|
84
|
+
incumbent (21.38% lower); RMSE 33.6904 vs 44.4791 (24.26% lower); 90% interval
|
|
85
|
+
coverage 94.53%. These results apply only to the checked-in workbook and split;
|
|
86
|
+
cohort samples are smaller and no universal accuracy or fairness claim is made.
|
|
87
|
+
|
|
88
|
+
### Migration
|
|
89
|
+
|
|
90
|
+
- Default engine is V2. Set `STRATHMARK_PREDICTION_ENGINE=legacy` for the temporary,
|
|
91
|
+
deterministic baseline-only rollback. The rollback never invokes an LLM numerically.
|
|
92
|
+
- See `docs/PREDICTION_ENGINE_V2.md` and `docs/DEPLOYMENT.md` before upgrading a live
|
|
93
|
+
consumer.
|
|
94
|
+
|
|
95
|
+
## [1.0.0] - 2026-05-08
|
|
96
|
+
|
|
97
|
+
First public PyPI release. No API changes relative to 0.5.0; the 1.0.0 designation marks publication readiness, not a redesign. The library has been production-tested for multiple seasons across STRATHEX and the Missoula Pro-Am tournament manager.
|
|
98
|
+
|
|
99
|
+
### Added
|
|
100
|
+
- PyPI distribution metadata: `Development Status :: 5 - Production/Stable`, `License :: OSI Approved :: Apache Software License`, `Operating System :: OS Independent`, and `Topic :: Software Development :: Libraries` classifiers.
|
|
101
|
+
- `[project.urls]` entries for Homepage, Issues, Documentation, and Changelog (in addition to the existing Source URL).
|
|
102
|
+
- Author email field in `[project.authors]`.
|
|
103
|
+
- Lower bound on the `ollama` optional dependency (`ollama>=0.3`) in the `[llm]` extra; previously unconstrained.
|
|
104
|
+
|
|
105
|
+
### Changed
|
|
106
|
+
- Version bumped from 0.5.0 to 1.0.0 to mark the first stable PyPI release. `__version__` in `strathmark/__init__.py` updated to match.
|
|
107
|
+
- README image and inter-doc links rewritten as absolute GitHub URLs (`https://raw.githubusercontent.com/.../main/...` for the logo, `https://github.com/SquirmyWormy275/STRATHMARK/blob/main/...` and `.../tree/main/...` for documents and directories) so they render correctly on the PyPI project page.
|
|
108
|
+
- README test-count figure updated from 708 to 759 to match the current suite.
|
|
109
|
+
- `.gitignore` virtual-environment block extended with `.venv*/` so per-purpose venvs (e.g. `.venv-pypi-readiness`) are ignored without relying on Python's venv-internal `.gitignore`.
|
|
110
|
+
|
|
111
|
+
### Fixed
|
|
112
|
+
- README "Usage" prose claimed `HandicapCalculator().calculate()` returns `CalculationResult` objects with a `gap` attribute. The actual return type is `MarkResult` (defined in `strathmark.calculator`) with fields `name`, `mark`, `predicted_time`, `method_used`, `confidence`, `explanation`, `std_dev`. README rewritten to match the real API. Discovered by running the README example against the built wheel.
|
|
113
|
+
|
|
114
|
+
### Removed
|
|
115
|
+
- Placeholder LinkedIn line in the README "About the author" section.
|
|
116
|
+
|
|
117
|
+
## [0.5.0] - 2026-05-08
|
|
118
|
+
|
|
119
|
+
### Added
|
|
120
|
+
- MNEMEX integration: STRATHMARK Supabase becomes a hydrated cache of canonical results held in a separate MNEMEX project. Sync runs in dry-run mode until `MNEMEX_SUPABASE_URL`/`MNEMEX_SUPABASE_KEY` are configured.
|
|
121
|
+
- `strathmark/mnemex.py` — read-only MNEMEX client plus competitor registration helper. Reads canonical results, looks up canonical competitors, mints new ones via ULID.
|
|
122
|
+
- `strathmark/sync.py` — three sync paths sharing one upsert core: `nightly_batch()` (cron at 03:00 UTC), `strathex_finalization(event_id)` (webhook), `manual_force_sync(show_name=None, since=None)` (admin button / CLI). Failures raise after writing an audit-trail row to `sync_log`.
|
|
123
|
+
- `strathmark/drift.py` — calibration drift detection. `evaluate_drift(model_version_id, lookback_days=30)` returns a `DriftReport` with mean-shift, variance-ratio, and empirical-coverage alerts. Advisory only; never auto-deactivates a model.
|
|
124
|
+
- `strathmark/db.py` ML state writes: `register_model_version()`, `set_active_model()`, `record_calibration()`, `store_features()`, `record_prediction()`, `settle_prediction()`. Best-effort vs raise-on-failure discipline matches the policy doc.
|
|
125
|
+
- `_BiasCircuitBreaker` in `strathmark/predictor.py` — 60-second sliding window, 3-strike threshold, auto-reset. Replaces the prior session-level disable so transient Supabase blips don't permanently degrade bias correction.
|
|
126
|
+
- Three SQL migrations under `strathmark/migrations/`: `001` adds source-tracking columns (`source_type`, `mnemex_id`), `002` creates ML state tables (`model_versions`, `calibration_tables`, `feature_store`, `predictions`, `prediction_residuals` extensions), `003` reframes RLS for controlled-write enforcement (FORCE ROW LEVEL SECURITY plus a dedicated `mnemex_sync` role plumbing checklist).
|
|
127
|
+
- `scripts/rekey_against_mnemex.py` — idempotent re-keying script that fills in `mnemex_id` on existing STRATHMARK competitor rows from MNEMEX. Refuses to commit below the 95% match-rate threshold without `--force`.
|
|
128
|
+
- `docs/ml-persistence-policy.md` — policy doc covering retraining cadence, model versioning, calibration drift, feature store, hot-path circuit breaker, non-blocking guarantee.
|
|
129
|
+
- `docs/schema-reality-2026-05-04.md`, `docs/cleanup-candidates-2026-05-04.md`, `docs/ml-research-questions.md` — Phase 1 schema verification plus a cleanup audit confirming zero stray validation rows.
|
|
130
|
+
- 65 new tests across `tests/test_mnemex.py`, `tests/test_sync.py`, `tests/test_drift.py`, `tests/test_circuit_breaker.py`, `tests/test_ml_state.py`, plus 277 lines of additions to `tests/test_db.py`.
|
|
131
|
+
|
|
132
|
+
### Changed
|
|
133
|
+
- `register_competitor()` rewrite: routes through MNEMEX when configured, falls back to STRATHMARK-local mint with a deprecation warning when MNEMEX is unset. Default `wait_for_sync=False`; opting in to blocking requires explicit kwarg.
|
|
134
|
+
- `get_competitor_bias()` no longer swallows DB exceptions internally. Callers on the prediction hot path wrap in `_BiasCircuitBreaker`; the policy is documented in `docs/ml-persistence-policy.md` section 5.
|
|
135
|
+
- `_do_sync` writes a failure sync_log row before re-raising on Supabase upsert error, so the audit trail is preserved AND callers see a non-zero exit (matches the module docstring).
|
|
136
|
+
- Added `ulid-py>=1.1` to base dependencies.
|
|
137
|
+
|
|
138
|
+
### Fixed
|
|
139
|
+
- Cascade naming mismatch: `record_prediction` validator and the `predictions_cascade_level_check` constraint now accept `'panel'` instead of `'panel_fallback'`, matching the canonical emitter strings in `strathmark/predictor.py`.
|
|
140
|
+
- Drift detection's coverage rule now compares empirical coverage of recent residuals against a 90% prediction interval derived from baseline residual quantiles, replacing a check that compared the static calibration-time `coverage_at_90` value against a fixed band.
|
|
141
|
+
- RLS migration `003` now adds `FORCE ROW LEVEL SECURITY` to all governed tables, closing the BYPASSRLS bypass on `service_role`. Pre-application checklist expanded to require role plumbing AND `NOBYPASSRLS` rotation. The `wood_species_write_admin` policy no longer ORs in `service_role` (contradicted the header's "wood_admin only" intent).
|
|
142
|
+
|
|
143
|
+
## [0.4.1] - 2026-04-21
|
|
144
|
+
|
|
145
|
+
### Added
|
|
146
|
+
- `ONBOARDING.md` at repo root — routing hub for new contributors by task (bug fix, feature, deployment debug, AI agent)
|
|
147
|
+
- 7 new learning docs in `docs/solutions/`:
|
|
148
|
+
- `best-practices/llm-cascade-and-monte-carlo-tuning-2026-04-21.md` — cross-cutting v0.3.0 hardening narrative
|
|
149
|
+
- `best-practices/optional-dependency-gating-importorskip.md` — `[extras]` split + `pytest.importorskip` placement gotcha
|
|
150
|
+
- `best-practices/config-env-vars-importlib-reload-pattern.md` — test pattern for import-time env vars
|
|
151
|
+
- `architecture-decisions/dual-store-sqlite-supabase-split.md` — offline-first rationale for SQLite + Supabase
|
|
152
|
+
- `architecture-decisions/ensemble-predictor-design-decisions.md` — accepted design + deferred scope for TODO-001..011
|
|
153
|
+
- `test-failures/regression-test-must-include-triggering-input.md` — Codex-caught regression-coverage pattern
|
|
154
|
+
- `workflow-patterns/eng-review-cycle-and-todos-handoff.md` — plan-review → TODOS.md → impl → Codex → ship pattern
|
|
155
|
+
|
|
156
|
+
### Changed
|
|
157
|
+
- `docs/solutions/architecture-decisions/prediction-cascade-order.md` — added v0.3.0 provenance for JSON-schema / temp=0 / quality==5, cross-link to new hardening doc, `last_updated: 2026-04-21`
|
|
158
|
+
- `docs/solutions/architecture-decisions/mark-floor-ceiling-invariants.md` — added pre-v0.3.0 ceiling-rounding historical note, cross-link to new hardening doc, `last_updated: 2026-04-21`
|
|
159
|
+
- `strathmark/__init__.py` — `__version__` corrected from `0.3.1` (stale) to `0.4.1`
|
|
160
|
+
- `README.md` — version string updated to 0.4.1 and onboarding pointer added
|
|
161
|
+
|
|
162
|
+
## [0.4.0] - 2026-04-07
|
|
163
|
+
|
|
164
|
+
### Added
|
|
165
|
+
- Gemini cloud fallback (`google-generativeai`) in `llm.py` as a race-day fail-through when Ollama is unreachable
|
|
166
|
+
- `_env_int`/`_env_str` helpers in `config.py` for safe env-var parsing with sensible fallbacks
|
|
167
|
+
- `scripts/validate_deployment.py` — pre-event read-only deployment validation
|
|
168
|
+
- `scripts/ingest_proam_results.py` — post-event Pro-Am result ingestion with dry-run / --commit modes
|
|
169
|
+
- `push_results_dicts()` and `register_competitor()` public helpers for programmatic ingestion
|
|
170
|
+
- `docs/DEPLOYMENT.md` — full deployment guide
|
|
171
|
+
- `tests/test_deployment_fallbacks.py` — fail-fast cascade tests for unreachable Ollama / Supabase
|
|
172
|
+
|
|
173
|
+
### Changed
|
|
174
|
+
- Race-day Ollama defaults: `TIMEOUT_SECONDS` and `MAX_RETRIES` now env-overridable via `STRATHMARK_OLLAMA_*`; default `MAX_RETRIES=0` for fail-fast cascade behavior
|
|
175
|
+
- `STRATHMARK_OLLAMA_URL` / `STRATHMARK_OLLAMA_TIMEOUT` / `STRATHMARK_OLLAMA_MAX_RETRIES` now documented as first-class operational knobs
|
|
176
|
+
|
|
177
|
+
### Fixed
|
|
178
|
+
- Ollama cascade hang on unreachable host (120s blocking per call) — fail-fast via reduced timeout + zero retries
|
|
179
|
+
- Ollama status cache race condition under concurrent FastAPI requests — `threading.Lock` protecting cache reads/writes
|
|
180
|
+
- `LLMConfig` env-var resolution now happens at call time (via helpers) for hot-swappable values, while import-time frozen dataclass is retained for stable params
|
|
181
|
+
|
|
182
|
+
## [0.3.1] - 2026-03-24
|
|
183
|
+
|
|
184
|
+
### Added
|
|
185
|
+
- 221 new tests across 9 test files, bringing total from 446 to 667
|
|
186
|
+
- Regression tests for fixed bugs: banker's rounding, decay weights, timeout filtering, absolute variance, mark floor/ceiling enforcement
|
|
187
|
+
- Boundary tests for extreme values: 50-competitor fields, diameters 50-600mm, quality clamping, consistency rating thresholds
|
|
188
|
+
- Config invariant tests: frozen dataclass enforcement, rules consistency, threshold ordering, ML/LLM config sanity
|
|
189
|
+
- Extended decay tests: exponential precision, date type handling, adaptive vs fixed weighting, robust MAD clipping
|
|
190
|
+
- Extended store tests: CRUD, duplicate detection, DataFrame round-trips, column aliases, date handling
|
|
191
|
+
- Extended visualization tests: ASCII bar chart accuracy, line width, percentage sums, large field rendering
|
|
192
|
+
- Predictor regression tests: cascade priority, tournament weighting with num_tournament_rounds, division fallback
|
|
193
|
+
- Full pipeline integration tests: predict-calculate-simulate round-trips, multi-event days, store round-trips, simulation determinism
|
|
194
|
+
- Wood boundary tests: species multipliers, Janka hardness monotonicity, event scaling exponents
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Contributing to STRATHMARK
|
|
2
|
+
|
|
3
|
+
STRATHMARK is the shared handicap calculation core for STRATHEX,
|
|
4
|
+
Missoula-Pro-Am-Manager, and any future tournament manager built on the
|
|
5
|
+
same engine. Changes here propagate downstream, so the bar for tests and
|
|
6
|
+
lint is intentionally strict.
|
|
7
|
+
|
|
8
|
+
## Development install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install -e ".[dev]"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Optional extras you may also want while working on specific subsystems:
|
|
15
|
+
|
|
16
|
+
- `pip install -e ".[ml]"` — XGBoost / LightGBM / scikit-learn predictor
|
|
17
|
+
- `pip install -e ".[db]"` — Supabase backend
|
|
18
|
+
- `pip install -e ".[api]"` — FastAPI server
|
|
19
|
+
- `pip install -e ".[llm]"` — optional narrative-analysis client
|
|
20
|
+
|
|
21
|
+
## Running the test suite
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pytest tests/ -v
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Supabase-backed db tests are gated behind `STRATHMARK_TEST_DB=1` and skip
|
|
28
|
+
by default. ML predictor paths fall back to baseline when the `[ml]` extras
|
|
29
|
+
are not installed, so you do not need them to get a green run. Install
|
|
30
|
+
`.[dev,api]` to run the REST API contract tests locally.
|
|
31
|
+
|
|
32
|
+
## Linting and formatting
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
ruff check .
|
|
36
|
+
ruff format --check .
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
To auto-fix and apply formatting:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
ruff check . --fix
|
|
43
|
+
ruff format .
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## CI
|
|
47
|
+
|
|
48
|
+
GitHub Actions runs lint, the full test matrix (Ubuntu + Windows across
|
|
49
|
+
Python 3.10 through 3.13), oldest/current API dependency contracts, release and
|
|
50
|
+
cross-platform golden verification, the optimizer capacity gate, and isolated wheel
|
|
51
|
+
and source-distribution installs. **All PRs must pass CI before merge.** The workflow
|
|
52
|
+
definitions live under [`.github/workflows/`](.github/workflows/).
|
|
53
|
+
|
|
54
|
+
## Design rules (non-negotiable)
|
|
55
|
+
|
|
56
|
+
These are enforced in code and in review. See the README's *Design rules*
|
|
57
|
+
section for the full list, but the load-bearing ones are:
|
|
58
|
+
|
|
59
|
+
- Mark floor: 3 seconds
|
|
60
|
+
- Mark ceiling: 183 seconds system-wide
|
|
61
|
+
- Variance: performance uncertainty is represented in absolute seconds; proportional
|
|
62
|
+
scaling is only a clamped no-history fallback
|
|
63
|
+
- Prediction engine: manual override, otherwise the validated V2 posterior with deterministic fallback
|
|
64
|
+
- Output: plain text only, no emojis, no ANSI color codes
|