ar-mine commited on
Commit
91ddf7c
·
verified ·
1 Parent(s): e41bef1

Add pinned stage2_core_v1 reconstruction and derived action sidecars

Browse files
DATA_SETUP.md ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # `stage2_core_v1` data setup and linkage
2
+
3
+ ## What is and is not stored here
4
+
5
+ `stage2_core_v1` is this experiment's pinned selection from the official
6
+ `robometer/processed_datasets` repository; it is not an upstream release name.
7
+ The official trajectory `.npz` files are deliberately not duplicated here.
8
+
9
+ This private repository stores only assets that the official download cannot
10
+ recreate by itself:
11
+
12
+ - the frozen 2,689-row Phase 2.1A pair manifest;
13
+ - the exact 4,323-file subset inventory and checksums;
14
+ - recovered action sidecars and portable recovery manifests;
15
+ - download, extraction, linkage, and verification tools.
16
+
17
+ The active profile contains 53,765 trajectories in 13 cache directories. It
18
+ requires 14 physical archive files (RoboArena has two parts), approximately
19
+ 106.9 GiB compressed. The quarantined LIBERO Goal-failure archive is excluded.
20
+
21
+ ## 1. Download the pinned official archives
22
+
23
+ Choose storage with at least 230 GiB free for archives plus extraction:
24
+
25
+ ```bash
26
+ KIT_ROOT=/path/to/cosmos-robometer-private-code
27
+ DATA_ROOT=/path/to/stage2_core_v1
28
+
29
+ cd "$KIT_ROOT"
30
+ uv run --project environment/phase21a_robometer \
31
+ python scripts/download_stage2_core_v1.py \
32
+ --output-dir "$DATA_ROOT/archives"
33
+ ```
34
+
35
+ The script downloads only the active profile from:
36
+
37
+ ```text
38
+ robometer/processed_datasets
39
+ revision 1a8eb2d279c70964fadeaf8019a77c490c3abe02
40
+ ```
41
+
42
+ Do not use Robometer's unmodified `download_processed_datasets.sh` for this
43
+ profile: that script downloads the entire multi-terabyte repository and uses a
44
+ floating revision.
45
+
46
+ ## 2. Extract into the path expected by the manifest
47
+
48
+ ```bash
49
+ uv run --project environment/phase21a_robometer \
50
+ python scripts/extract_stage2_core_v1.py \
51
+ --archive-root "$DATA_ROOT/archives" \
52
+ --extract-root "$DATA_ROOT/processed_datasets" \
53
+ --output "$DATA_ROOT/extraction_report.json"
54
+ ```
55
+
56
+ The frozen pair manifest stores paths beginning with `processed_datasets/`.
57
+ Pass the directory itself to trainers:
58
+
59
+ ```bash
60
+ --manifest "$KIT_ROOT/manifests/phase2_remediation_pairs_v1.jsonl" \
61
+ --processed-root "$DATA_ROOT/processed_datasets"
62
+ ```
63
+
64
+ No symlink is required. If an existing installation expects a project-local
65
+ path, create a symlink named `processed_datasets` pointing to the extracted
66
+ directory; never copy the 100+ GiB tree merely to satisfy a path convention.
67
+
68
+ ## 3. Extract the non-official derived action sidecars
69
+
70
+ ```bash
71
+ mkdir -p "$DATA_ROOT/derived"
72
+ tar -xf "$KIT_ROOT/derived/action_sidecars_stage2_action_sidecar_v1.tar" \
73
+ -C "$DATA_ROOT/derived"
74
+ cd "$KIT_ROOT"
75
+ sha256sum --check derived/action_sidecars_stage2_action_sidecar_v1.tar.sha256
76
+ ```
77
+
78
+ The archive contains:
79
+
80
+ | Source | Scope | Sidecars | Raw action width |
81
+ |---|---|---:|---:|
82
+ | AutoEval | full attempted scope | 5,939 | 7 |
83
+ | LIBERO success | full | 1,709 | 7 |
84
+ | RoboArena | full, refined | 12,379 | 8 |
85
+ | RACER | pilot: `insert_onto_square_peg` | 593 | 9 |
86
+
87
+ These actions preserve each upstream action space; they are not converted into
88
+ a common canonical representation. Each `.npz` includes `metadata_json`, raw
89
+ actions, aligned actions, and source/alignment indices. RACER's fields are
90
+ `x,y,z,qx,qy,qz,qw,gripper_open,ignore_collision`. For the other sources, use
91
+ the upstream convention recorded in `metadata_json`; do not reinterpret their
92
+ unnamed raw dimensions as Cosmos 6D rotation features.
93
+
94
+ ## 4. Join trajectories and action sidecars
95
+
96
+ Join by `stage2_trajectory_id`, never by dataset row order. For example:
97
+
98
+ ```text
99
+ official trajectory:
100
+ processed_datasets/<cache_key>/frames/trajectory_<ID>.npz
101
+
102
+ portable action manifest row:
103
+ stage2_trajectory_id = <ID>
104
+ sidecar_path = action_sidecars/<source>/trajectory_<ID>.npz
105
+ ```
106
+
107
+ Resolve `sidecar_path` relative to `$DATA_ROOT/derived`. Rows without a
108
+ `sidecar_path` were not recovered and retain an explicit status such as
109
+ `source_has_no_actions` or `rejected_refinement_no_consensus`.
110
+
111
+ `Robometer-Low-LoRA` does not consume the action sidecars; they are packaged for
112
+ later action-conditioned Cosmos experiments and provenance auditing.
113
+
114
+ ## 5. Verify the complete association
115
+
116
+ Fast path/link check:
117
+
118
+ ```bash
119
+ uv run --project environment/phase21a_robometer \
120
+ python scripts/verify_stage2_links.py \
121
+ --manifest "$KIT_ROOT/manifests/phase2_remediation_pairs_v1.jsonl" \
122
+ --processed-root "$DATA_ROOT/processed_datasets" \
123
+ --action-manifest-dir "$KIT_ROOT/derived/action_manifests" \
124
+ --derived-root "$DATA_ROOT/derived"
125
+ ```
126
+
127
+ Full byte-level verification of the 4,323 training trajectories adds:
128
+
129
+ ```bash
130
+ --checksums "$KIT_ROOT/manifests/stage2_subset_SHA256SUMS"
131
+ ```
132
+
133
+ Expected link-check totals are 2,689 pair rows, 4,323 unique official frame
134
+ files, 23,359 action-manifest rows, and 20,620 resolved action sidecars.
README.md CHANGED
@@ -53,6 +53,10 @@ Robometer processed-data repository and the frozen dataset manifest.
53
  See [TRAINING_MANUAL.md](TRAINING_MANUAL.md). The frozen LoRA configuration is
