Cion-lab commited on
Commit
840f0b2
·
verified ·
1 Parent(s): 7fd3601

rehearsal: grab_json returns a reason, manifest fallback, single-line VERDICT

Browse files
Files changed (1) hide show
  1. build/smoke_hub_resume.py +60 -11
build/smoke_hub_resume.py CHANGED
@@ -37,22 +37,42 @@ def sh(argv, label):
37
  print(" |", line[:220], flush=True)
38
  if p.returncode != 0:
39
  print(" STDERR:", (p.stderr or "")[-1500:], flush=True)
40
- return {"rc": p.returncode, "out": out[-6000:], "err": (p.stderr or "")[-1500:]}
 
41
 
42
 
43
  def grab_json(text, begin, end):
44
- if begin in text and end in text:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  try:
46
- return json.loads(text.split(begin, 1)[1].split(end, 1)[0])
47
- except Exception:
48
- return None
49
- return None
 
50
 
51
 
52
  def main():
53
  R = {"repo": REPO, "sources": TWO}
54
  base = ["build_mix.py", "--root", ROOT, "--only", TWO, "--cap-tokens-per-source", "1200000",
55
  "--hub-repo", REPO]
 
56
 
57
  # Start from an empty stage repo. v3 of this rehearsal failed and, by design, KEPT the repo as
58
  # evidence; without this the next run would restore those sources and skip the staging step it is
@@ -70,7 +90,10 @@ def main():
70
  R["preclean"] = preclean()
71
  shutil.rmtree(ROOT, ignore_errors=True)
72
  r1 = sh(base + ["--stage-only"], "1. stage two sources and publish")
73
- R["stage"] = {"rc": r1["rc"], "json": grab_json(r1["out"], "BUILD_JSON_BEGIN", "BUILD_JSON_END")}
 
 
 
74
 
75
  # the wipe IS the test: after this, nothing local survives except this script and the code
76
  shutil.rmtree(ROOT, ignore_errors=True)
@@ -78,17 +101,39 @@ def main():
78
  "stage_dir_exists": os.path.exists(os.path.join(ROOT, "stage"))}
79
 
80
  r2 = sh(base + ["--merge-only"], "2. cold resume: merge from the Hub with an empty local tree")
81
- R["merge"] = {"rc": r2["rc"], "json": grab_json(r2["out"], "BUILD_JSON_BEGIN", "BUILD_JSON_END")}
 
 
 
82
 
83
  r3 = sh(["verify_mix.py", "--root", ROOT, "--min-sources-per-shard", "2",
84
  "--sample-decodes", "3"], "3. verify the restored mix")
85
- R["verify"] = grab_json(r3["out"], "VERIFY_JSON_BEGIN", "VERIFY_JSON_END")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
- staged = (R["merge"].get("json") or {}).get("total_tokens", 0)
88
  R["COLD_RESUME_PASSED"] = bool(
89
  r1["rc"] == 0 and r2["rc"] == 0 and staged > 1_000_000
90
  and (R["verify"] or {}).get("PASS") is True
91
  and (R["verify"] or {}).get("distinct_sources_in_mix") == 2)
 
92
 
93
  # cleanup: the throwaway stage repo must not outlive the test, or a later real build could restore
94
  # capped 1.2M-token sources and believe they were complete
@@ -111,8 +156,12 @@ def main():
111
  R["cleanup"] = {"error": f"{type(e).__name__}: {str(e)[:200]}",
112
  "action_needed": f"delete the throwaway dataset {REPO} manually"}
113
 
 
 
 
 
114
  print("SMOKE_JSON_BEGIN")
115
- print(json.dumps(R, indent=1, default=str)[:6000])
116
  print("SMOKE_JSON_END")
117
 
118
 
 
37
  print(" |", line[:220], flush=True)
38
  if p.returncode != 0:
39
  print(" STDERR:", (p.stderr or "")[-1500:], flush=True)
40
+ # Keep enough of the tail that the JSON block can never be the thing that got truncated.
41
+ return {"rc": p.returncode, "out": out[-120000:], "err": (p.stderr or "")[-1500:]}
42
 
43
 
44
  def grab_json(text, begin, end):
45
+ """Pull the JSON object out of the LAST marker pair. Returns (obj, why_null).
46
+
47
+ The reason matters: v4 of this rehearsal reported COLD_RESUME_PASSED=false on a pipeline that had
48
+ actually worked, because one status line printed inside the block made json.loads fail and the
49
+ helper folded that into a bare None (E-019).
50
+ """
51
+ if begin not in text:
52
+ return None, "begin marker absent from captured stdout"
53
+ span = text.rsplit(begin, 1)[1]
54
+ if end not in span:
55
+ return None, "end marker absent -- stdout truncated mid-block"
56
+ body = span.split(end, 1)[0]
57
+ try:
58
+ return json.loads(body), None
59
+ except Exception as e:
60
+ strict = f"{type(e).__name__}: {str(e)[:120]}"
61
+ i = body.find("{")
62
+ if i >= 0:
63
  try:
