-
Notifications
You must be signed in to change notification settings - Fork 0
159 lines (137 loc) · 6.2 KB
/
Copy pathci.yml
File metadata and controls
159 lines (137 loc) · 6.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
name: CI
on:
push:
branches: [master, main]
pull_request:
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
python:
name: Python checks
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# CPU-only torch: the CUDA wheel is several GB and CI never uses a GPU.
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install numpy scipy onnx onnxruntime onnxscript websockets textual
- name: Import every module
# Catches broken imports, bad signatures and syntax errors across the
# whole codebase without needing the optional audio/VR dependencies.
run: |
for m in data.schema data.session_writer inference.consent \
inference.donation inference.preview inference.rules \
inference.smoother models.gru_model training.train; do
echo "import $m"
python -c "import $m"
done
- name: Versions agree across Python, csproj and module.json
# The C# side cannot import browsync_version.py, so the three copies are
# checked here instead. They had already drifted once: the module logged
# v0.3.0 while the project was on 0.2.x.
run: |
python - <<'PY'
import json, re, sys
from pathlib import Path
from browsync_version import BROWSYNC_VERSION as V
csproj = Path("BrowSyncModule/BrowSyncModule/BrowSyncModule.csproj").read_text(encoding="utf-8")
cs_ver = re.search(r"<Version>([^<]+)</Version>", csproj).group(1)
mod_ver = json.loads(
Path("BrowSyncModule/BrowSyncModule/module.json").read_text(encoding="utf-8")
)["Version"]
bad = [n for n, v in (("csproj", cs_ver), ("module.json", mod_ver)) if v != V]
if bad:
print(f"Version drift: browsync_version.py={V}, "
f"csproj={cs_ver}, module.json={mod_ver}", file=sys.stderr)
sys.exit(1)
print(f"versions agree: {V}")
PY
- name: Ingest constants match schema
# The ingest Space duplicates NUM_INPUTS and the signed-feature indices
# because it deploys separately. If they drift, the endpoint silently
# rejects valid donations.
run: python tests/test_ingest_schema_sync.py
- name: Consent gate refuses upload without consent
run: |
python - <<'PY'
import json, tempfile
from pathlib import Path
from inference.consent import ConsentState, CONSENT_VERSION
from inference.donation import DonationClient
tmp = Path(tempfile.mkdtemp())
cfg, sess = tmp / "config.json", tmp / "s.jsonl"
sess.write_text('{"timestamp_ms":0,"inputs":[0.0],"targets":[0.0],'
'"has_labels":false,"session_id":"x"}\n')
def refuses(consent_block):
cfg.write_text(json.dumps({"donation": {
"ingest_url": "http://127.0.0.1:1",
"consent": consent_block}}))
r = DonationClient(config_path=cfg).upload(sess, ConsentState.load(cfg))
return (not r.ok) and "consent" in r.message
assert refuses({}), "absent consent must block upload"
assert refuses({"granted": False, "version": CONSENT_VERSION}), "denied must block"
assert refuses({"granted": True, "version": "stale"}), "stale version must block"
cfg.write_text("{ not json")
assert not ConsentState.load(cfg).allows_upload, "corrupt config must fail closed"
print("consent gate OK")
PY
- name: Smoother stability and asymmetry
run: |
python - <<'PY'
import numpy as np
from inference.smoother import BrowSmoother
s = BrowSmoother()
tgt = np.zeros(8, dtype=np.float32); tgt[0] = 1.0
rise = next(i for i in range(400) if s.smooth(tgt, 1/90)[0] >= 0.9)
tgt[0] = 0.0
fall = next(i for i in range(800) if s.smooth(tgt, 1/90)[0] <= 0.1)
assert fall > rise, f"attack/decay must be asymmetric (rise={rise} fall={fall})"
# Must not diverge at the 20fps dt clamp.
s2 = BrowSmoother(); t2 = np.ones(8, dtype=np.float32)
for _ in range(500):
out = s2.smooth(t2, 0.05)
assert np.all(np.isfinite(out)) and out.max() <= 1.0, "smoother diverged at 20fps"
print(f"smoother OK (rise={rise} fall={fall})")
PY
- name: Synthetic ground truth is independent of the rule base
# If these coincide the residual objective is degenerate and training
# can only ever learn to output zero.
run: |
python - <<'PY'
import numpy as np
from data.synthetic.generate_synthetic import generate_session
from inference.rules import RuleBasedEstimator
frames = generate_session(n_frames=900, session_id="ci", seed=1)
est = RuleBasedEstimator(deterministic=True)
gt = np.stack([f.targets for f in frames])
rule = np.stack([est.estimate_baseline(f) for f in frames])
resid = float((gt - rule).std())
assert resid > 0.01, f"ground truth collapsed onto the rule base (std={resid})"
print(f"residual std = {resid:.4f}")
PY
module:
name: VRCFT module build
runs-on: windows-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
- name: Build
working-directory: BrowSyncModule
run: dotnet build -c Release --nologo
- name: Verify module.json ships with the DLL
shell: bash
run: |
test -f BrowSyncModule/BrowSyncModule/module.json
python -c "import json;d=json.load(open('BrowSyncModule/BrowSyncModule/module.json'));assert d['DllFileName']=='BrowSyncModule.dll';print('module.json OK',d['ModuleId'])"