54
  `configs/phase21a_robometer_low_lora_train_v2.yaml`.
55
 
 
 
 
 
56
  ## Current support boundary
57
 
58
  The LoRA trainer is runnable and validated at micro-batch 32, gradient
 
53
  See [TRAINING_MANUAL.md](TRAINING_MANUAL.md). The frozen LoRA configuration is
54
  `configs/phase21a_robometer_low_lora_train_v2.yaml`.
55
 
56
+ For the pinned official `stage2_core_v1` download, extraction, frozen-manifest
57
+ association, and optional recovered-action linkage, see
58
+ [DATA_SETUP.md](DATA_SETUP.md).
59
+
60
  ## Current support boundary
61
 
62
  The LoRA trainer is runnable and validated at micro-batch 32, gradient
derived/action_manifests/autoeval_full.jsonl ADDED
The diff for this file is too large to render. See raw diff
 
derived/action_manifests/libero_full.jsonl ADDED
The diff for this file is too large to render. See raw diff
 
derived/action_manifests/racer_pilot.jsonl ADDED
The diff for this file is too large to render. See raw diff
 
derived/action_manifests/roboarena_full_refined.jsonl ADDED
The diff for this file is too large to render. See raw diff
 
derived/action_reports/autoeval_full_validation.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "action_dims": {
3
+ "7": 5939
4
+ },
5
+ "aligned_action_steps": {
6
+ "max": 32,
7
+ "median": 32.0,
8
+ "min": 10
9
+ },
10
+ "error_count": 0,
11
+ "error_examples": [],
12
+ "manifest": "experiments/cosmos3_edge_reasoner_robometer_route_a_v1/manifests/action_recovery_v1/autoeval_full.jsonl",
13
+ "manifest_rows": 8677,
14
+ "raw_action_steps": {
15
+ "max": 100,
16
+ "median": 70.0,
17
+ "min": 10
18
+ },
19
+ "recovered_rows": 5939,
20
+ "status": "pass",
21
+ "status_counts": {
22
+ "recovered": 5919,
23
+ "recovered_refined": 20,
24
+ "rejected_refinement_no_consensus": 20,
25
+ "source_has_no_actions": 2647,
26
+ "source_has_no_actions_refined": 71
27
+ },
28
+ "unique_sidecar_paths": 5939,
29
+ "unique_trajectory_ids": 5939
30
+ }
derived/action_reports/libero_full_validation.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "action_dims": {
3
+ "7": 1709
4
+ },
5
+ "aligned_action_steps": {
6
+ "max": 32,
7
+ "median": 32.0,
8
+ "min": 32
9
+ },
10
+ "error_count": 0,
11
+ "error_examples": [],
12
+ "manifest": "experiments/cosmos3_edge_reasoner_robometer_route_a_v1/manifests/action_recovery_v1/libero_full.jsonl",
13
+ "manifest_rows": 1709,
14
+ "raw_action_steps": {
15
+ "max": 505,
16
+ "median": 141.0,
17
+ "min": 75
18
+ },
19
+ "recovered_rows": 1709,
20
+ "status": "pass",
21
+ "status_counts": {
22
+ "recovered": 1709
23
+ },
24
+ "unique_sidecar_paths": 1709,
25
+ "unique_trajectory_ids": 1709
26
+ }
derived/action_reports/racer_pilot_validation.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "action_dims": {
3
+ "9": 593
4
+ },
5
+ "aligned_action_steps": {
6
+ "max": 6,
7
+ "median": 6.0,
8
+ "min": 2
9
+ },
10
+ "error_count": 0,
11
+ "error_examples": [],
12
+ "manifest": "experiments/cosmos3_edge_reasoner_robometer_route_a_v1/manifests/action_recovery_v1/racer_pilot.jsonl",
13
+ "manifest_rows": 594,
14
+ "raw_action_steps": {
15
+ "max": 8,
16
+ "median": 8.0,
17
+ "min": 6
18
+ },
19
+ "recovered_rows": 593,
20
+ "status": "pass",
21
+ "status_counts": {
22
+ "recovered": 593,
23
+ "rejected_alignment": 1
24
+ },
25
+ "unique_sidecar_paths": 593,
26
+ "unique_trajectory_ids": 593
27
+ }
derived/action_reports/roboarena_full_refined_validation.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "action_dims": {
3
+ "8": 12379
4
+ },
5
+ "aligned_action_steps": {
6
+ "max": 32,
7
+ "median": 32.0,
8
+ "min": 18
9
+ },
10
+ "error_count": 0,
11
+ "error_examples": [],
12
+ "manifest": "experiments/cosmos3_edge_reasoner_robometer_route_a_v1/manifests/action_recovery_v1/roboarena_full_refined.jsonl",
13
+ "manifest_rows": 12379,
14
+ "raw_action_steps": {
15
+ "max": 800,
16
+ "median": 400.0,
17
+ "min": 17
18
+ },
19
+ "recovered_rows": 12379,
20
+ "status": "pass",
21
+ "status_counts": {
22
+ "recovered": 12326,
23
+ "recovered_refined": 53
24
+ },
25
+ "unique_sidecar_paths": 12379,
26
+ "unique_trajectory_ids": 12379
27
+ }
derived/action_reports/summary.json ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "created_at": "2026-08-26T17:15:00+08:00",
3
+ "policy": {
4
+ "canonicalized_during_recovery": false,
5
+ "imputed_actions": false,
6
+ "mutated_frozen_stage2_cache": false,
7
+ "preserved_raw_action_space": true
8
+ },
9
+ "profile": "stage2_core_v1",
10
+ "results": {
11
+ "autoeval": {
12
+ "action_dim": 7,
13
+ "attempted_rows": 8677,
14
+ "recovered_rows": 5939,
15
+ "rejected_rows": 20,
16
+ "scope": "full",
17
+ "source_has_no_action_rows": 2718,
18
+ "validation_errors": 0
19
+ },
20
+ "libero_success": {
21
+ "action_dim": 7,
22
+ "attempted_rows": 1709,
23
+ "recovered_rows": 1709,
24
+ "rejected_rows": 0,
25
+ "scope": "full",
26
+ "source_has_no_action_rows": 0,
27
+ "validation_errors": 0
28
+ },
29
+ "racer": {
30
+ "action_dim": 9,
31
+ "attempted_rows": 594,
32
+ "expected_full_stage2_rows": 29115,
33
+ "recovered_rows": 593,
34
+ "rejected_rows": 1,
35
+ "scope": "pilot_insert_onto_square_peg",
36
+ "source_has_no_action_rows": 0,
37
+ "validation_errors": 0
38
+ },
39
+ "roboarena": {
40
+ "action_dim": 8,
41
+ "attempted_rows": 12379,
42
+ "recovered_rows": 12379,
43
+ "rejected_rows": 0,
44
+ "scope": "full",
45
+ "source_has_no_action_rows": 0,
46
+ "validation_errors": 0
47
+ }
48
+ },
49
+ "schema_version": "stage2_action_sidecar_v1",
50
+ "totals_for_attempted_scope": {
51
+ "attempted_rows": 23359,
52
+ "recovered_rows": 20620,
53
+ "rejected_rows": 21,
54
+ "source_has_no_action_rows": 2718,
55
+ "validation_errors": 0
56
+ },
57
+ "unattempted_stage2_rows": {
58
+ "fino_net_exact_action_unavailable": 229,
59
+ "libero_failure_exact_action_unavailable": 1473,
60
+ "metaworld_provenance_pending": 100,
61
+ "motif_exact_action_unavailable": 83,
62
+ "racer_remaining_full_scope": 28521,
63
+ "total": 30406
64
+ }
65
+ }
derived/action_sidecars_stage2_action_sidecar_v1.tar ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2b70561099696a769a6d6ee750270b48ab3ded47a44470173bf753a329a39a4e
3
+ size 455188480
derived/action_sidecars_stage2_action_sidecar_v1.tar.sha256 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5580061f5fd94ef18bb2a6ceb01f2bf1e7945634c27e3ba5df4685b8f4fa1f26
3
+ size 119
manifests/phase2_remediation_pairs_v1.jsonl ADDED
The diff for this file is too large to render. See raw diff
 