64
+ obj = json.JSONDecoder().raw_decode(body[i:])[0]
65
+ return obj, f"lenient parse used (junk after the object): {strict}"
66
+ except Exception as e:
67
+ strict = f"lenient also failed {type(e).__name__}: {str(e)[:120]}"
68
+ return None, strict
69
 
70
 
71
  def main():
72
  R = {"repo": REPO, "sources": TWO}
73
  base = ["build_mix.py", "--root", ROOT, "--only", TWO, "--cap-tokens-per-source", "1200000",
74
  "--hub-repo", REPO]
75
+ notes = []
76
 
77
  # Start from an empty stage repo. v3 of this rehearsal failed and, by design, KEPT the repo as
78
  # evidence; without this the next run would restore those sources and skip the staging step it is
 
90
  R["preclean"] = preclean()
91
  shutil.rmtree(ROOT, ignore_errors=True)
92
  r1 = sh(base + ["--stage-only"], "1. stage two sources and publish")
93
+ sj, why = grab_json(r1["out"], "BUILD_JSON_BEGIN", "BUILD_JSON_END")
94
+ R["stage"] = {"rc": r1["rc"], "json": sj}
95
+ if why:
96
+ notes.append(f"stage json: {why}")
97
 
98
  # the wipe IS the test: after this, nothing local survives except this script and the code
99
  shutil.rmtree(ROOT, ignore_errors=True)
 
101
  "stage_dir_exists": os.path.exists(os.path.join(ROOT, "stage"))}
102
 
103
  r2 = sh(base + ["--merge-only"], "2. cold resume: merge from the Hub with an empty local tree")
104
+ mj, why = grab_json(r2["out"], "BUILD_JSON_BEGIN", "BUILD_JSON_END")
105
+ R["merge"] = {"rc": r2["rc"], "json": mj}
106
+ if why:
107
+ notes.append(f"merge json: {why}")
108
 
109
  r3 = sh(["verify_mix.py", "--root", ROOT, "--min-sources-per-shard", "2",
110
  "--sample-decodes", "3"], "3. verify the restored mix")
111
+ vj, why = grab_json(r3["out"], "VERIFY_JSON_BEGIN", "VERIFY_JSON_END")
112
+ R["verify"] = vj
113
+ if why:
114
+ notes.append(f"verify json: {why}")
115
+
116
+ # The manifest on disk is a second, independent source for the same number. If the stdout parse
117
+ # fails but the manifest is good, the pipeline still passes and the harness is what is broken --
118
+ # distinguishing those two outcomes is the whole point of recording `notes`.
119
+ mpath = os.path.join(ROOT, "manifest.json")
120
+ man = None
121
+ if os.path.exists(mpath):
122
+ try:
123
+ man = json.load(open(mpath))
124
+ except Exception as e:
125
+ notes.append(f"manifest unreadable: {type(e).__name__}: {str(e)[:120]}")
126
+ else:
127
+ notes.append(f"no manifest at {mpath}")
128
+ R["manifest_total_tokens"] = (man or {}).get("total_tokens")
129
+ R["manifest_n_shards"] = (man or {}).get("n_shards")
130
 
131
+ staged = (mj or {}).get("total_tokens") or (man or {}).get("total_tokens") or 0
132
  R["COLD_RESUME_PASSED"] = bool(
133
  r1["rc"] == 0 and r2["rc"] == 0 and staged > 1_000_000
134
  and (R["verify"] or {}).get("PASS") is True
135
  and (R["verify"] or {}).get("distinct_sources_in_mix") == 2)
136
+ R["notes"] = notes
137
 
138
  # cleanup: the throwaway stage repo must not outlive the test, or a later real build could restore
139
  # capped 1.2M-token sources and believe they were complete
 
156
  R["cleanup"] = {"error": f"{type(e).__name__}: {str(e)[:200]}",
157
  "action_needed": f"delete the throwaway dataset {REPO} manually"}
158
 
159
+ blob = json.dumps(R, default=str, sort_keys=True)
160
+ # A single-line verdict survives log truncation and cannot be misread the way a nested dict can.
161
+ print(f"VERDICT COLD_RESUME_PASSED={R['COLD_RESUME_PASSED']} staged={staged} "
162
+ f"cleanup={str(R['cleanup'])[:40]} notes={len(notes)}")
163
  print("SMOKE_JSON_BEGIN")
164
+ print(blob[:12000])
165
  print("SMOKE_JSON_END")
166
 
167