mirror of
https://github.com/ruvnet/RuView.git
synced 2026-08-26 10:05:54 +00:00
feat: add physics-constrained pose refinement
This commit is contained in:
1
scripts/pose-physics/testdata/golden-results.jsonl
vendored
Normal file
1
scripts/pose-physics/testdata/golden-results.jsonl
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"ankle_penetration_m":0.04,"evidence":"SYNTHETIC/L0","expected_raw_hash":"98caf45c249d584d52ede84e2d76bd8c4bf225d426a4ef1651a5ddb178258b88","expected_result_hash":"8ef2ded432c938055a5ebc86eadff811216884093853f5c740c7aff7708b9bef","sequence":1}
|
||||
21
scripts/pose-physics/testdata/leaky-split-manifest.json
vendored
Normal file
21
scripts/pose-physics/testdata/leaky-split-manifest.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"records": [
|
||||
{
|
||||
"split": "train",
|
||||
"sequence": "sequence-1",
|
||||
"take": "take-1",
|
||||
"subject": "subject-1",
|
||||
"room": "room-1",
|
||||
"calibration_session": "calibration-1"
|
||||
},
|
||||
{
|
||||
"split": "test",
|
||||
"sequence": "sequence-2",
|
||||
"take": "take-2",
|
||||
"subject": "subject-1",
|
||||
"room": "room-2",
|
||||
"calibration_session": "calibration-2"
|
||||
}
|
||||
]
|
||||
}
|
||||
8
scripts/pose-physics/testdata/strict-split-manifest.json
vendored
Normal file
8
scripts/pose-physics/testdata/strict-split-manifest.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"evidence": "SYNTHETIC/L0",
|
||||
"records": [
|
||||
{ "split": "train", "sequence": "syn-train-seq", "take": "syn-train-take", "subject": "syn-train-subject", "room": "syn-train-room", "calibration_session": "syn-train-cal" },
|
||||
{ "split": "validation", "sequence": "syn-validation-seq", "take": "syn-validation-take", "subject": "syn-validation-subject", "room": "syn-validation-room", "calibration_session": "syn-validation-cal" },
|
||||
{ "split": "test", "sequence": "syn-test-seq", "take": "syn-test-take", "subject": "syn-test-subject", "room": "syn-test-room", "calibration_session": "syn-test-cal" }
|
||||
]
|
||||
}
|
||||
25
scripts/pose-physics/verify-feature-boundary.mjs
Normal file
25
scripts/pose-physics/verify-feature-boundary.mjs
Normal file
@@ -0,0 +1,25 @@
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const result = spawnSync(
|
||||
"cargo",
|
||||
["tree", "-p", "wifi-densepose-physics", "-e", "normal", "--prefix", "none"],
|
||||
{ cwd: path.join(root, "v2"), encoding: "utf8" },
|
||||
);
|
||||
|
||||
if (result.error) throw result.error;
|
||||
if (result.status !== 0) {
|
||||
if (result.stdout) process.stderr.write(result.stdout);
|
||||
if (result.stderr) process.stderr.write(result.stderr);
|
||||
process.exit(result.status ?? 1);
|
||||
}
|
||||
|
||||
const forbidden = /^(?:burn(?:-|\s|$)|rapier3d(?:\s|$)|tch(?:\s|$)|ort(?:\s|$))/m;
|
||||
if (forbidden.test(result.stdout)) {
|
||||
process.stderr.write(result.stdout);
|
||||
throw new Error("default physics dependency graph contains an optional heavy backend");
|
||||
}
|
||||
|
||||
process.stdout.write(JSON.stringify({ verdict: "PASS", profile: "default-kinematic" }) + "\n");
|
||||
16
scripts/pose-physics/verify-golden.mjs
Normal file
16
scripts/pose-physics/verify-golden.mjs
Normal file
@@ -0,0 +1,16 @@
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
const input = process.argv[2];
|
||||
if (!input) throw new Error("usage: replay-pose-physics-golden.sh <golden-results.jsonl>");
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const result = spawnSync(
|
||||
"cargo",
|
||||
["run", "--quiet", "-p", "wifi-densepose-physics", "--features", "deterministic", "--example", "verify_golden", "--", path.resolve(input)],
|
||||
{ cwd: path.join(root, "v2"), encoding: "utf8" },
|
||||
);
|
||||
if (result.stdout) process.stdout.write(result.stdout);
|
||||
if (result.stderr) process.stderr.write(result.stderr);
|
||||
if (result.error) throw result.error;
|
||||
if (result.status !== 0) process.exit(result.status ?? 1);
|
||||
27
scripts/pose-physics/verify-harness-tests.mjs
Normal file
27
scripts/pose-physics/verify-harness-tests.mjs
Normal file
@@ -0,0 +1,27 @@
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
const directory = path.dirname(fileURLToPath(import.meta.url));
|
||||
const run = (script, fixture) =>
|
||||
spawnSync(process.execPath, [path.join(directory, script), path.join(directory, "testdata", fixture)], {
|
||||
cwd: path.resolve(directory, "../.."),
|
||||
encoding: "utf8",
|
||||
});
|
||||
|
||||
const strict = run("verify-splits.mjs", "strict-split-manifest.json");
|
||||
if (strict.status !== 0 || !strict.stdout.includes('"verdict":"PASS"')) {
|
||||
throw new Error(`strict split fixture failed: ${strict.stderr || strict.stdout}`);
|
||||
}
|
||||
|
||||
const leaky = run("verify-splits.mjs", "leaky-split-manifest.json");
|
||||
if (leaky.status === 0 || !leaky.stderr.includes("leakage:")) {
|
||||
throw new Error("leaky split fixture was not rejected with a typed leakage error");
|
||||
}
|
||||
|
||||
const golden = run("verify-golden.mjs", "golden-results.jsonl");
|
||||
if (golden.status !== 0 || !golden.stdout.includes('"verdict":"PASS"')) {
|
||||
throw new Error(`golden replay fixture failed: ${golden.stderr || golden.stdout}`);
|
||||
}
|
||||
|
||||
process.stdout.write(JSON.stringify({ verdict: "PASS", checks: 3 }) + "\n");
|
||||
23
scripts/pose-physics/verify-splits.mjs
Normal file
23
scripts/pose-physics/verify-splits.mjs
Normal file
@@ -0,0 +1,23 @@
|
||||
import fs from "node:fs";
|
||||
import crypto from "node:crypto";
|
||||
|
||||
const path = process.argv[2];
|
||||
if (!path) throw new Error("usage: verify-pose-physics-splits.sh <manifest.json>");
|
||||
const bytes = fs.readFileSync(path);
|
||||
const manifest = JSON.parse(bytes);
|
||||
const dimensions = ["sequence", "take", "subject", "room", "calibration_session"];
|
||||
if (!Array.isArray(manifest.records) || manifest.records.length === 0) throw new Error("manifest.records must be non-empty");
|
||||
const ownership = new Map();
|
||||
for (const record of manifest.records) {
|
||||
if (!record.split || !["train", "validation", "test"].includes(record.split)) throw new Error("invalid split");
|
||||
for (const dimension of dimensions) {
|
||||
const value = record[dimension];
|
||||
if (typeof value !== "string" || value.length === 0) throw new Error(`missing ${dimension}`);
|
||||
const key = `${dimension}:${value}`;
|
||||
const prior = ownership.get(key);
|
||||
if (prior && prior !== record.split) throw new Error(`leakage: ${key} crosses ${prior}/${record.split}`);
|
||||
ownership.set(key, record.split);
|
||||
}
|
||||
}
|
||||
const digest = crypto.createHash("sha256").update(bytes).digest("hex");
|
||||
console.log(JSON.stringify({ verdict: "PASS", records: manifest.records.length, sha256: digest }));
|
||||
Reference in New Issue
Block a user