flexlock 0.8.2__tar.gz → 0.10.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.
- flexlock-0.10.0/.github/scripts/check_public_docs.py +16 -0
- flexlock-0.10.0/.github/scripts/check_version.py +35 -0
- flexlock-0.10.0/.github/workflows/ci.yml +66 -0
- flexlock-0.10.0/.github/workflows/docs.yml +58 -0
- flexlock-0.10.0/.github/workflows/release.yml +93 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/.gitignore +3 -0
- flexlock-0.10.0/CHANGELOG.md +78 -0
- flexlock-0.10.0/PKG-INFO +120 -0
- flexlock-0.10.0/README.md +105 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/agentic_workflows.md +9 -9
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/api.rst +5 -0
- flexlock-0.10.0/docs/changelog.md +2 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/cli_reference.md +207 -15
- flexlock-0.10.0/docs/dev_plan_pipeline_tasks.md +258 -0
- flexlock-0.10.0/docs/dev_plan_presets_records.md +408 -0
- flexlock-0.10.0/docs/dev_plan_workflow_integrity.md +61 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/docs/hpc_integration.md +264 -107
- flexlock-0.10.0/docs/index.rst +72 -0
- flexlock-0.10.0/docs/next_migration_decisions.md +123 -0
- flexlock-0.10.0/docs/optional_policy_inventory.md +166 -0
- flexlock-0.10.0/docs/performance_core_followup.md +413 -0
- flexlock-0.10.0/docs/philosophy.md +64 -0
- flexlock-0.10.0/docs/project_adoption_handoff.md +112 -0
- flexlock-0.10.0/docs/project_feedback_followup.md +103 -0
- flexlock-0.10.0/docs/project_feedback_triage.md +44 -0
- flexlock-0.10.0/docs/project_instructions.md +24 -0
- flexlock-0.10.0/docs/project_migration_agents.md +33 -0
- flexlock-0.10.0/docs/project_registry_items.md +97 -0
- flexlock-0.10.0/docs/provenance_discovery_decision.md +75 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/python_api.md +82 -219
- {flexlock-0.8.2 → flexlock-0.10.0}/docs/quickstart.md +11 -15
- flexlock-0.10.0/docs/record_and_source_scope_migration.md +70 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/reference.md +14 -39
- flexlock-0.10.0/docs/release_0_10.md +73 -0
- flexlock-0.10.0/docs/release_0_10_0rc1.md +3 -0
- flexlock-0.10.0/docs/release_0_9_1.md +64 -0
- flexlock-0.10.0/docs/release_0_9_2.md +36 -0
- flexlock-0.10.0/docs/release_0_9_3.md +31 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/docs/resolution_simplification_plan.md +6 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/docs/resolvers.md +52 -12
- flexlock-0.10.0/docs/slimmer_core_migration.md +381 -0
- flexlock-0.10.0/docs/slurm_submission_workflow.md +118 -0
- flexlock-0.10.0/docs/source_attribution.md +95 -0
- flexlock-0.10.0/docs/urgent_fix_decisions.md +44 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/docs/usage_guide.md +265 -115
- flexlock-0.10.0/docs/workflow_guidelines.md +481 -0
- flexlock-0.10.0/docs/workflow_lifecycle.md +67 -0
- flexlock-0.10.0/examples/slimmer_workflows/README.md +22 -0
- flexlock-0.10.0/examples/slimmer_workflows/bindings.py +45 -0
- flexlock-0.10.0/examples/slimmer_workflows/campaign.py +109 -0
- flexlock-0.10.0/examples/slimmer_workflows/cfgmod.py +32 -0
- flexlock-0.10.0/examples/slimmer_workflows/chunk_coverage.py +53 -0
- flexlock-0.10.0/examples/slimmer_workflows/orchestrate.py +46 -0
- flexlock-0.10.0/examples/slimmer_workflows/sar_coverage.py +105 -0
- flexlock-0.10.0/examples/slimmer_workflows/slurm/cpu-pool.yaml +9 -0
- flexlock-0.10.0/examples/slimmer_workflows/slurm/cpu.yaml +8 -0
- flexlock-0.10.0/examples/slimmer_workflows/slurm/gpu.yaml +9 -0
- flexlock-0.10.0/examples/slimmer_workflows/stages.py +42 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/__init__.py +2 -2
- flexlock-0.10.0/flexlock/api.py +1625 -0
- flexlock-0.10.0/flexlock/backends/dependencies.py +31 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/backends/pbs.py +18 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/backends/slurm.py +79 -14
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/cli.py +264 -17
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/config.py +37 -3
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/data_hash.py +10 -80
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/debug.py +12 -5
- flexlock-0.10.0/flexlock/destination_guard.py +249 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/diff.py +85 -10
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/diff_cli.py +40 -13
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/exceptions.py +5 -1
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/export.py +5 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/fingerprint.py +83 -5
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/freeze.py +35 -2
- flexlock-0.10.0/flexlock/git_utils.py +292 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/index.py +81 -48
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/load_stage.py +19 -13
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/mlflow.py +11 -11
- flexlock-0.10.0/flexlock/outputs.py +112 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/parallel.py +164 -8
- flexlock-0.10.0/flexlock/presets.py +575 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/query.py +45 -60
- flexlock-0.10.0/flexlock/queue_refs.py +72 -0
- flexlock-0.10.0/flexlock/record.py +265 -0
- flexlock-0.10.0/flexlock/registry.py +64 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/report_template.html +6 -0
- flexlock-0.10.0/flexlock/resolvers.py +437 -0
- flexlock-0.10.0/flexlock/run_record.py +327 -0
- flexlock-0.10.0/flexlock/runner.py +999 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/save_dir.py +11 -6
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/skills/flexlock-new-stage/SKILL.md +10 -4
- flexlock-0.10.0/flexlock/skills/flexlock-run-and-watch/SKILL.md +63 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/skills/flexlock-survey/SKILL.md +12 -1
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/snapshot.py +134 -15
- flexlock-0.10.0/flexlock/sweep_compile.py +109 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/taskdb.py +67 -6
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/utils.py +335 -46
- flexlock-0.10.0/flexlock/worker.py +484 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/flexlock/worker_cli.py +7 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/pyproject.toml +6 -3
- flexlock-0.10.0/tests/registry_items_acceptance.py +60 -0
- flexlock-0.10.0/tests/slurm_failure_acceptance.py +93 -0
- flexlock-0.10.0/tests/test_adoption_diagnostics.py +139 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_api.py +22 -48
- flexlock-0.10.0/tests/test_chained_and_paths.py +120 -0
- flexlock-0.10.0/tests/test_chunk_coverage_example.py +44 -0
- flexlock-0.10.0/tests/test_code_drift.py +197 -0
- flexlock-0.10.0/tests/test_compiled_guard_reuse.py +93 -0
- flexlock-0.10.0/tests/test_completed_stage_binding.py +55 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_completion_marker.py +2 -35
- flexlock-0.10.0/tests/test_controller_lock_handles.py +74 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_data_hash.py +46 -46
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_debug_enhanced.py +18 -0
- flexlock-0.10.0/tests/test_destination_guard.py +190 -0
- flexlock-0.10.0/tests/test_destination_resolution.py +63 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_diff_cli.py +10 -0
- flexlock-0.10.0/tests/test_discovery_policy.py +170 -0
- flexlock-0.10.0/tests/test_fingerprint.py +223 -0
- flexlock-0.10.0/tests/test_freeze_binding_reuse.py +72 -0
- flexlock-0.10.0/tests/test_hpc_dependencies.py +164 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_index.py +10 -46
- flexlock-0.10.0/tests/test_lineage_identity.py +39 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_multistage_config.py +80 -3
- flexlock-0.10.0/tests/test_ownership_loader.py +79 -0
- flexlock-0.10.0/tests/test_ownership_row_cache.py +98 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_parallel.py +19 -19
- flexlock-0.10.0/tests/test_pipeline_tasks.py +527 -0
- flexlock-0.10.0/tests/test_preparation_io.py +113 -0
- flexlock-0.10.0/tests/test_preparation_reuse.py +61 -0
- flexlock-0.10.0/tests/test_presets.py +419 -0
- flexlock-0.10.0/tests/test_queue_layout.py +63 -0
- flexlock-0.10.0/tests/test_queue_record_selection.py +76 -0
- flexlock-0.10.0/tests/test_queue_refs.py +129 -0
- flexlock-0.10.0/tests/test_record_results.py +65 -0
- flexlock-0.10.0/tests/test_registry_items.py +235 -0
- flexlock-0.10.0/tests/test_repo_collection_grouping.py +65 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_resolvers.py +13 -3
- flexlock-0.10.0/tests/test_reviewed_record_contracts.py +105 -0
- flexlock-0.10.0/tests/test_root_anchor_sweep.py +175 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_run_record.py +1 -1
- flexlock-0.10.0/tests/test_sar_coverage.py +95 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_save_dir_guard.py +28 -39
- flexlock-0.10.0/tests/test_single_task_runlock.py +278 -0
- flexlock-0.10.0/tests/test_slim_candidate.py +146 -0
- flexlock-0.10.0/tests/test_slimmer_workflow_examples.py +210 -0
- flexlock-0.10.0/tests/test_slurm_materialization.py +48 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_slurm_validation.py +13 -0
- flexlock-0.10.0/tests/test_source_attribution.py +132 -0
- flexlock-0.10.0/tests/test_source_capture_scope.py +59 -0
- flexlock-0.10.0/tests/test_submit_bindings.py +249 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_submit_params.py +12 -13
- flexlock-0.10.0/tests/test_swaps.py +127 -0
- flexlock-0.10.0/tests/test_sweep_compile.py +120 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_sweep_semantics.py +7 -7
- flexlock-0.10.0/tests/test_task_export_deferred.py +24 -0
- flexlock-0.10.0/tests/test_task_records.py +261 -0
- flexlock-0.10.0/tests/test_workflow_adoption_recipe.py +52 -0
- flexlock-0.10.0/tests/test_workflow_integrity.py +209 -0
- flexlock-0.8.2/.claude/settings.local.json +0 -7
- flexlock-0.8.2/.claude/worktrees/dedup-deps/.claude/settings.local.json +0 -7
- flexlock-0.8.2/.claude/worktrees/dedup-deps/.gitattributes +0 -2
- flexlock-0.8.2/.claude/worktrees/dedup-deps/.gitignore +0 -16
- flexlock-0.8.2/.claude/worktrees/dedup-deps/FABLE_IMPLEMENTATION_PLAN.md +0 -368
- flexlock-0.8.2/.claude/worktrees/dedup-deps/README.md +0 -341
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/debugging.md +0 -352
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/hpc_integration.md +0 -712
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/index.rst +0 -40
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/philosophy.md +0 -171
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/quickstart.md +0 -175
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/resolution_simplification_plan.md +0 -226
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/resolvers.md +0 -445
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/usage_guide.md +0 -1075
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/__init__.py +0 -87
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/api.py +0 -1362
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/backends/pbs.py +0 -219
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/backends/slurm.py +0 -333
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/cli.py +0 -953
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/config.py +0 -107
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/data_hash.py +0 -310
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/debug.py +0 -473
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/fingerprint.py +0 -129
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/freeze.py +0 -291
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/git_utils.py +0 -196
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/index.py +0 -300
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/load_stage.py +0 -60
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/query.py +0 -739
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/resolvers.py +0 -248
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/run_record.py +0 -173
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/runner.py +0 -560
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/save_dir.py +0 -124
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/skills/flexlock-new-stage/SKILL.md +0 -56
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/skills/flexlock-run-and-watch/SKILL.md +0 -58
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/skills/flexlock-survey/SKILL.md +0 -61
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/taskdb.py +0 -589
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/utils.py +0 -710
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/worker.py +0 -199
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/worker_cli.py +0 -138
- flexlock-0.8.2/.claude/worktrees/dedup-deps/pixi.lock +0 -5793
- flexlock-0.8.2/.claude/worktrees/dedup-deps/pyproject.toml +0 -103
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_api.py +0 -425
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_chained_and_paths.py +0 -227
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_completion_marker.py +0 -154
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_data_hash.py +0 -244
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_debug_enhanced.py +0 -403
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_diff_cli.py +0 -66
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_fingerprint.py +0 -112
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_multistage_config.py +0 -347
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_parallel.py +0 -584
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_resolvers.py +0 -421
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_run_record.py +0 -120
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_save_dir.py +0 -125
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_slurm_validation.py +0 -250
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_submit_params.py +0 -377
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_sweep_semantics.py +0 -312
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_utils.py +0 -923
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_worker_preflight.py +0 -97
- flexlock-0.8.2/.gitattributes +0 -2
- flexlock-0.8.2/FABLE_IMPLEMENTATION_PLAN.md +0 -368
- flexlock-0.8.2/PKG-INFO +0 -357
- flexlock-0.8.2/README.md +0 -341
- flexlock-0.8.2/bench/taskdb_contention.py +0 -126
- flexlock-0.8.2/docs/README.md +0 -23
- flexlock-0.8.2/docs/agentic_workflows.md +0 -131
- flexlock-0.8.2/docs/api.rst +0 -127
- flexlock-0.8.2/docs/cli_reference.md +0 -811
- flexlock-0.8.2/docs/conf.py +0 -64
- flexlock-0.8.2/docs/dev_plan_task_tags.md +0 -181
- flexlock-0.8.2/docs/index.rst +0 -40
- flexlock-0.8.2/docs/mlflow_integration.md +0 -960
- flexlock-0.8.2/docs/philosophy.md +0 -171
- flexlock-0.8.2/docs/python_api.md +0 -905
- flexlock-0.8.2/docs/reference.md +0 -305
- flexlock-0.8.2/docs/requirements.txt +0 -10
- flexlock-0.8.2/docs/upload_docs.sh +0 -17
- flexlock-0.8.2/flexlock/api.py +0 -1444
- flexlock-0.8.2/flexlock/backends/__init__.py +0 -11
- flexlock-0.8.2/flexlock/backends/base.py +0 -41
- flexlock-0.8.2/flexlock/context.py +0 -7
- flexlock-0.8.2/flexlock/diff.py +0 -253
- flexlock-0.8.2/flexlock/diff_cli.py +0 -155
- flexlock-0.8.2/flexlock/exceptions.py +0 -50
- flexlock-0.8.2/flexlock/export.py +0 -134
- flexlock-0.8.2/flexlock/flexcli.py +0 -163
- flexlock-0.8.2/flexlock/git_utils.py +0 -196
- flexlock-0.8.2/flexlock/mlflow.py +0 -192
- flexlock-0.8.2/flexlock/parallel.py +0 -378
- flexlock-0.8.2/flexlock/report.py +0 -78
- flexlock-0.8.2/flexlock/report_template.html +0 -246
- flexlock-0.8.2/flexlock/resolvers.py +0 -248
- flexlock-0.8.2/flexlock/run_cli.py +0 -44
- flexlock-0.8.2/flexlock/run_record.py +0 -173
- flexlock-0.8.2/flexlock/runner.py +0 -571
- flexlock-0.8.2/flexlock/skills/flexlock-report/SKILL.md +0 -50
- flexlock-0.8.2/flexlock/skills/flexlock-run-and-watch/SKILL.md +0 -60
- flexlock-0.8.2/flexlock/snapshot.py +0 -245
- flexlock-0.8.2/flexlock/status_cli.py +0 -299
- flexlock-0.8.2/flexlock/worker.py +0 -228
- flexlock-0.8.2/pixi.lock +0 -5793
- flexlock-0.8.2/plan_ergonomics_fable.md +0 -200
- flexlock-0.8.2/suggested_improvements.md +0 -126
- flexlock-0.8.2/tests/test_chained_and_paths.py +0 -227
- flexlock-0.8.2/tests/test_check.py +0 -62
- flexlock-0.8.2/tests/test_cli.py +0 -488
- flexlock-0.8.2/tests/test_debug_integration.py +0 -105
- flexlock-0.8.2/tests/test_deferred.py +0 -98
- flexlock-0.8.2/tests/test_diff.py +0 -559
- flexlock-0.8.2/tests/test_dump_enqueue.py +0 -274
- flexlock-0.8.2/tests/test_fingerprint.py +0 -112
- flexlock-0.8.2/tests/test_flexcli.py +0 -89
- flexlock-0.8.2/tests/test_flexcli_jupyter.py +0 -201
- flexlock-0.8.2/tests/test_git_utils.py +0 -181
- flexlock-0.8.2/tests/test_index.py +0 -202
- flexlock-0.8.2/tests/test_load_stage.py +0 -176
- flexlock-0.8.2/tests/test_mlflowlink.py +0 -246
- flexlock-0.8.2/tests/test_node_selection.py +0 -524
- flexlock-0.8.2/tests/test_progressive_framework.py +0 -136
- flexlock-0.8.2/tests/test_query.py +0 -371
- flexlock-0.8.2/tests/test_report.py +0 -104
- flexlock-0.8.2/tests/test_runner.py +0 -293
- flexlock-0.8.2/tests/test_skills.py +0 -72
- flexlock-0.8.2/tests/test_snapshot.py +0 -437
- flexlock-0.8.2/tests/test_target_includes.py +0 -135
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/README.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/conf.py +0 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/docs/debugging.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/mlflow_integration.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/requirements.txt +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/docs/upload_docs.sh +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/backends/__init__.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/backends/base.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/context.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/flexcli.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/report.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/run_cli.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/skills/flexlock-report/SKILL.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/flexlock/status_cli.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_check.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_cli.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_debug_integration.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_deferred.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_diff.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_dump_enqueue.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_flexcli.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_flexcli_jupyter.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_git_utils.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_load_stage.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_mlflowlink.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_node_selection.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_progressive_framework.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_query.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_report.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_runner.py +0 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_save_dir.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_skills.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_snapshot.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.10.0}/tests/test_target_includes.py +0 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_utils.py +0 -0
- {flexlock-0.8.2 → flexlock-0.10.0}/tests/test_worker_preflight.py +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Refuse personal filesystem paths in public documentation and shipped skills."""
|
|
2
|
+
import re
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
root = Path(__file__).resolve().parents[2]
|
|
5
|
+
paths = [root / "README.md", * (root / "docs").rglob("*.md"),
|
|
6
|
+
*(root / "docs").rglob("*.rst"), *(root / "flexlock/skills").rglob("*.md")]
|
|
7
|
+
bad = []
|
|
8
|
+
for path in paths:
|
|
9
|
+
if "_build" in path.parts:
|
|
10
|
+
continue
|
|
11
|
+
for number, line in enumerate(path.read_text().splitlines(), 1):
|
|
12
|
+
if re.search(r"/(?:ontap|scale|home|jobscratch)/", line):
|
|
13
|
+
bad.append(f"{path.relative_to(root)}:{number}")
|
|
14
|
+
if bad:
|
|
15
|
+
raise SystemExit("Personal filesystem paths in public docs: " + ", ".join(bad))
|
|
16
|
+
print("Public documentation path check passed")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Check that the version declarations agree (and match the tag, if given).
|
|
2
|
+
|
|
3
|
+
The wheel version comes from ``flexlock/__init__.py`` (hatch dynamic version);
|
|
4
|
+
the conda package version from ``[tool.pixi.package] version`` in
|
|
5
|
+
pyproject.toml. Usage: ``python .github/scripts/check_version.py [vX.Y.Z]``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
import tomllib
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
root = Path(__file__).resolve().parents[2]
|
|
14
|
+
init = (root / "flexlock" / "__init__.py").read_text()
|
|
15
|
+
m = re.search(r'^__version__\s*=\s*"([^"]+)"', init, re.M)
|
|
16
|
+
if not m:
|
|
17
|
+
sys.exit("could not find __version__ in flexlock/__init__.py")
|
|
18
|
+
py_version = m.group(1)
|
|
19
|
+
|
|
20
|
+
pixi_version = tomllib.loads((root / "pyproject.toml").read_text())["tool"]["pixi"]["package"]["version"]
|
|
21
|
+
|
|
22
|
+
errors = []
|
|
23
|
+
if py_version != pixi_version:
|
|
24
|
+
errors.append(
|
|
25
|
+
f"flexlock/__init__.py __version__={py_version!r} != "
|
|
26
|
+
f"[tool.pixi.package] version={pixi_version!r}"
|
|
27
|
+
)
|
|
28
|
+
if len(sys.argv) > 1:
|
|
29
|
+
tag = sys.argv[1].removeprefix("refs/tags/")
|
|
30
|
+
if tag != f"v{py_version}":
|
|
31
|
+
errors.append(f"tag {tag!r} does not match package version v{py_version}")
|
|
32
|
+
|
|
33
|
+
if errors:
|
|
34
|
+
sys.exit("\n".join(errors))
|
|
35
|
+
print(f"version OK: {py_version}")
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
tests:
|
|
18
|
+
name: tests (py${{ matrix.python-version }})
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0 # git_utils / snapshot tests inspect history
|
|
28
|
+
|
|
29
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python-version }}
|
|
32
|
+
activate-environment: true
|
|
33
|
+
|
|
34
|
+
- name: Install package and test deps
|
|
35
|
+
# Mirrors [tool.pixi.feature.test]; attrs is needed by test_utils.
|
|
36
|
+
run: uv pip install -e . "pytest>=8.3.2,<9" "pytest-mock>=3.14.0,<4" ipython attrs
|
|
37
|
+
|
|
38
|
+
- name: Git identity (tests create repos and commits)
|
|
39
|
+
run: |
|
|
40
|
+
git config --global user.name "flexlock-ci"
|
|
41
|
+
git config --global user.email "flexlock-ci@users.noreply.github.com"
|
|
42
|
+
|
|
43
|
+
- name: Run tests
|
|
44
|
+
run: pytest -q
|
|
45
|
+
|
|
46
|
+
build:
|
|
47
|
+
name: build sdist/wheel
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
51
|
+
|
|
52
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
53
|
+
with:
|
|
54
|
+
python-version: "3.11"
|
|
55
|
+
|
|
56
|
+
- name: Check version declarations agree
|
|
57
|
+
run: python .github/scripts/check_version.py
|
|
58
|
+
|
|
59
|
+
- run: uv build
|
|
60
|
+
|
|
61
|
+
- name: Wheel installs into a clean venv and imports
|
|
62
|
+
run: |
|
|
63
|
+
uv venv /tmp/wheelcheck
|
|
64
|
+
uv pip install --python /tmp/wheelcheck/bin/python dist/*.whl
|
|
65
|
+
cd /tmp && /tmp/wheelcheck/bin/python -c "import flexlock; print(flexlock.__version__)"
|
|
66
|
+
/tmp/wheelcheck/bin/flexlock --help > /dev/null
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
# Builds the Sphinx docs on every PR; deploys to GitHub Pages
|
|
4
|
+
# (https://quentinf00.github.io/flexlock/) on pushes to main.
|
|
5
|
+
# Requires Settings > Pages > Source = "GitHub Actions".
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
pull_request:
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: pages-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
build:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
24
|
+
|
|
25
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.11"
|
|
28
|
+
activate-environment: true
|
|
29
|
+
|
|
30
|
+
- name: Install docs deps
|
|
31
|
+
# Mirrors [tool.pixi.feature.docs]; conf.py imports flexlock.
|
|
32
|
+
run: uv pip install . sphinx myst-parser sphinx-rtd-theme
|
|
33
|
+
|
|
34
|
+
- name: Check portable documentation
|
|
35
|
+
run: python .github/scripts/check_public_docs.py
|
|
36
|
+
|
|
37
|
+
- name: Build HTML
|
|
38
|
+
run: |
|
|
39
|
+
sphinx-build -b html docs docs/_build/html
|
|
40
|
+
touch docs/_build/html/.nojekyll
|
|
41
|
+
|
|
42
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
43
|
+
with:
|
|
44
|
+
path: docs/_build/html
|
|
45
|
+
|
|
46
|
+
deploy:
|
|
47
|
+
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
|
48
|
+
needs: build
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
permissions:
|
|
51
|
+
pages: write
|
|
52
|
+
id-token: write
|
|
53
|
+
environment:
|
|
54
|
+
name: github-pages
|
|
55
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
56
|
+
steps:
|
|
57
|
+
- id: deployment
|
|
58
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Push a tag vX.Y.Z (matching flexlock/__init__.py and [tool.pixi.package]
|
|
4
|
+
# version) to build and publish the PyPI and conda packages.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-dist:
|
|
14
|
+
name: build sdist/wheel
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
18
|
+
|
|
19
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.11"
|
|
22
|
+
|
|
23
|
+
- name: Tag matches package versions
|
|
24
|
+
run: python .github/scripts/check_version.py "${GITHUB_REF_NAME}"
|
|
25
|
+
|
|
26
|
+
- run: uv build
|
|
27
|
+
|
|
28
|
+
- name: Wheel installs into a clean venv and imports
|
|
29
|
+
run: |
|
|
30
|
+
uv venv /tmp/wheelcheck
|
|
31
|
+
uv pip install --python /tmp/wheelcheck/bin/python dist/*.whl
|
|
32
|
+
cd /tmp && /tmp/wheelcheck/bin/python -c "import flexlock; print(flexlock.__version__)"
|
|
33
|
+
|
|
34
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
35
|
+
with:
|
|
36
|
+
name: dist
|
|
37
|
+
path: dist/
|
|
38
|
+
if-no-files-found: error
|
|
39
|
+
|
|
40
|
+
publish-pypi:
|
|
41
|
+
# Enable this repository variable after configuring the corresponding
|
|
42
|
+
# trusted publisher on PyPI. Local twine publishing works independently.
|
|
43
|
+
if: vars.PYPI_TRUSTED_PUBLISHING == 'true'
|
|
44
|
+
name: publish to PyPI (trusted publishing)
|
|
45
|
+
needs: build-dist
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
environment:
|
|
48
|
+
name: pypi
|
|
49
|
+
url: https://pypi.org/p/flexlock
|
|
50
|
+
permissions:
|
|
51
|
+
id-token: write # OIDC token for PyPI trusted publishing; no stored secret
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
54
|
+
with:
|
|
55
|
+
name: dist
|
|
56
|
+
path: dist/
|
|
57
|
+
|
|
58
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
59
|
+
|
|
60
|
+
conda:
|
|
61
|
+
name: build + upload conda package (anaconda.org/quentinf00)
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
env:
|
|
64
|
+
ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_API_TOKEN }}
|
|
65
|
+
environment:
|
|
66
|
+
name: anaconda
|
|
67
|
+
url: https://anaconda.org/quentinf00/flexlock
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
70
|
+
|
|
71
|
+
- name: Tag matches package versions
|
|
72
|
+
run: python3 .github/scripts/check_version.py "${GITHUB_REF_NAME}"
|
|
73
|
+
|
|
74
|
+
- uses: prefix-dev/setup-pixi@d3f436a425481402e6a95a1d1fc10331c708cd9e # v0.10.2
|
|
75
|
+
with:
|
|
76
|
+
pixi-version: v0.73.0
|
|
77
|
+
run-install: false
|
|
78
|
+
|
|
79
|
+
- name: Build conda package ([tool.pixi.package], pixi-build-python)
|
|
80
|
+
run: pixi build --output-dir conda-out
|
|
81
|
+
|
|
82
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
83
|
+
with:
|
|
84
|
+
name: conda-package
|
|
85
|
+
path: conda-out/*.conda
|
|
86
|
+
if-no-files-found: error
|
|
87
|
+
|
|
88
|
+
- name: Upload to anaconda.org
|
|
89
|
+
if: env.ANACONDA_API_TOKEN != ''
|
|
90
|
+
run: |
|
|
91
|
+
pixi exec --spec "anaconda-client>=1.14,<1.16" -- \
|
|
92
|
+
binstar -s api.anaconda.org -t "$ANACONDA_API_TOKEN" \
|
|
93
|
+
upload --user quentinf00 --label main conda-out/*.conda
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# 0.10.0
|
|
2
|
+
|
|
3
|
+
- Retire automatic cross-run cache search, marker-based partial-stage resume and
|
|
4
|
+
chained fanout; retain explicit producer selection, named sweeps and ordered stages.
|
|
5
|
+
- Record invocation source scopes separately from shared source capture.
|
|
6
|
+
- Preserve authoritative result records, pre-submission ownership guards, scheduler
|
|
7
|
+
dependencies and matching-worker queue continuation.
|
|
8
|
+
- Publish portable workflow recipes and align shipped agent skills with explicit
|
|
9
|
+
producer selection and fresh-attempt recovery.
|
|
10
|
+
|
|
11
|
+
# Changelog
|
|
12
|
+
|
|
13
|
+
## 0.10.0rc1 (local candidate, 2026-10-16)
|
|
14
|
+
|
|
15
|
+
- Remove automatic cross-run cache search, submission cache keywords and CLI
|
|
16
|
+
`--check-exists`, `Project.exists/get_result`, and chained fanout APIs.
|
|
17
|
+
- Reject old marker-based stage-resume payloads and worker-time unpinned run
|
|
18
|
+
selectors under scheduler dependencies. Keep explicit future producer bindings.
|
|
19
|
+
- Preserve exact-path reuse, authoritative output validation, recorded queue
|
|
20
|
+
continuation, ordered stages and provenance comparison. Tighten queue ownership
|
|
21
|
+
checks so foreign queues and changed payloads cannot bypass destination guards.
|
|
22
|
+
- Include the unreleased source-attribution and project-feedback fixes described
|
|
23
|
+
in [candidate migration notes](release_0_10.md).
|
|
24
|
+
|
|
25
|
+
This is an isolated validation candidate; no project environment upgrade or
|
|
26
|
+
scientific rerun is implied.
|
|
27
|
+
|
|
28
|
+
## 0.9.0 (2026-10-02)
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- Composite pipelines across sweeps, local/HPC workers, and enqueue/dequeue.
|
|
32
|
+
- Full per-stage run records in directories or the task DB, including upstream
|
|
33
|
+
references, code provenance, and code-drift detection.
|
|
34
|
+
- Environment lockfiles in run fingerprints.
|
|
35
|
+
- Preset tracking and `flexlock runs` / `flexlock presets`.
|
|
36
|
+
- `${run:...}` references to completed preset runs and `key=@name` config swaps.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
- Composite task snapshots retain every executed stage instead of overwriting
|
|
40
|
+
earlier stage records. Exports include each stage's inherited code and environment.
|
|
41
|
+
|
|
42
|
+
### Release infrastructure
|
|
43
|
+
- CI on Python 3.11–3.13, wheel/sdist checks, tag-driven PyPI and conda publishing,
|
|
44
|
+
and GitHub Pages documentation.
|
|
45
|
+
|
|
46
|
+
The unreleased 0.8.3 fixes below are included in this release.
|
|
47
|
+
|
|
48
|
+
## 0.8.3 (unreleased)
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- **Single HPC / `isolated=True` runs now get a full `run.lock`.** They used to
|
|
52
|
+
keep the submit-time placeholder (`config` = `save_dir` + `_snapshot_` only)
|
|
53
|
+
because the worker stored the real snapshot only in `run.lock.tasks.db`. That
|
|
54
|
+
broke `${run_lock:...}` (`KeyError`), made `flexlock-run -c run.lock` a
|
|
55
|
+
silent no-op, showed empty configs in `show`/`diff`/`ls`, linked no commits
|
|
56
|
+
on `tag`, and let `gc` delete the upstreams of a tagged run. The worker now
|
|
57
|
+
writes the full snapshot (config, fingerprint, git state, `note`) atomically
|
|
58
|
+
when its task owns the master dir. Sweep roots keep their placeholder.
|
|
59
|
+
- Readers (`${run_lock:...}`, `show`/`graph`/`why`/`report`, `flexlock-diff`,
|
|
60
|
+
`ls`/`gc`/`tag`, `load_stage`, lineage, `flexlock-run -c run.lock`) fall back
|
|
61
|
+
to the task-DB snapshot for placeholder `run.lock`s written by older versions.
|
|
62
|
+
- The worker refreshes `run.lock.tasks` when its queue drains, so it is no
|
|
63
|
+
longer left at `[]` after a `wait=False` submit.
|
|
64
|
+
- `force=True` on a single HPC / isolated submission deleted `run.complete` but
|
|
65
|
+
ran nothing: the old `done` row in the task DB was kept by `INSERT OR IGNORE`.
|
|
66
|
+
The task DB is now reset and the task re-executes. The reset also drops the
|
|
67
|
+
cached sqlite connection, which kept writing to the deleted DB file.
|
|
68
|
+
- Slurm backend: forkserver compatibility fix.
|
|
69
|
+
- `docs/hpc_integration.md`: the task DB lives inside `save_dir`, not in its
|
|
70
|
+
parent. The overview section, clobbered by an earlier edit, is restored.
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
- `flexlock.run_record.load_lock_data(run_dir)`: side-effect-free effective
|
|
74
|
+
`run.lock` (placeholder → task-DB snapshot).
|
|
75
|
+
- `flexlock.run_record.materialize_lock(run_dir)`: one-off rewrite of a
|
|
76
|
+
placeholder `run.lock` (keeps `run.lock.placeholder.bak`).
|
|
77
|
+
- `flexlock repair-locks <root> [-n]`: runs `materialize_lock` over a results tree.
|
|
78
|
+
- `flexlock.taskdb.reset_db(db_path)`.
|
flexlock-0.10.0/PKG-INFO
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: flexlock
|
|
3
|
+
Version: 0.10.0
|
|
4
|
+
Summary: A lightweight and painless SciOps library
|
|
5
|
+
Author-email: Quentin Febvre <quentin.febvre@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: cloudpickle<4,>=3.0.0
|
|
9
|
+
Requires-Dist: gitpython<4,>=3.1.46
|
|
10
|
+
Requires-Dist: joblib<2,>=1.5.2
|
|
11
|
+
Requires-Dist: loguru<0.8,>=0.7.3
|
|
12
|
+
Requires-Dist: omegaconf<3,>=2.3.0
|
|
13
|
+
Requires-Dist: xxhash<4,>=3.5.0
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# FlexLock
|
|
17
|
+
|
|
18
|
+
Python configuration and run provenance for research and offline data processing.
|
|
19
|
+
|
|
20
|
+
[Documentation](https://quentinf00.github.io/flexlock/) · MIT licensed
|
|
21
|
+
|
|
22
|
+
FlexLock lets you write a config in Python, select and override it from the CLI,
|
|
23
|
+
and execute locally or through cluster workers. Run records capture configuration,
|
|
24
|
+
declared source/data dependencies, upstream producers, outputs and return values.
|
|
25
|
+
|
|
26
|
+
The **0.10.0 release** removes automatic cross-run cache search and partial-stage
|
|
27
|
+
resume policy. See [breaking changes](docs/release_0_10.md).
|
|
28
|
+
|
|
29
|
+
## Configuration and execution
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
# cfgmod.py
|
|
33
|
+
from flexlock import py2cfg
|
|
34
|
+
from myproject.stages import prepare, train
|
|
35
|
+
|
|
36
|
+
cfg = dict(
|
|
37
|
+
runs_root='/shared/project/runs',
|
|
38
|
+
track='intensity', arm='baseline', run='20261016-seed3',
|
|
39
|
+
run_dir='${runs_root}/${track}/${arm}/${run}',
|
|
40
|
+
upstream_run='/shared/project/runs/preparation/base/20261001/prepare',
|
|
41
|
+
main=py2cfg(train,
|
|
42
|
+
save_dir='${run_dir}/train',
|
|
43
|
+
input_path='${run_lock:${upstream_run},config.output_path}',
|
|
44
|
+
checkpoint_path='${run_dir}/train/model.pt',
|
|
45
|
+
_snapshot_=dict(data=dict(dataset='${...input_path}')),
|
|
46
|
+
_outputs_=dict(model=dict(path='model.pt', sha256=True))),
|
|
47
|
+
)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
flexlock-run -d cfgmod.cfg -s main -o upstream_run=/shared/runs/other/prepare
|
|
52
|
+
flexlock-run -d cfgmod.cfg -s main --sweep-file configs/smoke.yaml --n_jobs 2
|
|
53
|
+
flexlock-run -d cfgmod.cfg -s main --slurm-config configs/slurm_gpu.yaml
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Choose fresh destinations for independent runs. Occupied run directories raise
|
|
57
|
+
before scheduler submission; active ownership also prevents forced overwrites.
|
|
58
|
+
Use the [workflow recipes](docs/workflow_guidelines.md) for named sweeps, per-item
|
|
59
|
+
destinations and explicit producer selection.
|
|
60
|
+
|
|
61
|
+
Python submission uses the same execution kernel:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from flexlock import Project
|
|
65
|
+
|
|
66
|
+
project = Project('cfgmod.cfg')
|
|
67
|
+
result = project.submit('main')
|
|
68
|
+
result.raise_on_failure()
|
|
69
|
+
print(result.save_dir, result.result)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Provenance and explicit reuse
|
|
73
|
+
|
|
74
|
+
Source snapshots describe the declared repository scope, including include/exclude
|
|
75
|
+
patterns. Data hashes and upstream bindings record what the callable consumed.
|
|
76
|
+
Comparison tools provide evidence for deciding whether preparation remains acceptable
|
|
77
|
+
after a code change; FlexLock does not choose that scientific policy.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
flexlock-diff /shared/runs/producer_a /shared/runs/producer_b
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Consumers bind concrete producer paths with `run_lock`. FlexLock resolves and records
|
|
84
|
+
the selected producer accurately and rejects identity changes at consumption time.
|
|
85
|
+
It does not silently substitute a newer producer.
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
selected = project.submit(cfg, save_dir_policy='skip')
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`skip` reuses exactly the selected complete destination after authoritative-record
|
|
92
|
+
and declared-output validation. It returns the producer's recorded config. It does
|
|
93
|
+
not certify equivalence to a new config or current source. `force=True` intentionally
|
|
94
|
+
reruns in place and records the new attempt while keeping products in place.
|
|
95
|
+
|
|
96
|
+
## Sweeps and ordered stages
|
|
97
|
+
|
|
98
|
+
Sweep files keep large cohorts out of comma-separated CLI arguments. Workers claim
|
|
99
|
+
tasks from a shared SQLite queue, allowing many items with a bounded worker allocation.
|
|
100
|
+
Project coverage checks distinguish successful processing, valid empty outcomes,
|
|
101
|
+
exclusions, missing products and failures.
|
|
102
|
+
|
|
103
|
+
CLI `-s prepare train assess` executes selected stages in order on one allocation,
|
|
104
|
+
with distinct provenance and fail-fast execution. Independent pipeline items can run
|
|
105
|
+
in parallel. Stages needing different resources use separate scheduler jobs and
|
|
106
|
+
`--after`, with concrete future producer paths and an accepted-ID ledger.
|
|
107
|
+
|
|
108
|
+
An unchanged recorded queue can continue pending work without rerunning done rows.
|
|
109
|
+
For a partially completed pipeline, explicitly select remaining stages, bind retained
|
|
110
|
+
producers and use fresh destinations. There is no automatic marker-based stage skip.
|
|
111
|
+
|
|
112
|
+
## Further reading
|
|
113
|
+
|
|
114
|
+
- [Workflow guidelines and five executable recipes](docs/workflow_guidelines.md)
|
|
115
|
+
- [Python API](docs/python_api.md) and [CLI reference](docs/cli_reference.md)
|
|
116
|
+
- [Source attribution](docs/source_attribution.md) and [HPC integration](docs/hpc_integration.md)
|
|
117
|
+
- [Slim-core design](docs/philosophy.md) and [migration notes](docs/release_0_10.md)
|
|
118
|
+
|
|
119
|
+
Install this release with `pip install flexlock==0.10.0` or from the
|
|
120
|
+
`quentinf00` Conda channel. See the migration notes before upgrading existing callers.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# FlexLock
|
|
2
|
+
|
|
3
|
+
Python configuration and run provenance for research and offline data processing.
|
|
4
|
+
|
|
5
|
+
[Documentation](https://quentinf00.github.io/flexlock/) · MIT licensed
|
|
6
|
+
|
|
7
|
+
FlexLock lets you write a config in Python, select and override it from the CLI,
|
|
8
|
+
and execute locally or through cluster workers. Run records capture configuration,
|
|
9
|
+
declared source/data dependencies, upstream producers, outputs and return values.
|
|
10
|
+
|
|
11
|
+
The **0.10.0 release** removes automatic cross-run cache search and partial-stage
|
|
12
|
+
resume policy. See [breaking changes](docs/release_0_10.md).
|
|
13
|
+
|
|
14
|
+
## Configuration and execution
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
# cfgmod.py
|
|
18
|
+
from flexlock import py2cfg
|
|
19
|
+
from myproject.stages import prepare, train
|
|
20
|
+
|
|
21
|
+
cfg = dict(
|
|
22
|
+
runs_root='/shared/project/runs',
|
|
23
|
+
track='intensity', arm='baseline', run='20261016-seed3',
|
|
24
|
+
run_dir='${runs_root}/${track}/${arm}/${run}',
|
|
25
|
+
upstream_run='/shared/project/runs/preparation/base/20261001/prepare',
|
|
26
|
+
main=py2cfg(train,
|
|
27
|
+
save_dir='${run_dir}/train',
|
|
28
|
+
input_path='${run_lock:${upstream_run},config.output_path}',
|
|
29
|
+
checkpoint_path='${run_dir}/train/model.pt',
|
|
30
|
+
_snapshot_=dict(data=dict(dataset='${...input_path}')),
|
|
31
|
+
_outputs_=dict(model=dict(path='model.pt', sha256=True))),
|
|
32
|
+
)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
flexlock-run -d cfgmod.cfg -s main -o upstream_run=/shared/runs/other/prepare
|
|
37
|
+
flexlock-run -d cfgmod.cfg -s main --sweep-file configs/smoke.yaml --n_jobs 2
|
|
38
|
+
flexlock-run -d cfgmod.cfg -s main --slurm-config configs/slurm_gpu.yaml
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Choose fresh destinations for independent runs. Occupied run directories raise
|
|
42
|
+
before scheduler submission; active ownership also prevents forced overwrites.
|
|
43
|
+
Use the [workflow recipes](docs/workflow_guidelines.md) for named sweeps, per-item
|
|
44
|
+
destinations and explicit producer selection.
|
|
45
|
+
|
|
46
|
+
Python submission uses the same execution kernel:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from flexlock import Project
|
|
50
|
+
|
|
51
|
+
project = Project('cfgmod.cfg')
|
|
52
|
+
result = project.submit('main')
|
|
53
|
+
result.raise_on_failure()
|
|
54
|
+
print(result.save_dir, result.result)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Provenance and explicit reuse
|
|
58
|
+
|
|
59
|
+
Source snapshots describe the declared repository scope, including include/exclude
|
|
60
|
+
patterns. Data hashes and upstream bindings record what the callable consumed.
|
|
61
|
+
Comparison tools provide evidence for deciding whether preparation remains acceptable
|
|
62
|
+
after a code change; FlexLock does not choose that scientific policy.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
flexlock-diff /shared/runs/producer_a /shared/runs/producer_b
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Consumers bind concrete producer paths with `run_lock`. FlexLock resolves and records
|
|
69
|
+
the selected producer accurately and rejects identity changes at consumption time.
|
|
70
|
+
It does not silently substitute a newer producer.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
selected = project.submit(cfg, save_dir_policy='skip')
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`skip` reuses exactly the selected complete destination after authoritative-record
|
|
77
|
+
and declared-output validation. It returns the producer's recorded config. It does
|
|
78
|
+
not certify equivalence to a new config or current source. `force=True` intentionally
|
|
79
|
+
reruns in place and records the new attempt while keeping products in place.
|
|
80
|
+
|
|
81
|
+
## Sweeps and ordered stages
|
|
82
|
+
|
|
83
|
+
Sweep files keep large cohorts out of comma-separated CLI arguments. Workers claim
|
|
84
|
+
tasks from a shared SQLite queue, allowing many items with a bounded worker allocation.
|
|
85
|
+
Project coverage checks distinguish successful processing, valid empty outcomes,
|
|
86
|
+
exclusions, missing products and failures.
|
|
87
|
+
|
|
88
|
+
CLI `-s prepare train assess` executes selected stages in order on one allocation,
|
|
89
|
+
with distinct provenance and fail-fast execution. Independent pipeline items can run
|
|
90
|
+
in parallel. Stages needing different resources use separate scheduler jobs and
|
|
91
|
+
`--after`, with concrete future producer paths and an accepted-ID ledger.
|
|
92
|
+
|
|
93
|
+
An unchanged recorded queue can continue pending work without rerunning done rows.
|
|
94
|
+
For a partially completed pipeline, explicitly select remaining stages, bind retained
|
|
95
|
+
producers and use fresh destinations. There is no automatic marker-based stage skip.
|
|
96
|
+
|
|
97
|
+
## Further reading
|
|
98
|
+
|
|
99
|
+
- [Workflow guidelines and five executable recipes](docs/workflow_guidelines.md)
|
|
100
|
+
- [Python API](docs/python_api.md) and [CLI reference](docs/cli_reference.md)
|
|
101
|
+
- [Source attribution](docs/source_attribution.md) and [HPC integration](docs/hpc_integration.md)
|
|
102
|
+
- [Slim-core design](docs/philosophy.md) and [migration notes](docs/release_0_10.md)
|
|
103
|
+
|
|
104
|
+
Install this release with `pip install flexlock==0.10.0` or from the
|
|
105
|
+
`quentinf00` Conda channel. See the migration notes before upgrading existing callers.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agentic Workflows
|
|
2
2
|
|
|
3
3
|
FlexLock already persists everything needed to reconstruct experiment history
|
|
4
|
-
(`run.lock`, shadow git commits, data hashes, lineage, the
|
|
4
|
+
(`run.lock`, shadow git commits, data hashes, lineage, the
|
|
5
5
|
task DB, and tags as git refs). This page documents the **machine-readable query
|
|
6
6
|
commands** that turn that on-disk state into a stable, agent-facing contract, the
|
|
7
7
|
**shipped skills** that encode common workflows, and the **static HTML report**.
|
|
@@ -25,7 +25,7 @@ Every JSON payload is gated by a `schema_version` (currently `1`).
|
|
|
25
25
|
|
|
26
26
|
### `flexlock show --format json`
|
|
27
27
|
|
|
28
|
-
```
|
|
28
|
+
```text
|
|
29
29
|
{"schema_version":1, "path":"/abs", "kind":"run|sweep_master|sweep_task",
|
|
30
30
|
"status":"complete|failed|interrupted|running|pending|unknown", "status_detail":null,
|
|
31
31
|
"timestamp":"...", "note":null, "target":"myproject.train.train",
|
|
@@ -46,7 +46,7 @@ DB row; otherwise `run.complete` → `complete`, `run.error` → `failed`, `run.
|
|
|
46
46
|
|
|
47
47
|
### `flexlock graph --format json`
|
|
48
48
|
|
|
49
|
-
```
|
|
49
|
+
```text
|
|
50
50
|
{"schema_version":1, "root":"/abs", "generated_at":"...",
|
|
51
51
|
"nodes":[{"id":"/abs/dir","label":"train","kind":"run","status":"complete",
|
|
52
52
|
"timestamp":"...","note":null,"target":null,"fingerprint":null,"tag":null,
|
|
@@ -57,13 +57,13 @@ DB row; otherwise `run.complete` → `complete`, `run.error` → `failed`, `run.
|
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
`id` is a resolved absolute path. `metrics` are the top-level numeric keys of
|
|
60
|
-
`results.json
|
|
60
|
+
the authoritative return payload (including legacy `results.json`). Edges pointing outside the scanned tree materialise `kind:
|
|
61
61
|
external` stub nodes so the graph is closed. `--groups` adds size-≥2 clusters of
|
|
62
62
|
nodes sharing identical tree hashes / data dicts.
|
|
63
63
|
|
|
64
64
|
### `flexlock why --format json`
|
|
65
65
|
|
|
66
|
-
```
|
|
66
|
+
```text
|
|
67
67
|
{"schema_version":1,"run_a":"/a","run_b":"/b","match":false,
|
|
68
68
|
"diffs":{"config":[...],"git":[...],"data":[...]},
|
|
69
69
|
"commits":{"main":{"trees_identical":false,
|
|
@@ -89,16 +89,16 @@ query command. See [Reference › On-Disk Run Files](reference.md#on-disk-run-fi
|
|
|
89
89
|
## Failure records — `run.error`
|
|
90
90
|
|
|
91
91
|
When a run's user function raises, FlexLock writes a `run.error` JSON sidecar next
|
|
92
|
-
to `run.lock` (schema in the [Reference](reference.md
|
|
92
|
+
to `run.lock` (schema in the [Reference](reference.md)).
|
|
93
93
|
Triage a failure without touching sqlite:
|
|
94
94
|
|
|
95
95
|
```bash
|
|
96
96
|
flexlock show <run_dir> --format json # .error.exc_type / .error.traceback
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
Inspect error and worker ownership before retrying. Code/config/data changes get
|
|
100
|
+
a fresh attempt with explicit retained inputs. In-place force deliberately replaces
|
|
101
|
+
prior provenance; it is not the default recovery.
|
|
102
102
|
|
|
103
103
|
## Shipped skills
|
|
104
104
|
|