Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3cbe7ac
Add read-only Tracking Cloth Deformation evaluation pilot
FlorianPfaff Aug 29, 2026
f6c1f9c
Run one-shot tracking cloth branch repair
FlorianPfaff Aug 29, 2026
06db901
Run Python-only tracking cloth formatter
FlorianPfaff Aug 29, 2026
1cb8c56
Trigger tracking cloth formatter
FlorianPfaff Aug 29, 2026
25ed061
Format tracking cloth evaluation
github-actions[bot] Aug 29, 2026
de818e2
Restrict real cloth evaluation to dispatched main
FlorianPfaff Aug 29, 2026
004acb2
Remove temporary tracking cloth repair workflow
FlorianPfaff Aug 29, 2026
8ad5600
Remove tracking cloth formatter trigger
FlorianPfaff Aug 29, 2026
2e7bb22
Route tracking-cloth evaluation to gpuserver4090
FlorianPfaff Aug 30, 2026
2f0a1a4
Add outcome-blind active probe selection policies
FlorianPfaff Aug 30, 2026
5709ff2
Freeze the active-probe shake-to-twist protocol
FlorianPfaff Aug 30, 2026
8186677
Test active probe objectives and selected-outcome access
FlorianPfaff Aug 30, 2026
c5a44d5
Add synthetic integration tests for active-probe sealing
FlorianPfaff Aug 30, 2026
42714f2
Record reviewed Tracking Cloth workflow increase
FlorianPfaff Aug 30, 2026
c685938
Document reviewed Tracking Cloth workflow budget
FlorianPfaff Aug 30, 2026
ae90af6
Complete active-probe belief construction helpers
FlorianPfaff Aug 30, 2026
39a1178
Format active-probe runner contracts
FlorianPfaff Aug 30, 2026
1d44305
Format active-probe selection contracts
FlorianPfaff Aug 30, 2026
516970e
Format active-probe belief helpers
FlorianPfaff Aug 30, 2026
ae81d39
Format active-probe selection contracts
FlorianPfaff Aug 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/quality/workflow-inventory-budget-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"schema": "bayesian-phystwin.workflow-inventory-budget",
"schema_version": 1,
"baseline_revision": "45e1f4454d50fd1970af13578f0383872814125e",
"maximum_checked_in_workflows": 82,
"maximum_checked_in_workflows": 83,
"temporary_looking_workflow_allowlist": [],
"retirement_target_maximum_checked_in_workflows": 81,
"retirement_target_maximum_temporary_looking_workflows": 0
Expand Down
299 changes: 299 additions & 0 deletions .github/workflows/tracking-cloth-evaluation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
# workflow-lifecycle: permanent
# workflow-owner: IPS-Stuttgart maintainers
name: Tracking Cloth Deformation evaluation