manifests/phase2_remediation_pairs_v1_summary.json CHANGED
@@ -1,26 +1,26 @@
1
  {
2
- "status": "pass",
3
- "role": "phase2_five_percent_id_only_remediation",
4
- "seed": 1701,
5
- "requested_confirmation_fraction_of_full_stream": 0.2,
6
- "pair_count": 2689,
7
- "original_stream_pair_count": 538,
8
- "train_pair_count": 2021,
9
- "original_dev_pair_count": 108,
10
- "confirmation_dev_pair_count": 538,
11
- "excluded_original_dev_component_pair_count": 22,
12
- "component_count": 2393,
13
- "eligible_confirmation_component_count": 1874,
14
- "selected_confirmation_component_count": 495,
15
- "original_dev_preserved_verbatim": true,
16
- "five_percent_is_exact_one_percent_prefix_extension": true,
17
- "confirmation_ids_seen_in_original_stream": 0,
18
  "active_split_trajectory_id_overlaps": {
19
- "train_dev": 0,
20
  "train_confirmation_dev": 0,
21
- "dev_confirmation_dev": 0
22
  },
23
  "active_unique_feature_sides": 5181,
 
 
 
 
 
 
24
  "manifest": "manifests/phase2_remediation_pairs_v1.jsonl",
25
- "manifest_sha256": "c77642e3d34177d1bfbcebe8c97cdf0af952c83d95a677cf42d95426b6d49204"
 
 
 
 
 
 
 
 
 
 
26
  }
 
