Cion-lab commited on
Commit
b2ba2a9
Β·
verified Β·
1 Parent(s): 8fcd1c4

mirror ops/ so the kept code is self-contained

Browse files
Files changed (2) hide show
  1. ops/SESSION_LOOP.md +117 -0
  2. ops/watch_ckpt.sh +38 -0
ops/SESSION_LOOP.md ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SESSION_LOOP β€” unattended Phase 4 session turnover
2
+
3
+ You are a fresh agent session, probably at an odd hour, with no conversation history. Your only job is to
4
+ advance the ounce100m main training run by **one** step of this loop. Do nothing else. Read
5
+ `memory/STATE.md` first; it overrides this file if they disagree.
6
+
7
+ **Standing instruction from the user (2026-09-20T14:02Z):** run the sleep β†’ wake β†’ check β†’ launch loop across
8
+ all remaining sessions and do not start any other work unless it is an emergency as defined in Β§5.
9
+
10
+ ## 1. Check (always do this, ~30 s, no GPU)
11
+
12
+ ```
13
+ curl -s "https://huggingface.co/api/datasets/Cion-lab/ounce100m-ckpt/commits/main"
14
+ curl -sL "https://huggingface.co/datasets/Cion-lab/ounce100m-ckpt/resolve/main/latest.json"
15
+ curl -sL "https://huggingface.co/datasets/Cion-lab/ounce100m-ckpt/resolve/main/ckpt/checkpoint-<step>/cursor.json"
16
+ curl -sL "https://huggingface.co/datasets/Cion-lab/ounce100m-ckpt/resolve/main/ckpt/checkpoint-<step>/trainer_state.json"
17
+ ```
18
+
19
+ Pass criteria, all of them:
20
+
21
+ | Check | Expected |
22
+ |---|---|
23
+ | head commit | `latest -> N`, and `ckpt/checkpoint-N` exists 7–10 s earlier |
24
+ | `latest.json.step` | equals `N`, and `path_in_repo` is `ckpt/checkpoint-N` |
25
+ | `cursor.json.tokens_consumed` | exactly `N Γ— 262,144` |
26
+ | `cursor.json.samples_consumed` | exactly `N Γ— 256` |
27
+ | `dataset_files_sha` / `shuffle_perm_sha` | `53df4708526da5c8` / `c6f617b96f502d96` β€” **unchanged** |
28
+ | `trainer_state.json` | `global_step == N`, `max_steps == 3814`, `save_steps == 127`, loss lower than the previous checkpoint |
29
+
30
+ Also read the live quota (`get_accelerator_quota` β†’ `gpu_quota.time_used`, `total_time_allowed`) and the session
31
+ status for `dodosoomro/ounce100m-p4-sessionK`.
32
+
33
+ ## 2. Decide which of the three states you are in
34
+
35
+ - **A session is still running** and the pointer is advancing on the 127 grid β†’ nothing to do. Report the step
36
+ and stop. Do not launch anything.
37
+ - **A session ended and `latest -> 762 Γ— k`** for k = 1..4, k < 5 β†’ launch session k+1 (Β§3).
38
+ - **`latest -> 3814`** β†’ the run is finished (Β§4).
39
+
40
+ Session grid: S1 0β†’762, S2 β†’1,524, S3 β†’2,286, S4 β†’3,048, S5 β†’3,814. A session that stopped short of its
41
+ boundary (platform kill) is **not** an emergency β€” the next session resumes from wherever `latest` points,
42
+ because `phase4_session.py` plans from the pointer. Launch the next session with the *remaining* step count it
43
+ would need; if the planner's own arithmetic disagrees, that is an emergency (Β§5).
44
+
45
+ ## 3. Launch the next session
46
+
47
+ **The one editable line.** `code/kernels/phase4_bootstrap.py` is the whole kernel body; it pins
48
+ `REV = "c237b478076f68da43dabd3403daa5639286899e"` and `LAUNCHER_SHA = "5fb14bc3…"` and fetches
49
+ `kernels/phase4_session.py` at that REV, sha256-asserting it. **Only line 13 changes per session:**
50
+ `os.environ["QUOTA_LEFT_HOURS"] = "<live hours from the Β§1 read>"`. Nothing else β€” it resumes from
51
+ `latest.json` and needs no other input.
52
+
53
+ 1. **Book the ledger row first** (`memory/QUOTA.md`, next row number, before the job starts). Β§8 forbids an
54
+ unbooked GPU job. State the live hours remaining and the CPU-alternative check (Β§3.7: there is none β€” the
55
+ quantity is 762 steps of real T4 training).
56
+ 2. **Confirm session K has actually exited** before launching K+1 β€” two concurrent GPU sessions would
57
+ double-bill and the second hits the stale-stop guard. Use `get_notebook_session_status`, not the Hub
58
+ pointer, as the liveness answer (`time_reserved` in the quota read is always `0s` and means nothing).
59
+ 3. Submit with `mcp__kaggle__save_notebook`, `kernelExecutionType: "SaveAndRunAll"` (this creates *and* runs β€”
60
+ there is no separate run call; `create_notebook_session` takes only a slug and a machine shape, so it is not
61
+ how a script is uploaded). Send the **full verified envelope** every time; a missing `language` fails with a
62
+ message-less error (E-020):
63
+
64
+ ```
65
+ slug = "dodosoomro/ounce100m-p4-sessionK"
66
+ text = <contents of code/kernels/phase4_bootstrap.py, line 13 updated>
67
+ language = "python"
68
+ kernelType = "script"
69
+ machineShape = "GPU" # + enableGpu: true β‡’ 2Γ—T4. Do not invent a T4-specific shape string.
70
+ kernelExecutionType = "SaveAndRunAll"
71
+ enableGpu = true
72
+ isPrivate = true
73
+ enableInternet = true
74
+ sessionTimeoutSeconds = 25200
75
+ ```
76
+
77
+ `newTitle` is **required for a kernel that does not exist yet** β€” session 2 was refused with
78
+ "New kernels must have a title specified" until it was sent. For a new kernel set it **equal to the slug
79
+ suffix** so the returned `ref` is the slug you asked for; for an **existing** kernel never send a title that
80
+ differs from its current suffix, because `newTitle` rewrites the slug (E-020) and breaks every reference.
81
+ Always poll the returned `ref`, never the requested slug.
82
+ 4. **Poll the returned slug, never the requested one**, and record slug + version + kernel id + submission
83
+ time in `ASSETS.md`. Expect ~60-90 s of queue and boot before anything happens; don't poll sooner than 60 s.
84
+ Note that `get_notebook_info` may be denied by API scope β€” **liveness comes from the quota delta**: read
85
+ `get_accelerator_quota` twice a few minutes apart and see whether `time_used` is advancing (it is, at 1Γ—
86
+ wall clock, from the moment the container starts).
87
+ 5. Confirm within ~3 minutes that it did **not** exit fast. An exit inside ~2 min is a `REFUSED_TO_START`
88
+ verdict (free space / pointer read / manifest arithmetic) β€” read the log, and treat it as Β§5 only if the
89
+ reason is not self-evidently transient.
90
+ 6. Do **not** babysit it. Write "next check at <time>" into `STATE.md` and stop, or arm one long-lived waiter
91
+ (`watch_ckpt.sh <boundary_step> <seconds>`, or a read-only watcher agent for a whole session leg).
92
+
93
+
94
+ ## 4. When `latest -> 3814`
95
+
96
+ 1. Verify all six final checkpoints and `final/` exist and are byte-verified (compare oids against the local
97
+ manifest the run wrote).
98
+ 2. Run **Phase 5 on CPU** (`code/build/publish_model.py`) β€” 0 GPU hours. Gate 5's clean-room check must pop
99
+ `HF_TOKEN`, not just pass `token=False` (E-045/E-046).
100
+ 3. Then Phase 6 per `docs/05-eval-plan.md`, tasks in constitution order, incrementally saved, smoke `--limit 5`
101
+ first, installed **with** deps. Spend whatever GPU hours remain this week; the rest waits for the reset
102
+ (D-019). **Never publish a partial eight-task table as a result.**
103
+ 4. Fill the four PENDING blocks in `docs/final-report.md`, set `STATE.md` to COMPLETE, and stop. Do not start
104
+ new work after that.
105
+
106
+ ## 5. Emergencies β€” the only reasons to do more than the above
107
+
108
+ - The pointer **moved backwards**, or a cursor hash changed, or `tokens != step Γ— 262,144`. Stop everything;
109
+ this is data corruption. Do not launch another session. Write the evidence into `ERRORS.md` and `STATE.md`
110
+ as a blocker and surface it to the user.
111
+ - Two consecutive launches that exit inside ~2 min for the same reason.
112
+ - Quota cannot fund a full remaining session. Then **park**: do not change configuration to fit (Β§8). Write the
113
+ resume step, the reset instant (2026-09-26T00:00Z, a Saturday) and the exact next command into `STATE.md`.
114
+ - Loss discontinuity beyond noise at a checkpoint boundary, or grad-norm moving with it.
115
+
116
+ Anything else is not an emergency. Refactoring, "improving throughput", re-auditing settled decisions, and
117
+ re-running completed probes are all explicitly out of scope for these turns.
ops/watch_ckpt.sh ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # watch_ckpt.sh β€” print the run's checkpoint cadence, then wait for the NEXT one.
3
+ # Usage: watch_ckpt.sh <expected_step> <max_wait_seconds>
4
+ # Exits 0 early with "ARRIVED <step>" once commits/main shows "latest -> <expected_step>".
5
+ # Exits 0 with "TIMEOUT" if it does not arrive inside the window (that is the signal to investigate).
6
+ set -u
7
+ API="https://huggingface.co/api/datasets/Cion-lab/ounce100m-ckpt/commits/main"
8
+ want="${1:-508}"
9
+ max="${2:-540}"
10
+ deadline=$(( $(date -u +%s) + max ))
11
+ echo "now=$(date -u +%FT%TZ) waiting for latest -> ${want} (up to ${max}s)"
12
+ echo "--- commits so far ---"
13
+ curl -s "$API" | python -c "
14
+ import json,sys
15
+ for c in json.load(sys.stdin)[:14]:
16
+ print(' ', c['date'], '|', (c.get('title') or '').strip())
17
+ "
18
+ while :; do
19
+ head_line=$(curl -s "$API" | python -c "
20
+ import json,sys
21
+ try:
22
+ d=json.load(sys.stdin)
23
+ print(d[0]['date'], '|', (d[0].get('title') or '').strip())
24
+ except Exception as e:
25
+ print('READ_ERROR', e)
26
+ ")
27
+ case "$head_line" in
28
+ *"latest -> ${want}"*) echo "now=$(date -u +%FT%TZ) ARRIVED ${want} :: ${head_line}"; exit 0 ;;
29
+ esac
30
+ if echo "$head_line" | grep -q READ_ERROR; then
31
+ echo "now=$(date -u +%FT%TZ) READ_ERROR (transient; retrying): ${head_line}"
32
+ fi
33
+ if [ "$(date -u +%s)" -ge "$deadline" ]; then
34
+ echo "now=$(date -u +%FT%TZ) TIMEOUT latest->${want} not present. head=${head_line}"
35
+ exit 0
36
+ fi
37
+ sleep 45
38
+ done