on:
pull_request:
paths:
- .github/workflows/tracking-cloth-evaluation.yml
- .github/requests/tracking-cloth-deformation-v1-evaluate.json
- experiments/tracking_cloth_deformation_v1/**
- tests/test_tracking_cloth_deformation_v1.py
push:
branches: [main]
paths:
- .github/requests/tracking-cloth-deformation-v1-evaluate.json
workflow_dispatch:
inputs:
mode:
description: "inventory / source-only qualification / sealed shake-to-twist pilot"
type: choice
options: [inventory, source_only, evaluate]
default: source_only
required: true
workers:
description: "Source rollout CPU workers (GPU is not needed)"
type: choice
options: ["1", "2", "4", "8"]
default: "4"
required: true

permissions:
contents: read

concurrency:
group: tracking-cloth-evaluation-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: false

env:
PYTHONUNBUFFERED: "1"
PYTHONDONTWRITEBYTECODE: "1"
OPENBLAS_NUM_THREADS: "1"
OMP_NUM_THREADS: "1"
MKL_NUM_THREADS: "1"

jobs:
contracts:
name: Tracking-cloth synthetic contracts
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
cache: pip
cache-dependency-path: experiments/tracking_cloth_deformation_v1/requirements.txt
- name: Install isolated test dependencies
run: python -m pip install -r experiments/tracking_cloth_deformation_v1/requirements.txt pytest ruff
- name: Test data boundaries, predictors, and sealed scoring
run: python -m pytest -q tests/test_tracking_cloth_deformation_v1.py
- name: Validate a canonical real-data request when present
shell: bash
run: |
python - <<'PY'
import json
from pathlib import Path

path = Path(".github/requests/tracking-cloth-deformation-v1-evaluate.json")
if not path.exists():
raise SystemExit(0)
request = json.loads(path.read_text())
required = {
"schema": "tracking-cloth-deformation-evaluation-request-v1",
"mode": "evaluate",
"dataset_root": "/home/github-runner/.cache/datasets/tracking-cloth-deformation-v1-zenodo-14644526",
"runner_label": "gpuserver4090",
"workers": 4,
"authorize_target_scoring": True,
"paper_claim_authorized": False,
}
for key, value in required.items():
if request.get(key) != value:
raise SystemExit(f"Invalid request field {key!r}: {request.get(key)!r}")
allowed = set(required) | {"request_id", "expected_source_revision", "evidence_class"}
unknown = set(request) - allowed
if unknown:
raise SystemExit(f"Unknown request fields: {sorted(unknown)}")
if not request.get("request_id"):
raise SystemExit("request_id must be nonempty")
revision = request.get("expected_source_revision", "")
if len(revision) != 40 or any(c not in "0123456789abcdef" for c in revision):
raise SystemExit("expected_source_revision must be a lowercase commit SHA")
if request.get("evidence_class") != "public-real-data-pilot; no fresh-confirmation claim":
raise SystemExit("Unexpected evidence_class")
PY
- name: Lint and formatting diagnostics
if: always()
run: |
python -m ruff format --diff experiments/tracking_cloth_deformation_v1 tests/test_tracking_cloth_deformation_v1.py > formatting.patch || true
cat formatting.patch
python -m ruff check experiments/tracking_cloth_deformation_v1 tests/test_tracking_cloth_deformation_v1.py
python -m ruff format --check experiments/tracking_cloth_deformation_v1 tests/test_tracking_cloth_deformation_v1.py
- name: Retain a formatting patch on validation failure
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0
with:
name: tracking-cloth-formatting-${{ github.run_id }}
path: formatting.patch
retention-days: 7
if-no-files-found: ignore

authorize-real-data:
name: Authorize target-closed real-data request
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 2
- name: Require main for manual dispatch
if: github.event_name == 'workflow_dispatch'
shell: bash
run: test "$GITHUB_REF" = refs/heads/main
- name: Require one newly added canonical request on push
if: github.event_name == 'push'
shell: bash
env:
BEFORE_SHA: ${{ github.event.before }}
PUSH_FORCED: ${{ github.event.forced }}
run: |
set -euo pipefail
request=.github/requests/tracking-cloth-deformation-v1-evaluate.json
test "$GITHUB_REF" = refs/heads/main
test "$PUSH_FORCED" = false
test "$BEFORE_SHA" != 0000000000000000000000000000000000000000
mapfile -t changed < <(git diff --name-status "$BEFORE_SHA" "$GITHUB_SHA")
printf 'Changed files:\n%s\n' "${changed[*]}"
test "${#changed[@]}" -eq 1
test "${changed[0]}" = $'A\t'"$request"
python - <<'PY'
import json
import os
import subprocess
from pathlib import Path

path = Path(".github/requests/tracking-cloth-deformation-v1-evaluate.json")
request = json.loads(path.read_text())
parent = subprocess.check_output(
["git", "rev-parse", f"{os.environ['GITHUB_SHA']}^"], text=True
).strip()
if request["expected_source_revision"] != parent:
raise SystemExit(
"Request expected_source_revision does not equal the trigger commit parent"
)
PY

evaluation:
name: Read-only cloth pilot / gpuserver4090
needs: [contracts, authorize-real-data]
if: >-
always() &&
(github.event_name == 'workflow_dispatch' || github.event_name == 'push') &&
github.ref == 'refs/heads/main' &&
github.repository == 'IPS-Stuttgart/BayesianPhysTwin' &&
needs.contracts.result == 'success' &&
needs.authorize-real-data.result == 'success'
runs-on: [self-hosted, Linux, X64, gpuserver4090]
timeout-minutes: 90
env:
DATASET_ROOT: /home/github-runner/.cache/datasets/tracking-cloth-deformation-v1-zenodo-14644526
EVALUATION_MODE: ${{ github.event_name == 'push' && 'evaluate' || inputs.mode }}
WORKERS: ${{ github.event_name == 'push' && '4' || inputs.workers }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: Prepare private scratch and isolated environment
shell: bash
run: |
set -euo pipefail
test -d "$DATASET_ROOT"
test -r "$DATASET_ROOT"
echo "Runner: $RUNNER_NAME; required label: gpuserver4090"
echo "Included dataset license: CC BY-NC-SA 4.0; metadata conflict retained."
venv="$RUNNER_TEMP/tracking-cloth-venv-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
output="$RUNNER_TEMP/tracking-cloth-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
test ! -e "$venv"
test ! -e "$output"
python -m venv "$venv"
"$venv/bin/python" -m pip install -r experiments/tracking_cloth_deformation_v1/requirements.txt
echo "CLOTH_PY=$venv/bin/python" >> "$GITHUB_ENV"
echo "CLOTH_VENV=$venv" >> "$GITHUB_ENV"
echo "CLOTH_OUT=$output" >> "$GITHUB_ENV"
- name: Audit, fit sources, and optionally seal target predictions
shell: bash
run: |
set -euo pipefail
case "$EVALUATION_MODE" in
inventory) stage=inventory ;;
source_only) stage=source ;;
evaluate) stage=predict ;;
*) echo "Unsupported mode" >&2; exit 2 ;;
esac
"$CLOTH_PY" -m experiments.tracking_cloth_deformation_v1.run \
--dataset-root "$DATASET_ROOT" --output "$CLOTH_OUT" \
--stage "$stage" --workers "$WORKERS"
"$CLOTH_PY" - <<'PY'
import hashlib
import json
import os
from pathlib import Path

event = os.environ["GITHUB_EVENT_NAME"]
request_path = Path(
".github/requests/tracking-cloth-deformation-v1-evaluate.json"
)
if event == "push":
raw = request_path.read_bytes()
request = json.loads(raw)
request_sha256 = hashlib.sha256(raw).hexdigest()
else:
request = {
"schema": "tracking-cloth-deformation-manual-dispatch-v1",
"request_id": f"github-run-{os.environ['GITHUB_RUN_ID']}-attempt-{os.environ['GITHUB_RUN_ATTEMPT']}",
"mode": os.environ["EVALUATION_MODE"],
"dataset_root": os.environ["DATASET_ROOT"],
"runner_label": "gpuserver4090",
"workers": int(os.environ["WORKERS"]),
"authorize_target_scoring": os.environ["EVALUATION_MODE"] == "evaluate",
"paper_claim_authorized": False,
}
raw = json.dumps(request, sort_keys=True, separators=(",", ":")).encode()
request_sha256 = hashlib.sha256(raw).hexdigest()
record = {
**request,
"request_sha256": request_sha256,
"github_sha": os.environ["GITHUB_SHA"],
"github_run_id": os.environ["GITHUB_RUN_ID"],
"github_run_attempt": os.environ["GITHUB_RUN_ATTEMPT"],
}
output = Path(os.environ["CLOTH_OUT"]) / "evaluation_request.json"
output.write_text(json.dumps(record, indent=2, sort_keys=True) + "\n")
PY
- name: Publish complete prediction seal before target scoring
if: env.EVALUATION_MODE == 'evaluate'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0
with:
name: tracking-cloth-prediction-seal-${{ github.run_id }}-${{ github.run_attempt }}
path: |
${{ env.CLOTH_OUT }}/protocol.json
${{ env.CLOTH_OUT }}/source_fit.json
${{ env.CLOTH_OUT }}/dataset_manifest.json
${{ env.CLOTH_OUT }}/prediction_seal.json
${{ env.CLOTH_OUT }}/run_manifest.json
${{ env.CLOTH_OUT }}/evaluation_request.json
${{ env.CLOTH_OUT }}/DATA_LICENSE.txt
retention-days: 90
if-no-files-found: error
- name: Score only sealed twisting forecasts
if: env.EVALUATION_MODE == 'evaluate'
shell: bash
run: |
set -euo pipefail
"$CLOTH_PY" -m experiments.tracking_cloth_deformation_v1.run \
--dataset-root "$DATASET_ROOT" --output "$CLOTH_OUT" --stage score
- name: Publish operator summary
if: always() && env.CLOTH_OUT != ''
shell: bash
run: |
if test -f "$CLOTH_OUT/report.md"; then cat "$CLOTH_OUT/report.md" >> "$GITHUB_STEP_SUMMARY"; fi
if test -f "$CLOTH_OUT/failure.json"; then
echo '## Incomplete run: no scientific conclusion' >> "$GITHUB_STEP_SUMMARY"
cat "$CLOTH_OUT/failure.json" >> "$GITHUB_STEP_SUMMARY"
fi
- name: Upload aggregate evidence only, never raw recordings or trajectory arrays
if: always() && env.CLOTH_OUT != ''
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0
with:
name: tracking-cloth-${{ env.EVALUATION_MODE }}-${{ github.run_id }}-${{ github.run_attempt }}
path: |
${{ env.CLOTH_OUT }}/*.json
${{ env.CLOTH_OUT }}/*.csv
${{ env.CLOTH_OUT }}/report.md
${{ env.CLOTH_OUT }}/DATA_LICENSE.txt
retention-days: 90
if-no-files-found: warn
- name: Remove private predictions and isolated environment
if: always()
shell: bash
run: |
if test -n "${CLOTH_OUT:-}"; then rm -rf "$CLOTH_OUT/private_predictions"; fi
if test -n "${CLOTH_VENV:-}"; then rm -rf "$CLOTH_VENV"; fi
19 changes: 14 additions & 5 deletions docs/workflow_inventory_budget.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ At source revision
The machine-readable contract is
`.github/quality/workflow-inventory-budget-v1.json`.

## Completed one-shot retirement and current reviewed increase
## Completed one-shot retirement and reviewed permanent increases

The twelve historical one-shot files are absent from `.github/workflows`. Their
exact Git blobs are retained below
Expand All @@ -46,18 +46,27 @@ ordinary workflows with zero temporary-looking files. The permanent
addition: it runs the target-free controlled falsification study, requires
primary/replay byte identity, binds regenerated output to the retained result,
and records the exact reviewed head and canonical Python/NumPy runtime. Its
addition raises the checked-in ceiling by one, from 81 to 82, without changing
addition raised the checked-in ceiling by one, from 81 to 82, without changing
the retirement target.

The permanent `tracking-cloth-evaluation.yml` workflow is a second deliberately
reviewed addition. It provides synthetic contract validation plus a read-only,
main-branch-only public real-data pilot on the protected `gpuserver4090` runner.
The workflow freezes source-only shake fitting before twisting-target scoring,
publishes the complete prediction seal before scoring, retains aggregate
evidence only, and requires a canonical single-file authorization commit for
the first target-scored run. Its addition raises the checked-in ceiling by one,
from 82 to 83, without changing the retirement target.

The exact active inventory and targets are therefore:

- 82 checked-in workflows;
- 83 checked-in workflows;
- zero temporary-looking workflow files;
- a retirement target of at most 81 checked-in workflows; and
- a retirement target of zero temporary-looking workflows.

The one-workflow retirement gap is intentional and visible. A future
consolidation or retirement should lower the ceiling back to 81 in the same
The two-workflow retirement gap is intentional and visible. Future
consolidations or retirements should lower the ceiling toward 81 in the same
change rather than silently reusing that capacity.

Validate the active inventory with:
Expand Down
Loading
Loading