1
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  "active_split_trajectory_id_overlaps": {
3
+ "dev_confirmation_dev": 0,
4
  "train_confirmation_dev": 0,
5
+ "train_dev": 0
6
  },
7
  "active_unique_feature_sides": 5181,
8
+ "component_count": 2393,
9
+ "confirmation_dev_pair_count": 538,
10
+ "confirmation_ids_seen_in_original_stream": 0,
11
+ "eligible_confirmation_component_count": 1874,
12
+ "excluded_original_dev_component_pair_count": 22,
13
+ "five_percent_is_exact_one_percent_prefix_extension": true,
14
  "manifest": "manifests/phase2_remediation_pairs_v1.jsonl",
15
+ "manifest_sha256": "c77642e3d34177d1bfbcebe8c97cdf0af952c83d95a677cf42d95426b6d49204",
16
+ "original_dev_pair_count": 108,
17
+ "original_dev_preserved_verbatim": true,
18
+ "original_stream_pair_count": 538,
19
+ "pair_count": 2689,
20
+ "requested_confirmation_fraction_of_full_stream": 0.2,
21
+ "role": "phase2_five_percent_id_only_remediation",
22
+ "seed": 1701,
23
+ "selected_confirmation_component_count": 495,
24
+ "status": "pass",
25
+ "train_pair_count": 2021
26
  }
