loadcoach 1.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.
- loadcoach-1.0.0/.editorconfig +23 -0
- loadcoach-1.0.0/.github/workflows/ci.yml +174 -0
- loadcoach-1.0.0/.github/workflows/release.yml +63 -0
- loadcoach-1.0.0/.gitignore +100 -0
- loadcoach-1.0.0/.importlinter +40 -0
- loadcoach-1.0.0/.pre-commit-config.yaml +22 -0
- loadcoach-1.0.0/CHANGELOG.md +635 -0
- loadcoach-1.0.0/CONTRIBUTING.md +50 -0
- loadcoach-1.0.0/LICENSE +201 -0
- loadcoach-1.0.0/PKG-INFO +120 -0
- loadcoach-1.0.0/README.md +75 -0
- loadcoach-1.0.0/SECURITY.md +39 -0
- loadcoach-1.0.0/docs/README.md +16 -0
- loadcoach-1.0.0/docs/apps/loadcoach/api.md +305 -0
- loadcoach-1.0.0/docs/apps/loadcoach/data-model.md +281 -0
- loadcoach-1.0.0/docs/apps/loadcoach/development-plan.md +484 -0
- loadcoach-1.0.0/docs/apps/loadcoach/queue-and-scheduling.md +322 -0
- loadcoach-1.0.0/docs/apps/loadcoach/risks.md +105 -0
- loadcoach-1.0.0/docs/apps/loadcoach/routing.md +341 -0
- loadcoach-1.0.0/docs/apps/loadcoach/spec.md +387 -0
- loadcoach-1.0.0/docs/configuration.md +158 -0
- loadcoach-1.0.0/docs/openapi.json +1984 -0
- loadcoach-1.0.0/docs/operations.md +99 -0
- loadcoach-1.0.0/docs/quickstart.md +91 -0
- loadcoach-1.0.0/docs/routing.md +64 -0
- loadcoach-1.0.0/docs/security.md +104 -0
- loadcoach-1.0.0/docs/troubleshooting.md +65 -0
- loadcoach-1.0.0/docs/upgrading.md +52 -0
- loadcoach-1.0.0/pyproject.toml +127 -0
- loadcoach-1.0.0/requirements/.gitkeep +1 -0
- loadcoach-1.0.0/requirements/README.md +76 -0
- loadcoach-1.0.0/requirements/ci.lock +1521 -0
- loadcoach-1.0.0/requirements/release.in +6 -0
- loadcoach-1.0.0/requirements/release.lock +493 -0
- loadcoach-1.0.0/src/loadcoach/__about__.py +1 -0
- loadcoach-1.0.0/src/loadcoach/__main__.py +12 -0
- loadcoach-1.0.0/src/loadcoach/bootstrap.py +157 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/config.py +169 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/db.py +249 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/evidence.py +347 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/generate.py +134 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/job.py +394 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/models.py +215 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/queue.py +162 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/reliability.py +92 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/route.py +191 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/system.py +137 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/tasks.py +158 -0
- loadcoach-1.0.0/src/loadcoach/cli/commands/token.py +146 -0
- loadcoach-1.0.0/src/loadcoach/cli/main.py +84 -0
- loadcoach-1.0.0/src/loadcoach/config/manual_capability_scores.toml +15 -0
- loadcoach-1.0.0/src/loadcoach/config/schemas/code_debug_findings.json +13 -0
- loadcoach-1.0.0/src/loadcoach/config/schemas/code_review_findings.json +25 -0
- loadcoach-1.0.0/src/loadcoach/config/schemas/content_review_findings.json +24 -0
- loadcoach-1.0.0/src/loadcoach/config/schemas/fact_check_findings.json +26 -0
- loadcoach-1.0.0/src/loadcoach/config/schemas/structured_extract.json +11 -0
- loadcoach-1.0.0/src/loadcoach/config/task_profiles.toml +417 -0
- loadcoach-1.0.0/src/loadcoach/config.py +894 -0
- loadcoach-1.0.0/src/loadcoach/domain/admission.py +230 -0
- loadcoach-1.0.0/src/loadcoach/domain/authorization.py +105 -0
- loadcoach-1.0.0/src/loadcoach/domain/circuit_breaker.py +357 -0
- loadcoach-1.0.0/src/loadcoach/domain/evidence_policy.py +848 -0
- loadcoach-1.0.0/src/loadcoach/domain/priority.py +158 -0
- loadcoach-1.0.0/src/loadcoach/domain/queue_state.py +214 -0
- loadcoach-1.0.0/src/loadcoach/domain/registry.py +194 -0
- loadcoach-1.0.0/src/loadcoach/domain/reliability.py +812 -0
- loadcoach-1.0.0/src/loadcoach/domain/retry_policy.py +192 -0
- loadcoach-1.0.0/src/loadcoach/domain/routing/constraints.py +567 -0
- loadcoach-1.0.0/src/loadcoach/domain/routing/context_budget.py +188 -0
- loadcoach-1.0.0/src/loadcoach/domain/routing/explanation.py +288 -0
- loadcoach-1.0.0/src/loadcoach/domain/routing/narrative.py +360 -0
- loadcoach-1.0.0/src/loadcoach/domain/routing/ranking.py +118 -0
- loadcoach-1.0.0/src/loadcoach/domain/routing/scoring.py +549 -0
- loadcoach-1.0.0/src/loadcoach/domain/routing/subject.py +343 -0
- loadcoach-1.0.0/src/loadcoach/domain/task_profile.py +221 -0
- loadcoach-1.0.0/src/loadcoach/domain/validation.py +399 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/migrations/.gitkeep +0 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/migrations/env.py +34 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/migrations/script.py.mako +26 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/migrations/versions/0001_initial_schema.py +161 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/migrations/versions/0002_routing_decisions.py +118 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/migrations/versions/0003_jobs_and_attempts.py +218 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/migrations/versions/0004_residency.py +84 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/migrations/versions/0005_capability_evidence.py +143 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/migrations/versions/0006_feedback_and_reliability.py +111 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/models.py +727 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/repositories/.gitkeep +0 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/db/repositories/settings.py +51 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/freeweight_client.py +470 -0
- loadcoach-1.0.0/src/loadcoach/infrastructure/providers/factory.py +63 -0
- loadcoach-1.0.0/src/loadcoach/observability/logging.py +144 -0
- loadcoach-1.0.0/src/loadcoach/prompts/.gitkeep +0 -0
- loadcoach-1.0.0/src/loadcoach/prompts/execution/structured_output.retry.v1.json +38 -0
- loadcoach-1.0.0/src/loadcoach/prompts/manifest.json +14 -0
- loadcoach-1.0.0/src/loadcoach/services/config_reference.py +154 -0
- loadcoach-1.0.0/src/loadcoach/services/dashboard.py +191 -0
- loadcoach-1.0.0/src/loadcoach/services/database.py +359 -0
- loadcoach-1.0.0/src/loadcoach/services/doctor.py +535 -0
- loadcoach-1.0.0/src/loadcoach/services/evidence.py +1563 -0
- loadcoach-1.0.0/src/loadcoach/services/execution.py +1589 -0
- loadcoach-1.0.0/src/loadcoach/services/feedback.py +245 -0
- loadcoach-1.0.0/src/loadcoach/services/health.py +379 -0
- loadcoach-1.0.0/src/loadcoach/services/job_events.py +287 -0
- loadcoach-1.0.0/src/loadcoach/services/machine.py +73 -0
- loadcoach-1.0.0/src/loadcoach/services/models.py +485 -0
- loadcoach-1.0.0/src/loadcoach/services/prompts.py +63 -0
- loadcoach-1.0.0/src/loadcoach/services/queue.py +1501 -0
- loadcoach-1.0.0/src/loadcoach/services/queue_stream.py +151 -0
- loadcoach-1.0.0/src/loadcoach/services/recovery.py +165 -0
- loadcoach-1.0.0/src/loadcoach/services/reliability.py +450 -0
- loadcoach-1.0.0/src/loadcoach/services/residency.py +367 -0
- loadcoach-1.0.0/src/loadcoach/services/retention.py +126 -0
- loadcoach-1.0.0/src/loadcoach/services/routing.py +903 -0
- loadcoach-1.0.0/src/loadcoach/services/settings.py +271 -0
- loadcoach-1.0.0/src/loadcoach/services/status.py +125 -0
- loadcoach-1.0.0/src/loadcoach/services/task_profiles.py +140 -0
- loadcoach-1.0.0/src/loadcoach/services/telemetry_stream.py +170 -0
- loadcoach-1.0.0/src/loadcoach/services/tokens.py +164 -0
- loadcoach-1.0.0/src/loadcoach/services/worker.py +1920 -0
- loadcoach-1.0.0/src/loadcoach/web/app.py +404 -0
- loadcoach-1.0.0/src/loadcoach/web/auth.py +189 -0
- loadcoach-1.0.0/src/loadcoach/web/csrf.py +55 -0
- loadcoach-1.0.0/src/loadcoach/web/limits.py +149 -0
- loadcoach-1.0.0/src/loadcoach/web/rate_limit.py +282 -0
- loadcoach-1.0.0/src/loadcoach/web/rendering.py +79 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/access.py +44 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/dashboard.py +36 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/evidence.py +263 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/generate.py +372 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/jobs.py +411 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/models.py +153 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/queue.py +181 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/reliability.py +103 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/routing.py +203 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/settings.py +106 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/system.py +110 -0
- loadcoach-1.0.0/src/loadcoach/web/routes/task_profiles.py +59 -0
- loadcoach-1.0.0/src/loadcoach/web/routing_support.py +87 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/.gitkeep +0 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/dashboard/index.html +89 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/error.html +34 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/evidence/index.html +105 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/jobs/detail.html +100 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/jobs/index.html +46 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/models/index.html +42 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/queue/_live.html +63 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/queue/index.html +47 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/reliability/index.html +106 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/routing/_narrative.html +67 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/routing/detail.html +85 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/routing/index.html +30 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/settings/index.html +39 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/system/index.html +84 -0
- loadcoach-1.0.0/src/loadcoach/web/templates/task_profiles/index.html +24 -0
- loadcoach-1.0.0/tests/accessibility/test_ui_checklist.py +270 -0
- loadcoach-1.0.0/tests/conftest.py +128 -0
- loadcoach-1.0.0/tests/contract/test_evidence_import.py +201 -0
- loadcoach-1.0.0/tests/contract/test_openapi_snapshot.py +68 -0
- loadcoach-1.0.0/tests/contract/test_schema_rejection.py +185 -0
- loadcoach-1.0.0/tests/e2e/test_dashboard.py +137 -0
- loadcoach-1.0.0/tests/e2e/test_job_detail.py +159 -0
- loadcoach-1.0.0/tests/e2e/test_model_and_profile_detail.py +55 -0
- loadcoach-1.0.0/tests/e2e/test_models_and_task_profiles.py +99 -0
- loadcoach-1.0.0/tests/e2e/test_queue_controls.py +100 -0
- loadcoach-1.0.0/tests/e2e/test_server_boot.py +120 -0
- loadcoach-1.0.0/tests/e2e/test_settings.py +119 -0
- loadcoach-1.0.0/tests/e2e/test_system_page.py +41 -0
- loadcoach-1.0.0/tests/integration/_other_app_fixture/env.py +35 -0
- loadcoach-1.0.0/tests/integration/_other_app_fixture/models.py +29 -0
- loadcoach-1.0.0/tests/integration/_other_app_fixture/versions/0001_create_machines.py +29 -0
- loadcoach-1.0.0/tests/integration/test_breaker_probe.py +207 -0
- loadcoach-1.0.0/tests/integration/test_breaker_sync_path.py +135 -0
- loadcoach-1.0.0/tests/integration/test_cancellation.py +88 -0
- loadcoach-1.0.0/tests/integration/test_discovery.py +165 -0
- loadcoach-1.0.0/tests/integration/test_evidence_api.py +453 -0
- loadcoach-1.0.0/tests/integration/test_evidence_fetch.py +638 -0
- loadcoach-1.0.0/tests/integration/test_evidence_importer.py +603 -0
- loadcoach-1.0.0/tests/integration/test_evidence_routing_change.py +635 -0
- loadcoach-1.0.0/tests/integration/test_feedback_affects_routing.py +586 -0
- loadcoach-1.0.0/tests/integration/test_feedback_api.py +240 -0
- loadcoach-1.0.0/tests/integration/test_generate.py +405 -0
- loadcoach-1.0.0/tests/integration/test_jobs_api.py +275 -0
- loadcoach-1.0.0/tests/integration/test_migrations.py +582 -0
- loadcoach-1.0.0/tests/integration/test_queue.py +586 -0
- loadcoach-1.0.0/tests/integration/test_queue_stream.py +188 -0
- loadcoach-1.0.0/tests/integration/test_recovery.py +232 -0
- loadcoach-1.0.0/tests/integration/test_reliability_api.py +164 -0
- loadcoach-1.0.0/tests/integration/test_retention.py +131 -0
- loadcoach-1.0.0/tests/integration/test_route_endpoint.py +487 -0
- loadcoach-1.0.0/tests/integration/test_streaming.py +326 -0
- loadcoach-1.0.0/tests/integration/test_validation.py +300 -0
- loadcoach-1.0.0/tests/integration/test_worker.py +103 -0
- loadcoach-1.0.0/tests/live/test_ollama_generation.py +115 -0
- loadcoach-1.0.0/tests/performance/.gitkeep +0 -0
- loadcoach-1.0.0/tests/performance/test_generate_overhead.py +110 -0
- loadcoach-1.0.0/tests/performance/test_queue_budgets.py +288 -0
- loadcoach-1.0.0/tests/performance/test_routing_budgets.py +227 -0
- loadcoach-1.0.0/tests/performance/test_streaming_gap.py +105 -0
- loadcoach-1.0.0/tests/security/.gitkeep +0 -0
- loadcoach-1.0.0/tests/security/test_checklist.py +427 -0
- loadcoach-1.0.0/tests/security/test_queue_cap.py +38 -0
- loadcoach-1.0.0/tests/security/test_rate_limit.py +201 -0
- loadcoach-1.0.0/tests/security/test_scopes.py +472 -0
- loadcoach-1.0.0/tests/simulation/simulator.py +1015 -0
- loadcoach-1.0.0/tests/simulation/test_scale.py +110 -0
- loadcoach-1.0.0/tests/simulation/test_scheduling_properties.py +1176 -0
- loadcoach-1.0.0/tests/simulation/test_simulator_mechanics.py +341 -0
- loadcoach-1.0.0/tests/unit/test_admission.py +122 -0
- loadcoach-1.0.0/tests/unit/test_circuit_breaker.py +138 -0
- loadcoach-1.0.0/tests/unit/test_cli.py +355 -0
- loadcoach-1.0.0/tests/unit/test_config.py +180 -0
- loadcoach-1.0.0/tests/unit/test_config_reference.py +53 -0
- loadcoach-1.0.0/tests/unit/test_doctor.py +174 -0
- loadcoach-1.0.0/tests/unit/test_evidence_policy.py +504 -0
- loadcoach-1.0.0/tests/unit/test_health.py +162 -0
- loadcoach-1.0.0/tests/unit/test_priority.py +113 -0
- loadcoach-1.0.0/tests/unit/test_queue_state.py +142 -0
- loadcoach-1.0.0/tests/unit/test_registry.py +127 -0
- loadcoach-1.0.0/tests/unit/test_reliability_math.py +586 -0
- loadcoach-1.0.0/tests/unit/test_residency_service.py +139 -0
- loadcoach-1.0.0/tests/unit/test_retry_policy.py +102 -0
- loadcoach-1.0.0/tests/unit/test_routing_constraints.py +425 -0
- loadcoach-1.0.0/tests/unit/test_routing_context_budget.py +115 -0
- loadcoach-1.0.0/tests/unit/test_routing_explanation.py +170 -0
- loadcoach-1.0.0/tests/unit/test_routing_narrative.py +222 -0
- loadcoach-1.0.0/tests/unit/test_routing_ranking.py +161 -0
- loadcoach-1.0.0/tests/unit/test_routing_scoring.py +285 -0
- loadcoach-1.0.0/tests/unit/test_routing_subject.py +110 -0
- loadcoach-1.0.0/tests/unit/test_task_profile_validation.py +125 -0
- loadcoach-1.0.0/tests/unit/test_telemetry_stream.py +100 -0
- loadcoach-1.0.0/tests/unit/test_tokens.py +116 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 4
|
|
10
|
+
|
|
11
|
+
[*.py]
|
|
12
|
+
indent_size = 4
|
|
13
|
+
max_line_length = 100
|
|
14
|
+
|
|
15
|
+
[*.{toml,yml,yaml,json}]
|
|
16
|
+
indent_size = 2
|
|
17
|
+
|
|
18
|
+
[*.md]
|
|
19
|
+
trim_trailing_whitespace = false
|
|
20
|
+
max_line_length = off
|
|
21
|
+
|
|
22
|
+
[Makefile]
|
|
23
|
+
indent_style = tab
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
format:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with: { python-version: "3.12" }
|
|
15
|
+
- run: pip install ruff
|
|
16
|
+
- run: ruff format --check .
|
|
17
|
+
|
|
18
|
+
lint:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with: { python-version: "3.12" }
|
|
24
|
+
- run: pip install ruff
|
|
25
|
+
- run: ruff check .
|
|
26
|
+
|
|
27
|
+
# Every job below installs from the hash-pinned lock and then the package itself with
|
|
28
|
+
# `--no-deps` (Packaging Standards §4): what CI tests is what `requirements/ci.lock` resolved,
|
|
29
|
+
# not today's resolution, and the package is installed non-editably so coverage and imports
|
|
30
|
+
# measure the installed distribution. The 3.14 early-warning job is the one deliberate
|
|
31
|
+
# exception — see its comment.
|
|
32
|
+
types:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- uses: actions/setup-python@v5
|
|
37
|
+
with: { python-version: "3.12" }
|
|
38
|
+
- run: pip install --require-hashes -r requirements/ci.lock
|
|
39
|
+
- run: pip install . --no-deps
|
|
40
|
+
- run: mypy src tests
|
|
41
|
+
|
|
42
|
+
boundaries:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v4
|
|
46
|
+
- uses: actions/setup-python@v5
|
|
47
|
+
with: { python-version: "3.12" }
|
|
48
|
+
- run: pip install --require-hashes -r requirements/ci.lock
|
|
49
|
+
- run: pip install . --no-deps
|
|
50
|
+
- run: lint-imports
|
|
51
|
+
|
|
52
|
+
tests:
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
strategy:
|
|
55
|
+
matrix:
|
|
56
|
+
python-version: ["3.12", "3.13"]
|
|
57
|
+
steps:
|
|
58
|
+
- uses: actions/checkout@v4
|
|
59
|
+
- uses: actions/setup-python@v5
|
|
60
|
+
with: { python-version: "${{ matrix.python-version }}" }
|
|
61
|
+
- run: pip install --require-hashes -r requirements/ci.lock
|
|
62
|
+
- run: pip install . --no-deps
|
|
63
|
+
- run: pytest -m "not live and not performance" --cov --cov-report=xml
|
|
64
|
+
|
|
65
|
+
tests-314-early-warning:
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
continue-on-error: true
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v4
|
|
70
|
+
- uses: actions/setup-python@v5
|
|
71
|
+
with: { python-version: "3.14" }
|
|
72
|
+
# Deliberately unpinned: ci.lock is resolved on 3.13, and pinning a version that has no
|
|
73
|
+
# 3.14 wheels would defeat the purpose of an early warning.
|
|
74
|
+
- run: pip install -e ".[dev]"
|
|
75
|
+
- run: pytest -m "not live and not performance"
|
|
76
|
+
|
|
77
|
+
db-matrix:
|
|
78
|
+
name: tests (PostgreSQL)
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
services:
|
|
81
|
+
postgres:
|
|
82
|
+
image: postgres:16
|
|
83
|
+
# Credentials and database name match `weightsdb.testing`'s documented default URL, so the
|
|
84
|
+
# service this job starts is the one the package looks for. The previous values named a
|
|
85
|
+
# `postgres`/`postgres` server nothing ever connected to: `temporary_postgres` reads
|
|
86
|
+
# WEIGHTSDB_POSTGRES_URL, not DATABASE_URL, and under REQUIRE_POSTGRES=1 the unused
|
|
87
|
+
# default was a hard failure rather than a skip — so this job had never run a query.
|
|
88
|
+
env:
|
|
89
|
+
POSTGRES_USER: weightsdb
|
|
90
|
+
POSTGRES_PASSWORD: weightsdb
|
|
91
|
+
POSTGRES_DB: weightsdb_test
|
|
92
|
+
ports: ["5432:5432"]
|
|
93
|
+
options: >-
|
|
94
|
+
--health-cmd "pg_isready -U weightsdb -d weightsdb_test" --health-interval 5s --health-timeout 5s --health-retries 10
|
|
95
|
+
steps:
|
|
96
|
+
- uses: actions/checkout@v4
|
|
97
|
+
- uses: actions/setup-python@v5
|
|
98
|
+
with: { python-version: "3.12" }
|
|
99
|
+
- run: pip install --require-hashes -r requirements/ci.lock
|
|
100
|
+
- run: pip install . --no-deps
|
|
101
|
+
- run: pytest -m "not live and not performance" tests/integration
|
|
102
|
+
env:
|
|
103
|
+
WEIGHTSDB_REQUIRE_POSTGRES: "1"
|
|
104
|
+
# Set explicitly rather than relying on the default, so the job states which server it
|
|
105
|
+
# is testing.
|
|
106
|
+
WEIGHTSDB_POSTGRES_URL: postgresql+psycopg://weightsdb:weightsdb@localhost:5432/weightsdb_test
|
|
107
|
+
|
|
108
|
+
coverage:
|
|
109
|
+
needs: [tests]
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
steps:
|
|
112
|
+
- uses: actions/checkout@v4
|
|
113
|
+
- uses: actions/setup-python@v5
|
|
114
|
+
with: { python-version: "3.12" }
|
|
115
|
+
- run: pip install --require-hashes -r requirements/ci.lock
|
|
116
|
+
- run: pip install . --no-deps
|
|
117
|
+
- run: pytest -m "not live and not performance" --cov --cov-report=term-missing --cov-fail-under=85
|
|
118
|
+
|
|
119
|
+
contracts:
|
|
120
|
+
runs-on: ubuntu-latest
|
|
121
|
+
steps:
|
|
122
|
+
- uses: actions/checkout@v4
|
|
123
|
+
- uses: actions/setup-python@v5
|
|
124
|
+
with: { python-version: "3.12" }
|
|
125
|
+
- run: pip install --require-hashes -r requirements/ci.lock
|
|
126
|
+
- run: pip install . --no-deps
|
|
127
|
+
- run: pytest -m contract
|
|
128
|
+
|
|
129
|
+
security:
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/checkout@v4
|
|
133
|
+
# gitleaks scans *history*, and `actions/checkout` fetches a single commit by default.
|
|
134
|
+
# For a push it is handed `<first-pushed>^..<last-pushed>`, so the parent of the first
|
|
135
|
+
# pushed commit has to be in the object store; in a depth-1 clone it is not, and git
|
|
136
|
+
# answers "unknown revision", which the action reports as exit code 1. It fails the same
|
|
137
|
+
# way whether or not a secret exists, so a green run would not have meant anything either.
|
|
138
|
+
with: { fetch-depth: 0 }
|
|
139
|
+
- uses: actions/setup-python@v5
|
|
140
|
+
with: { python-version: "3.12" }
|
|
141
|
+
- run: pip install pip-audit
|
|
142
|
+
# Audit the locked sets, not the job's own environment: a bare `pip-audit` here would
|
|
143
|
+
# inspect an environment containing only pip-audit itself (Security Standards §11).
|
|
144
|
+
- run: pip-audit --require-hashes -r requirements/ci.lock
|
|
145
|
+
- run: pip-audit --require-hashes -r requirements/release.lock
|
|
146
|
+
- uses: gitleaks/gitleaks-action@v2
|
|
147
|
+
env:
|
|
148
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
149
|
+
|
|
150
|
+
build:
|
|
151
|
+
runs-on: ubuntu-latest
|
|
152
|
+
steps:
|
|
153
|
+
- uses: actions/checkout@v4
|
|
154
|
+
- uses: actions/setup-python@v5
|
|
155
|
+
with: { python-version: "3.12" }
|
|
156
|
+
# The pinned build chain, byte-for-byte what `release.yml` uses, so a release is the
|
|
157
|
+
# artifact CI proved rather than a fresh resolution of `build` and `hatchling`.
|
|
158
|
+
- run: pip install --require-hashes -r requirements/release.lock
|
|
159
|
+
- run: python -m build --no-isolation
|
|
160
|
+
- run: twine check dist/*
|
|
161
|
+
- uses: actions/upload-artifact@v4
|
|
162
|
+
with: { name: dist, path: dist/ }
|
|
163
|
+
|
|
164
|
+
install-check:
|
|
165
|
+
needs: [build]
|
|
166
|
+
runs-on: ubuntu-latest
|
|
167
|
+
steps:
|
|
168
|
+
- uses: actions/checkout@v4
|
|
169
|
+
- uses: actions/setup-python@v5
|
|
170
|
+
with: { python-version: "3.12" }
|
|
171
|
+
- uses: actions/download-artifact@v4
|
|
172
|
+
with: { name: dist, path: dist/ }
|
|
173
|
+
- run: pip install dist/*.whl
|
|
174
|
+
- run: python -c "import loadcoach"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*.*.*"]
|
|
6
|
+
workflow_dispatch: # manual TestPyPI dry run; see publish-testpypi below
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write # required for PyPI Trusted Publishing
|
|
10
|
+
contents: write # required to create the GitHub release
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
release:
|
|
14
|
+
# Tag pushes only. Without this, clicking "Run workflow" for the TestPyPI dry run below would
|
|
15
|
+
# also fire this job and publish to real PyPI — the exact opposite of a dry run.
|
|
16
|
+
if: github.event_name == 'push'
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
environment: pypi # must match the Environment name set on the PyPI trusted publisher
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with: { python-version: "3.12" }
|
|
23
|
+
# Byte-for-byte the dry run's build chain below. A real release that resolved `build` and
|
|
24
|
+
# `hatchling` fresh from PyPI would not be the artifact the dry run proved.
|
|
25
|
+
- run: pip install --require-hashes -r requirements/release.lock
|
|
26
|
+
- run: python -m build --no-isolation
|
|
27
|
+
- run: twine check dist/*
|
|
28
|
+
# NOTE: this step cannot succeed until `weightsdb 0.2.0` and `mirrorwall 0.2.0` are
|
|
29
|
+
# published — both are runtime dependencies of this package and neither is on any
|
|
30
|
+
# index today. See requirements/README.md.
|
|
31
|
+
- run: pip install "dist/$(ls dist | grep .whl)[dev]"
|
|
32
|
+
- run: pytest -m "not live and not performance"
|
|
33
|
+
- name: Publish to PyPI
|
|
34
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
35
|
+
- name: Create GitHub release
|
|
36
|
+
uses: softprops/action-gh-release@v2
|
|
37
|
+
with:
|
|
38
|
+
generate_release_notes: true
|
|
39
|
+
files: dist/*
|
|
40
|
+
|
|
41
|
+
publish-testpypi:
|
|
42
|
+
# Manual only, via Actions -> Release -> Run workflow. Packaging and Release Standards §6
|
|
43
|
+
# requires a successful TestPyPI publish ahead of a package's first real release; 0.9.0b0 is
|
|
44
|
+
# this package's first published version, so run this once before tagging v0.9.0b0. Later
|
|
45
|
+
# releases may skip it, or use it again as a dry run.
|
|
46
|
+
if: github.event_name == 'workflow_dispatch'
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@v4
|
|
50
|
+
- uses: actions/setup-python@v5
|
|
51
|
+
with: { python-version: "3.12" }
|
|
52
|
+
- run: pip install --require-hashes -r requirements/release.lock
|
|
53
|
+
- run: python -m build --no-isolation
|
|
54
|
+
- run: twine check dist/*
|
|
55
|
+
# NOTE: this step cannot succeed until `weightsdb 0.2.0` and `mirrorwall 0.2.0` are
|
|
56
|
+
# published — both are runtime dependencies of this package and neither is on any
|
|
57
|
+
# index today. See requirements/README.md.
|
|
58
|
+
- run: pip install "dist/$(ls dist | grep .whl)[dev]"
|
|
59
|
+
- run: pytest -m "not live and not performance"
|
|
60
|
+
- name: Publish to TestPyPI
|
|
61
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
62
|
+
with:
|
|
63
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# ---- Python ----
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
MANIFEST
|
|
23
|
+
|
|
24
|
+
# ---- Packaging / build backends ----
|
|
25
|
+
pip-wheel-metadata/
|
|
26
|
+
share/python-wheels/
|
|
27
|
+
|
|
28
|
+
# ---- Testing / coverage ----
|
|
29
|
+
.pytest_cache/
|
|
30
|
+
.cache
|
|
31
|
+
.coverage
|
|
32
|
+
.coverage.*
|
|
33
|
+
coverage.xml
|
|
34
|
+
*.cover
|
|
35
|
+
*.py,cover
|
|
36
|
+
htmlcov/
|
|
37
|
+
nosetests.xml
|
|
38
|
+
.hypothesis/
|
|
39
|
+
|
|
40
|
+
# ---- Type checking / linting ----
|
|
41
|
+
.mypy_cache/
|
|
42
|
+
.dmypy.json
|
|
43
|
+
dmypy.json
|
|
44
|
+
.ruff_cache/
|
|
45
|
+
.pytype/
|
|
46
|
+
|
|
47
|
+
# ---- Virtual environments ----
|
|
48
|
+
.venv/
|
|
49
|
+
venv/
|
|
50
|
+
ENV/
|
|
51
|
+
env/
|
|
52
|
+
env.bak/
|
|
53
|
+
venv.bak/
|
|
54
|
+
.python-version
|
|
55
|
+
|
|
56
|
+
# ---- Distribution / dependency locking ----
|
|
57
|
+
# requirements/*.lock is deliberately NOT ignored. The lock files are committed
|
|
58
|
+
# inputs: CI and release jobs install from them with --require-hashes (Packaging
|
|
59
|
+
# and Release Standards §4, Security Standards §11), so an ignored lock file
|
|
60
|
+
# means a checkout that cannot build.
|
|
61
|
+
|
|
62
|
+
# ---- Editors / OS ----
|
|
63
|
+
.vscode/
|
|
64
|
+
.idea/
|
|
65
|
+
*.swp
|
|
66
|
+
*.swo
|
|
67
|
+
.DS_Store
|
|
68
|
+
Thumbs.db
|
|
69
|
+
|
|
70
|
+
# ---- Suite runtime state (this component's local data) ----
|
|
71
|
+
# The application writes to XDG paths at runtime (~/.config, ~/.local/share,
|
|
72
|
+
# ~/.local/state per Master Architecture §1.2), never inside the repository.
|
|
73
|
+
# These entries only guard against a developer pointing XDG_* at the repo
|
|
74
|
+
# during local testing.
|
|
75
|
+
.local/
|
|
76
|
+
.config/
|
|
77
|
+
*.sqlite3
|
|
78
|
+
*.sqlite3-journal
|
|
79
|
+
*.sqlite3-wal
|
|
80
|
+
*.sqlite3-shm
|
|
81
|
+
/data/
|
|
82
|
+
/logs/
|
|
83
|
+
/backups/
|
|
84
|
+
/artifacts/
|
|
85
|
+
/exports/
|
|
86
|
+
|
|
87
|
+
# ---- Secrets ----
|
|
88
|
+
# Per Security Standards §8: secrets are never committed. Config files may
|
|
89
|
+
# only name where a secret comes from (*_env / *_file), never the value.
|
|
90
|
+
.env
|
|
91
|
+
.env.*
|
|
92
|
+
*.key
|
|
93
|
+
*.pem
|
|
94
|
+
secrets.toml
|
|
95
|
+
|
|
96
|
+
# ---- Node-free JS assets (MirrorWall consumers may still use a local tool) ----
|
|
97
|
+
node_modules/
|
|
98
|
+
|
|
99
|
+
# ---- Build artifacts from docs generation ----
|
|
100
|
+
docs/api/openapi-v1.json.tmp
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[importlinter]
|
|
2
|
+
root_package = loadcoach
|
|
3
|
+
include_external_packages = True
|
|
4
|
+
|
|
5
|
+
[importlinter:contract:layers]
|
|
6
|
+
name = LoadCoach internal layering
|
|
7
|
+
type = layers
|
|
8
|
+
layers =
|
|
9
|
+
web
|
|
10
|
+
cli
|
|
11
|
+
services
|
|
12
|
+
domain
|
|
13
|
+
containers = loadcoach
|
|
14
|
+
|
|
15
|
+
[importlinter:contract:web-cli-independence]
|
|
16
|
+
name = Web and CLI never import each other
|
|
17
|
+
type = independence
|
|
18
|
+
modules =
|
|
19
|
+
loadcoach.web
|
|
20
|
+
loadcoach.cli
|
|
21
|
+
|
|
22
|
+
[importlinter:contract:domain-purity]
|
|
23
|
+
name = Domain imports no frameworks
|
|
24
|
+
type = forbidden
|
|
25
|
+
source_modules = loadcoach.domain
|
|
26
|
+
forbidden_modules =
|
|
27
|
+
fastapi
|
|
28
|
+
starlette
|
|
29
|
+
sqlalchemy
|
|
30
|
+
typer
|
|
31
|
+
httpx
|
|
32
|
+
jinja2
|
|
33
|
+
|
|
34
|
+
[importlinter:contract:no-other-applications]
|
|
35
|
+
name = LoadCoach must not import other applications
|
|
36
|
+
type = forbidden
|
|
37
|
+
source_modules = loadcoach
|
|
38
|
+
forbidden_modules =
|
|
39
|
+
freeweight
|
|
40
|
+
ideapress
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.6.9
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
9
|
+
rev: v4.6.0
|
|
10
|
+
hooks:
|
|
11
|
+
- id: trailing-whitespace
|
|
12
|
+
- id: end-of-file-fixer
|
|
13
|
+
- id: check-toml
|
|
14
|
+
- id: check-json
|
|
15
|
+
- id: check-added-large-files
|
|
16
|
+
- id: check-merge-conflict
|
|
17
|
+
- id: mixed-line-ending
|
|
18
|
+
args: [--fix=lf]
|
|
19
|
+
- repo: https://github.com/gitleaks/gitleaks
|
|
20
|
+
rev: v8.18.4
|
|
21
|
+
hooks:
|
|
22
|
+
- id: gitleaks
|