diff --git a/docs/slides/assets/boil_oracle_demo.mp4 b/docs/slides/assets/boil_oracle_demo.mp4 new file mode 100644 index 000000000..5b72ed343 Binary files /dev/null and b/docs/slides/assets/boil_oracle_demo.mp4 differ diff --git a/docs/slides/assets/bridge_explore_1x3.mp4 b/docs/slides/assets/bridge_explore_1x3.mp4 new file mode 100644 index 000000000..ce0753ef2 Binary files /dev/null and b/docs/slides/assets/bridge_explore_1x3.mp4 differ diff --git a/docs/slides/assets/bridge_oracle_hybrid_1x3.mp4 b/docs/slides/assets/bridge_oracle_hybrid_1x3.mp4 new file mode 100644 index 000000000..4394ca97a Binary files /dev/null and b/docs/slides/assets/bridge_oracle_hybrid_1x3.mp4 differ diff --git a/docs/slides/assets/bridge_oracle_hybrid_seed0.mp4 b/docs/slides/assets/bridge_oracle_hybrid_seed0.mp4 new file mode 100644 index 000000000..34753a01c Binary files /dev/null and b/docs/slides/assets/bridge_oracle_hybrid_seed0.mp4 differ diff --git a/docs/slides/assets/domino_al_test_seed0.mp4 b/docs/slides/assets/domino_al_test_seed0.mp4 new file mode 100644 index 000000000..00453b5e2 Binary files /dev/null and b/docs/slides/assets/domino_al_test_seed0.mp4 differ diff --git a/docs/slides/assets/fan_al_test_seed1.mp4 b/docs/slides/assets/fan_al_test_seed1.mp4 new file mode 100644 index 000000000..6be7146ac Binary files /dev/null and b/docs/slides/assets/fan_al_test_seed1.mp4 differ diff --git a/docs/slides/assets/make_bridge_mosaics.py b/docs/slides/assets/make_bridge_mosaics.py new file mode 100644 index 000000000..52fc99457 --- /dev/null +++ b/docs/slides/assets/make_bridge_mosaics.py @@ -0,0 +1,110 @@ +"""Build the bridge 1x3 mosaics for the 2026-08-20 weekly-sync deck. + +Two grids, one row of three seeds each: + + bridge_oracle_hybrid_1x3.mp4 the agent_oracle_hybrid_sim arm's solved + test episodes (opus replication, seeds + 0/1/2, all first-attempt solves) + bridge_explore_1x3.mp4 cycle-0 explore episodes of the learning + arm's 2026-08-19 diagnostic runs (seeds + 0/1/2) - the agent experimenting with + glue before it has any cure model + +Sources are 900x900; same recipe as make_al_margin_mosaics.py minus the +crop (the bridge camera has no dead floor region): lanczos downscale, +hairline border, short clips hold their last frame so the row loops +together. + +Usage: + python docs/slides/assets/make_bridge_mosaics.py +""" +import subprocess +from pathlib import Path + +import imageio_ffmpeg + +HERE = Path(__file__).resolve().parent +REPO = HERE.parents[2] +VIDEOS = REPO / "videos" + +ORACLE_HYBRID = (VIDEOS / "agent_sim_learning" / + "bridge-agent_oracle_hybrid_sim_opus") +ORACLE_RUNS = { + 0: "run_20260819_104107", + 1: "run_20260819_104104", + 2: "run_20260819_104101", +} +LEARNING = (VIDEOS / "agent_sim_predicate_invention" / + "bridge-agent_po_predicate_invention_al") + +TILE = 424 # px per tile after downscale; 3 tiles -> ~1.3k row +BORDER = 3 +FPS = 20 + + +def _oracle_clip(seed: int) -> Path: + run_dir = ORACLE_HYBRID / f"seed{seed}" / ORACLE_RUNS[seed] + matches = sorted(run_dir.glob("*__task1__cycleNone.mp4")) + assert len(matches) == 1, (run_dir, matches) + return matches[0] + + +def _explore_clip(seed: int) -> Path: + """First cycle-0 explore episode of the seed's 08-19 evening run.""" + run_dirs = sorted((LEARNING / f"seed{seed}").glob("run_20260819_18*")) + assert run_dirs, f"no 08-19 evening run for seed{seed}" + matches = sorted(run_dirs[-1].glob("*__ep0__cycle0.mp4")) + assert len(matches) == 1, (run_dirs[-1], matches) + return matches[0] + + +def _row_filter(n_inputs: int) -> str: + step = TILE + 2 * BORDER + per_input = "".join( + f"[{i}:v]scale={TILE}:{TILE}:flags=lanczos,fps={FPS}," + f"pad={step}:{step}:{BORDER}:{BORDER}:white," + f"tpad=stop_mode=clone:stop_duration=600[v{i}];" + for i in range(n_inputs)) + layout = "|".join(f"{i * step}_0" for i in range(n_inputs)) + return (f"{per_input}" + f"{''.join(f'[v{i}]' for i in range(n_inputs))}" + f"xstack=inputs={n_inputs}:layout={layout}:shortest=0[grid]") + + +def _duration(ffmpeg: str, path: Path) -> float: + out = subprocess.run([ffmpeg, "-hide_banner", "-i", str(path)], + capture_output=True, + text=True, + check=False).stderr + for line in out.splitlines(): + if "Duration:" in line: + hh, mm, ss = line.split("Duration:")[1].split(",")[0].split(":") + return int(hh) * 3600 + int(mm) * 60 + float(ss) + raise RuntimeError(f"no duration reported for {path}") + + +def build(stem: str, clips: list[Path]) -> None: + ffmpeg = imageio_ffmpeg.get_ffmpeg_exe() + longest = max(_duration(ffmpeg, c) for c in clips) + mp4 = HERE / f"{stem}.mp4" + inputs = [arg for c in clips for arg in ("-i", str(c))] + subprocess.run([ + ffmpeg, "-y", "-hide_banner", "-loglevel", "error", *inputs, + "-filter_complex", + _row_filter(len(clips)), "-map", "[grid]", "-t", f"{longest:.2f}", + "-c:v", "libx264", "-preset", "slow", "-crf", "22", "-pix_fmt", + "yuv420p", "-movflags", "+faststart", + str(mp4) + ], + check=True) + print(f"wrote {mp4} ({mp4.stat().st_size // 1024} KB)") + + +def main() -> int: + build("bridge_oracle_hybrid_1x3", [_oracle_clip(s) for s in (0, 1, 2)]) + build("bridge_explore_1x3", [_explore_clip(s) for s in (0, 1, 2)]) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/docs/slides/make_standalone.py b/docs/slides/make_standalone.py new file mode 100644 index 000000000..658a6be9b --- /dev/null +++ b/docs/slides/make_standalone.py @@ -0,0 +1,100 @@ +"""Build a fully standalone single-file version of the 2026-08-20 deck. + +Produces ``weekly_sync_20260820_slides_standalone.html`` next to the +source deck, with everything inlined so the file works offline and can +be shared as a single attachment: + + - reveal.js CSS/JS + plugins (fetched from the pinned CDN version), + - the white theme's Source Sans Pro font files (data URIs), + - every ``assets/`` image and video the deck references (data URIs). + +Needs network access at build time (for the reveal.js files only). +Re-run after editing the source deck. + +Usage: + python docs/slides/make_standalone.py +""" +import base64 +import mimetypes +import re +import sys +import urllib.request +from pathlib import Path + +HERE = Path(__file__).resolve().parent +SRC = HERE / "weekly_sync_20260820_slides.html" +OUT = HERE / "weekly_sync_20260820_slides_standalone.html" +CDN_BASE = "https://cdn.jsdelivr.net/npm/reveal.js@4.6.1" + +mimetypes.add_type("font/woff2", ".woff2") +mimetypes.add_type("font/woff", ".woff") +mimetypes.add_type("application/vnd.ms-fontobject", ".eot") + + +def data_uri(content: bytes, mime: str) -> str: + return f"data:{mime};base64," + base64.b64encode(content).decode("ascii") + + +def fetch(url: str) -> bytes: + with urllib.request.urlopen(url, timeout=60) as r: + return r.read() + + +def font_css_inlined() -> str: + """source-sans-pro.css with every url(...) embedded as a data URI.""" + base = f"{CDN_BASE}/dist/theme/fonts/source-sans-pro" + css = fetch(f"{base}/source-sans-pro.css").decode("utf-8") + + def repl(m: re.Match) -> str: + ref = m.group(1).strip("'\"") + path = ref.split("#")[0].split("?")[0].removeprefix("./") + mime = mimetypes.guess_type(path)[0] or "application/octet-stream" + blob = fetch(f"{base}/{path}") + print(f" embedded font {path} ({len(blob)//1024} KB)") + return f"url({data_uri(blob, mime)})" + + return re.sub(r"url\(([^)]+)\)", repl, css) + + +def main() -> int: + html = SRC.read_text(encoding="utf-8") + + for path in ("dist/reveal.css", "dist/theme/white.css", + "plugin/highlight/monokai.css"): + tag = f'' + assert tag in html, tag + css = fetch(f"{CDN_BASE}/{path}").decode("utf-8") + if path == "dist/theme/white.css": + imp = "@import url(./fonts/source-sans-pro/source-sans-pro.css);" + assert imp in css + print("inlining Source Sans Pro fonts...") + css = css.replace(imp, font_css_inlined()) + html = html.replace(tag, f"") + + for path in ("dist/reveal.js", "plugin/markdown/markdown.js", + "plugin/highlight/highlight.js", "plugin/notes/notes.js"): + tag = f'' + assert tag in html, tag + js = fetch(f"{CDN_BASE}/{path}").decode("utf-8") + # Inline JS must not close the surrounding tag early. + assert "\n{js}\n") + + for ref in sorted(set(re.findall(r'src="(assets/[^"]+)"', html))): + f = HERE / ref + assert f.is_file(), f + mime = mimetypes.guess_type(f.name)[0] + assert mime, f + blob = f.read_bytes() + html = html.replace(f'src="{ref}"', f'src="{data_uri(blob, mime)}"') + print(f"embedded {ref} ({len(blob)//1024} KB)") + + assert "cdn.jsdelivr.net" not in html, "CDN reference survived" + assert 'src="assets/' not in html, "asset reference survived" + OUT.write_text(html, encoding="utf-8") + print(f"\nwrote {OUT} ({OUT.stat().st_size / 1e6:.1f} MB)") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/docs/slides/weekly_sync_20260820_slides.html b/docs/slides/weekly_sync_20260820_slides.html new file mode 100644 index 000000000..5e7dd4617 --- /dev/null +++ b/docs/slides/weekly_sync_20260820_slides.html @@ -0,0 +1,270 @@ + + + + +Weekly Sync 2026-08-20: Bridge - Oracle Solved, Learning Made Honest + + + + + + + +
+ + + +
+ +
+ +
+ + + + + + + diff --git a/scripts/configs/predicatorv3/common.yaml b/scripts/configs/predicatorv3/common.yaml index 778555d9b..8927e076e 100644 --- a/scripts/configs/predicatorv3/common.yaml +++ b/scripts/configs/predicatorv3/common.yaml @@ -32,4 +32,4 @@ FLAGS: log: 'logs/' no_repeated_arguments_in_grounding: True START_SEED: 0 -NUM_SEEDS: 3 \ No newline at end of file +NUM_SEEDS: 1 \ No newline at end of file diff --git a/scripts/configs/predicatorv3/envs/all.yaml b/scripts/configs/predicatorv3/envs/all.yaml index 95fdb21b5..a685903a7 100644 --- a/scripts/configs/predicatorv3/envs/all.yaml +++ b/scripts/configs/predicatorv3/envs/all.yaml @@ -386,7 +386,7 @@ ENVS: # Parked by default; exp_bridge.yaml un-skips it. SKIP: True FLAGS: - max_initial_demos: 1 + max_initial_demos: 0 horizon: 3000 # A full assembly plan runs well past the common 500-step cap # (12 of 19 options already cost ~483 steps), so give explore diff --git a/scripts/configs/predicatorv3/exp_bridge.yaml b/scripts/configs/predicatorv3/exp_bridge.yaml index 4d0b7e737..7f39d2993 100644 --- a/scripts/configs/predicatorv3/exp_bridge.yaml +++ b/scripts/configs/predicatorv3/exp_bridge.yaml @@ -19,3 +19,5 @@ APPROACHES: SKIP: False FLAGS: skip_initial_test: True + bilevel_plan_without_sim: True # for the demonstrator + agent_solve_max_attempts: 1