manifests/stage2_core_v1_active_archives.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema_version": "stage2_core_v1_active_archives_v1",
3
+ "repo_id": "robometer/processed_datasets",
4
+ "revision": "1a8eb2d279c70964fadeaf8019a77c490c3abe02",
5
+ "profile": "stage2_core_v1_active",
6
+ "physical_archive_files": 14,
7
+ "logical_cache_directories": 13,
8
+ "expected_trajectories": 53765,
9
+ "total_bytes": 114772469760,
10
+ "total_gib": 106.89019203186035,
11
+ "quarantined_and_not_downloaded": [
12
+ "ykorkmaz_libero_failure_rfm_libero_goal_failure.tar"
13
+ ],
14
+ "archives": [
15
+ {"name": "abraranwar_libero_rfm_libero256_10.tar", "bytes": 743413760},
16
+ {"name": "abraranwar_libero_rfm_libero256_goal.tar", "bytes": 818688000},
17
+ {"name": "abraranwar_libero_rfm_libero256_object.tar", "bytes": 1179627520},
18
+ {"name": "abraranwar_libero_rfm_libero256_spatial.tar", "bytes": 796948480},
19
+ {"name": "aliangdw_metaworld_metaworld_train.tar", "bytes": 233943040},
20
+ {"name": "jesbu1_auto_eval_rfm_auto_eval_rfm.tar", "bytes": 33058539520},
21
+ {"name": "jesbu1_fino_net_rfm_fino_net.tar", "bytes": 865863680},
22
+ {"name": "jesbu1_motif_rfm_motif_rfm.tar", "bytes": 162570240},
23
+ {"name": "jesbu1_racer_rfm_racer_train.tar", "bytes": 15018711040},
24
+ {"name": "jesbu1_roboarena_0825_rfm_roboarena.tar.part-aa", "bytes": 32212254720},
25
+ {"name": "jesbu1_roboarena_0825_rfm_roboarena.tar.part-ab", "bytes": 26715269120},
26
+ {"name": "ykorkmaz_libero_failure_rfm_libero_10_failure.tar", "bytes": 968499200},
27
+ {"name": "ykorkmaz_libero_failure_rfm_libero_object_failure.tar", "bytes": 1107578880},
28
+ {"name": "ykorkmaz_libero_failure_rfm_libero_spatial_failure.tar", "bytes": 890562560}
29
+ ]
30
+ }
manifests/stage2_subset_SHA256SUMS ADDED
The diff for this file is too large to render. See raw diff
 
manifests/stage2_subset_inventory.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/download_stage2_core_v1.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Download the pinned active stage2_core_v1 archive profile from Robometer."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ from pathlib import Path
9
+
10
+ from huggingface_hub import snapshot_download
11
+
12
+
13
+ REPO_ID = "robometer/processed_datasets"
14
+ REVISION = "1a8eb2d279c70964fadeaf8019a77c490c3abe02"
15
+ ACTIVE_ARCHIVES = (
16
+ "abraranwar_libero_rfm_libero256_10.tar",
17
+ "abraranwar_libero_rfm_libero256_goal.tar",
18
+ "abraranwar_libero_rfm_libero256_object.tar",
19
+ "abraranwar_libero_rfm_libero256_spatial.tar",
20
+ "aliangdw_metaworld_metaworld_train.tar",
21
+ "jesbu1_auto_eval_rfm_auto_eval_rfm.tar",
22
+ "jesbu1_fino_net_rfm_fino_net.tar",
23
+ "jesbu1_motif_rfm_motif_rfm.tar",
24
+ "jesbu1_racer_rfm_racer_train.tar",
25
+ "jesbu1_roboarena_0825_rfm_roboarena.tar.part-aa",
26
+ "jesbu1_roboarena_0825_rfm_roboarena.tar.part-ab",
27
+ "ykorkmaz_libero_failure_rfm_libero_10_failure.tar",
28
+ "ykorkmaz_libero_failure_rfm_libero_object_failure.tar",
29
+ "ykorkmaz_libero_failure_rfm_libero_spatial_failure.tar",
30
+ )
31
+
32
+
33
+ def main() -> None:
34
+ parser = argparse.ArgumentParser()
35
+ parser.add_argument("--output-dir", type=Path, required=True)
36
+ args = parser.parse_args()
37
+ args.output_dir.mkdir(parents=True, exist_ok=True)
38
+ location = snapshot_download(
39
+ repo_id=REPO_ID,
40
+ repo_type="dataset",
41
+ revision=REVISION,
42
+ allow_patterns=list(ACTIVE_ARCHIVES),
43
+ local_dir=args.output_dir,
44
+ )
45
+ missing = [name for name in ACTIVE_ARCHIVES if not (args.output_dir / name).is_file()]
46
+ if missing:
47
+ raise FileNotFoundError(f"download completed with missing archives: {missing}")
48
+ print(json.dumps({
49
+ "status": "complete",
50
+ "repo_id": REPO_ID,
51
+ "revision": REVISION,
52
+ "profile": "stage2_core_v1_active",
53
+ "archive_files": len(ACTIVE_ARCHIVES),
54
+ "local_dir": str(Path(location).resolve()),
55
+ }, indent=2))
56
+
57
+
58
+ if __name__ == "__main__":
59
+ main()
scripts/extract_stage2_core_v1.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Safely extract the pinned stage2_core_v1 archive set without overwrites."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import subprocess
9
+ import time
10
+ from datetime import datetime
11
+ from pathlib import Path
12
+
13
+
14
+ EXPECTED_ARCHIVES = (
15
+ "abraranwar_libero_rfm_libero256_10.tar",
16
+ "abraranwar_libero_rfm_libero256_goal.tar",
17
+ "abraranwar_libero_rfm_libero256_object.tar",
18
+ "abraranwar_libero_rfm_libero256_spatial.tar",
19
+ "aliangdw_metaworld_metaworld_train.tar",
20
+ "jesbu1_auto_eval_rfm_auto_eval_rfm.tar",
21
+ "jesbu1_fino_net_rfm_fino_net.tar",
22
+ "jesbu1_motif_rfm_motif_rfm.tar",
23
+ "jesbu1_racer_rfm_racer_train.tar",
24
+ "jesbu1_roboarena_0825_rfm_roboarena.tar.part-aa",
25
+ "jesbu1_roboarena_0825_rfm_roboarena.tar.part-ab",
26
+ "ykorkmaz_libero_failure_rfm_libero_10_failure.tar",
27
+ "ykorkmaz_libero_failure_rfm_libero_object_failure.tar",
28
+ "ykorkmaz_libero_failure_rfm_libero_spatial_failure.tar",
29
+ )
30
+
31
+
32
+ def parse_args() -> argparse.Namespace:
33
+ parser = argparse.ArgumentParser()
34
+ parser.add_argument("--archive-root", type=Path, required=True)
35
+ parser.add_argument("--extract-root", type=Path, required=True)
36
+ parser.add_argument("--output", type=Path, required=True)
37
+ return parser.parse_args()
38
+
39
+
40
+ def cache_key(archive_name: str) -> str:
41
+ return archive_name.split(".tar", 1)[0]
42
+
43
+
44
+ def tar_command(extract_root: Path, archive: Path | None = None) -> list[str]:
45
+ archive_arg = str(archive) if archive is not None else "-"
46
+ return [
47
+ "tar",
48
+ "-xf",
49
+ archive_arg,
50
+ "-C",
51
+ str(extract_root),
52
+ "--no-same-owner",
53
+ "--no-same-permissions",
54
+ ]
55
+
56
+
57
+ def main() -> None:
58
+ args = parse_args()
59
+ archive_root = args.archive_root.resolve()
60
+ extract_root = args.extract_root.resolve()
61
+ missing = [
62
+ name for name in EXPECTED_ARCHIVES if not (archive_root / name).is_file()
63
+ ]
64
+ if missing:
65
+ raise FileNotFoundError(f"Missing expected archives: {missing}")
66
+
67
+ expected_names = set(EXPECTED_ARCHIVES)
68
+ observed_names = {
69
+ path.name
70
+ for path in archive_root.iterdir()
71
+ if path.is_file() and (".tar" in path.name)
72
+ }
73
+ if observed_names != expected_names:
74
+ raise RuntimeError(
75
+ "Archive set differs from the pinned contract: "
76
+ f"missing={sorted(expected_names - observed_names)}, "
77
+ f"unexpected={sorted(observed_names - expected_names)}"
78
+ )
79
+
80
+ extract_root.mkdir(parents=True, exist_ok=True)
81
+ logical_archives = [
82
+ name for name in EXPECTED_ARCHIVES if not name.endswith(".part-ab")
83
+ ]
84
+ target_keys = [cache_key(name) for name in logical_archives]
85
+ existing = [key for key in target_keys if (extract_root / key).exists()]
86
+ if existing:
87
+ raise FileExistsError(
88
+ f"Refusing to overwrite existing extracted cache directories: {existing}"
89
+ )
90
+
91
+ started = time.perf_counter()
92
+ records = []
93
+ for name in logical_archives:
94
+ item_started = time.perf_counter()
95
+ path = archive_root / name
96
+ key = cache_key(name)
97
+ print(json.dumps({"event": "extract_start", "archive": name}), flush=True)
98
+ if name.endswith(".part-aa"):
99
+ part_ab = archive_root / name.removesuffix(".part-aa")
100
+ part_ab = part_ab.with_name(part_ab.name + ".part-ab")
101
+ cat_process = subprocess.Popen(
102
+ ["cat", str(path), str(part_ab)], stdout=subprocess.PIPE
103
+ )
104
+ if cat_process.stdout is None:
105
+ raise RuntimeError("Failed to open split-archive stream")
106
+ tar_result = subprocess.run(
107
+ tar_command(extract_root),
108
+ stdin=cat_process.stdout,
109
+ check=False,
110
+ )
111
+ cat_process.stdout.close()
112
+ cat_returncode = cat_process.wait()
113
+ if tar_result.returncode or cat_returncode:
114
+ raise RuntimeError(
115
+ f"Split extraction failed: tar={tar_result.returncode}, "
116
+ f"cat={cat_returncode}"
117
+ )
118
+ else:
119
+ subprocess.run(tar_command(extract_root, path), check=True)
120
+
121
+ target = extract_root / key
122
+ if not target.is_dir():
123
+ raise RuntimeError(
124
+ f"Archive did not create its expected cache root: {target}"
125
+ )
126
+ record = {
127
+ "archive": name,
128
+ "cache_key": key,
129
+ "seconds": time.perf_counter() - item_started,
130
+ }
131
+ records.append(record)
132
+ print(json.dumps({"event": "extract_complete", **record}), flush=True)
133
+
134
+ result = {
135
+ "status": "pass",
136
+ "created_at": datetime.now().astimezone().isoformat(),
137
+ "archive_root": str(archive_root),
138
+ "extract_root": str(extract_root),
139
+ "physical_archive_files": len(EXPECTED_ARCHIVES),
140
+ "logical_cache_directories": len(target_keys),
141
+ "total_seconds": time.perf_counter() - started,
142
+ "records": records,
143
+ }
144
+ args.output.parent.mkdir(parents=True, exist_ok=True)
145
+ args.output.write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8")
146
+ print(json.dumps({"event": "summary", **result}), flush=True)
147
+
148
+
149
+ if __name__ == "__main__":
150
+ main()
scripts/package_private_derived_metadata.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Create portable copies of locally derived manifests and reports."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import shutil
9
+ from pathlib import Path
10
+
11
+
12
+ ACTION_MANIFESTS = {
13
+ "autoeval_full.jsonl": "autoeval",
14
+ "libero_full.jsonl": "libero_success",
15
+ "roboarena_full_refined.jsonl": "roboarena",
16
+ "racer_pilot.jsonl": "racer_pilot",
17
+ }
18
+ ACTION_REPORTS = (
19
+ "summary.json",
20
+ "autoeval_full_validation.json",
21
+ "libero_full_validation.json",
22
+ "roboarena_full_refined_validation.json",
23
+ "racer_pilot_validation.json",
24
+ )
25
+
26
+
27
+ def portable(value, experiment_root: Path):
28
+ if isinstance(value, dict):
29
+ return {key: portable(item, experiment_root) for key, item in value.items()}
30
+ if isinstance(value, list):
31
+ return [portable(item, experiment_root) for item in value]
32
+ if not isinstance(value, str):
33
+ return value
34
+ if "/action_labels/stage2_action_sidecar_v1/" in value:
35
+ return "action_sidecars/" + value.split("/action_labels/stage2_action_sidecar_v1/", 1)[1]
36
+ racer_marker = "/artifacts/action_recovery_v1/racer_pilot/"
37
+ if racer_marker in value:
38
+ return "action_sidecars/racer_pilot/" + value.split(racer_marker, 1)[1]
39
+ if "/action_sources/" in value:
40
+ return "upstream_raw/" + value.split("/action_sources/", 1)[1]
41
+ root_text = str(experiment_root.resolve()) + "/"
42
+ if value.startswith(root_text):
43
+ return value[len(root_text):]
44
+ return value
45
+
46
+
47
+ def rewrite_json(source: Path, target: Path, experiment_root: Path) -> None:
48
+ payload = portable(json.loads(source.read_text()), experiment_root)
49
+ target.parent.mkdir(parents=True, exist_ok=True)
50
+ target.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n")
51
+
52
+
53
+ def rewrite_jsonl(source: Path, target: Path, experiment_root: Path, source_name: str) -> None:
54
+ target.parent.mkdir(parents=True, exist_ok=True)
55
+ output = []
56
+ for line in source.read_text().splitlines():
57
+ if not line:
58
+ continue
59
+ row = portable(json.loads(line), experiment_root)
60
+ if "sidecar_path" in row:
61
+ row["sidecar_path"] = f"action_sidecars/{source_name}/trajectory_{row['stage2_trajectory_id']}.npz"
62
+ output.append(json.dumps(row, sort_keys=True) + "\n")
63
+ target.write_text("".join(output))
64
+
65
+
66
+ def main() -> None:
67
+ parser = argparse.ArgumentParser()
68
+ parser.add_argument("--experiment-root", type=Path, required=True)
69
+ parser.add_argument("--dataset-metadata-root", type=Path, required=True)
70
+ parser.add_argument("--output-root", type=Path, required=True)
71
+ args = parser.parse_args()
72
+ experiment = args.experiment_root.resolve()
73
+ output = args.output_root.resolve()
74
+
75
+ manifests = experiment / "manifests"
76
+ shutil.copy2(manifests / "phase2_remediation_pairs_v1.jsonl", output / "manifests/phase2_remediation_pairs_v1.jsonl")
77
+ rewrite_json(manifests / "phase2_remediation_pairs_v1_summary.json", output / "manifests/phase2_remediation_pairs_v1_summary.json", experiment)
78
+ action_source = manifests / "action_recovery_v1"
79
+ for name, source_name in ACTION_MANIFESTS.items():
80
+ rewrite_jsonl(action_source / name, output / "derived/action_manifests" / name, experiment, source_name)
81
+ report_source = experiment / "reports/action_recovery_v1"
82
+ for name in ACTION_REPORTS:
83
+ rewrite_json(report_source / name, output / "derived/action_reports" / name, experiment)
84
+
85
+ inventory_source = args.dataset_metadata_root / "phase21a_data_inventory.json"
86
+ inventory = json.loads(inventory_source.read_text())
87
+ inventory["manifest"] = "manifests/phase2_remediation_pairs_v1.jsonl"
88
+ inventory["output_dir"] = "."
89
+ (output / "manifests/stage2_subset_inventory.json").write_text(
90
+ json.dumps(inventory, indent=2, sort_keys=True) + "\n"
91
+ )
92
+ shutil.copy2(args.dataset_metadata_root / "SHA256SUMS", output / "manifests/stage2_subset_SHA256SUMS")
93
+ print(json.dumps({"status": "complete", "output_root": str(output)}, indent=2))
94
+
95
+
96
+ if __name__ == "__main__":
97
+ main()
scripts/verify_stage2_links.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Verify that frozen pair/action manifests resolve against reconstructed data."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import hashlib
8
+ import json
9
+ from pathlib import Path
10
+
11
+
12
+ def digest(path: Path) -> str:
13
+ result = hashlib.sha256()
14
+ with path.open("rb") as stream:
15
+ for block in iter(lambda: stream.read(8 * 1024 * 1024), b""):
16
+ result.update(block)
17
+ return result.hexdigest()
18
+
19
+
20
+ def main() -> None:
21
+ parser = argparse.ArgumentParser()
22
+ parser.add_argument("--manifest", type=Path, required=True)
23
+ parser.add_argument("--processed-root", type=Path, required=True)
24
+ parser.add_argument("--checksums", type=Path)
25
+ parser.add_argument("--action-manifest-dir", type=Path)
26
+ parser.add_argument("--derived-root", type=Path)
27
+ args = parser.parse_args()
28
+
29
+ rows = [json.loads(line) for line in args.manifest.read_text().splitlines() if line]
30
+ references: set[Path] = set()
31
+ for row in rows:
32
+ for role in ("chosen", "rejected"):
33
+ relative = Path(str(row[role]["source_frame_file"]))
34
+ parts = relative.parts[1:] if relative.parts[:1] in ((".",), ("processed_datasets",)) else relative.parts
35
+ if relative.parts[:1] == (".",) and parts[:1] == ("processed_datasets",):
36
+ parts = parts[1:]
37
+ references.add(Path(*parts))
38
+ missing = [str(path) for path in sorted(references) if not (args.processed_root / path).is_file()]
39
+ if missing:
40
+ raise FileNotFoundError(f"missing {len(missing)} manifest frame files; examples={missing[:10]}")
41
+ if len(rows) != 2689 or len(references) != 4323:
42
+ raise RuntimeError(f"unexpected frozen counts: rows={len(rows)} files={len(references)}")
43
+
44
+ checksum_count = 0
45
+ if args.checksums:
46
+ for line in args.checksums.read_text().splitlines():
47
+ expected, relative = line.split(maxsplit=1)
48
+ relative_path = Path(relative.strip())
49
+ parts = relative_path.parts[1:] if relative_path.parts[:1] == ("processed_datasets",) else relative_path.parts
50
+ target = args.processed_root / Path(*parts)
51
+ if digest(target) != expected:
52
+ raise RuntimeError(f"SHA256 mismatch: {target}")
53
+ checksum_count += 1
54
+
55
+ action_rows = action_files = 0
56
+ if args.action_manifest_dir or args.derived_root:
57
+ if not (args.action_manifest_dir and args.derived_root):
58
+ raise ValueError("action-manifest-dir and derived-root must be supplied together")
59
+ for manifest in sorted(args.action_manifest_dir.glob("*.jsonl")):
60
+ for line in manifest.read_text().splitlines():
61
+ row = json.loads(line)
62
+ action_rows += 1
63
+ if "sidecar_path" not in row:
64
+ continue
65
+ target = args.derived_root / row["sidecar_path"]
66
+ if not target.is_file():
67
+ raise FileNotFoundError(target)
68
+ action_files += 1
69
+
70
+ print(json.dumps({
71
+ "status": "pass",
72
+ "pair_rows": len(rows),
73
+ "unique_stage2_frame_files": len(references),
74
+ "sha256_files_verified": checksum_count,
75
+ "action_manifest_rows": action_rows,
76
+ "action_sidecar_files_resolved": action_files,
77
+ }, indent=2))
78
+
79
+
80
+ if __name__ == "__main__":
81
+ main()