Browse files
scripts/publish_gate.py 595 lines · 25.9 KB · python
1
#!/usr/bin/env python3
2
"""Pre-publish gate: mechanical checks before any public table ships.
3
4
Run against the result files you intend to publish:
5
6
  python3 scripts/publish_gate.py results/latest.jsonl results/latest.mount.jsonl ...
7
8
Checks (fail = exit 1; manual items print as MANUAL and never fail the gate):
9
10
1. calibration     docs/token-calibration-factors.md exists and is committed —
11
                   published token deltas must cite calibrated factors, not
12
                   raw char/4 (README warns char/4 is biased for VCS output).
13
2. tuned-git       core-lane results include git_untracked_cache AND
14
                   git_fsmonitor subject rows. Stock git alone overstates oak
15
                   wins on wide trees.
16
3. transports      no row set mixes remote transports under one operation
17
                   name (remote.net.* vs remote.*); rows touching a remote
18
                   carry remote_transport.
19
4. levels          agent rows carry instruction_level and the file holds only
20
                   one level (never aggregate across levels).
21
5. nulls           null means unmeasured: summaries must not render null as 0.
22
                   (Spot-checked by scanning for '| 0 |' columns whose JSONL
23
                   value is null — heuristic, reported as MANUAL.)
24
6. skips           every returncode-77 row carries skip_reason (work items,
25
                   never silent absence); count is printed for the summary.
26
7. tails           rows with tail percentiles carry their sample counts
27
                   (tail_latency_summary embeds n; absence is a failure).
28
8. provenance      published Oak subject rows carry clean Oak source
29
                   provenance (hash present, status clean).
30
9. samples         public core rows carry enough repetitions per
31
                   subject/scenario/operation group (n>=30).
32
10. randomization  public core rows state whether subject order was randomized;
33
                   randomized rows carry the per-run subject order.
34
11. failures       public rows do not hide failed operations behind successful
35
                   averages.
36
12. tracks         each result file holds one benchmark_track.
37
13. env-isolation  public core rows carry one env isolation version so rows
38
                   measured before/after harness environment policy changes
39
                   cannot be compared silently.
40
14. conformance    inputs holding Oak rows also hold diagnostic conformance rows
41
                   (scripts/vcs_conformance.py --output) for every published Oak
42
                   binary; the Oak rows pass the conformance gate against
43
                   config/conformance_expected_failures.json (no regression, no
44
                   missing behaviour, no FIXED-but-still-listed entry, no
45
                   entry whose ticket is still pending:<slug>).
46
"""
47
48
from __future__ import annotations
49
50
import json
51
import sys
52
from pathlib import Path
53
54
from oakbench.integrity import content_integrity_public_trust_passed
55
from oakbench.public_output import output_evidence_failures, workflow_evidence_failures, workflow_qualification_failures
56
from oakbench.rows import row_returncode
57
58
ROOT = Path(__file__).resolve().parents[1]
59
CALIBRATION_DOC = ROOT / "docs" / "token-calibration-factors.md"
60
# Tuned subjects whose mode.setup.* rows must all succeed before any of their
61
# rows are publishable (a failed setup means stock git measured under a tuned
62
# label).
63
TUNED_GIT_SUBJECTS = {"git_untracked_cache", "git_fsmonitor", "git_lfs"}
64
# Tuned subjects every core publish must include. git_lfs is deliberately not
65
# required here: it only applies to the binary-fixture scenarios listed in
66
# config/git_modes.json and needs git-lfs installed, so its absence is an
67
# honest coverage gap (skip rows), while a present-but-failed lfs setup still
68
# fails the gate via TUNED_GIT_SUBJECTS above.
69
REQUIRED_TUNED_GIT_SUBJECTS = {"git_untracked_cache", "git_fsmonitor"}
70
CORE_PROFILES = {"smoke", "standard", "large", "micro"}
71
PUBLIC_CORE_PROFILES = {"standard", "large", "micro"}
72
PUBLIC_CORE_MIN_SAMPLES = 30
73
EXCLUDED_SAMPLE_OP_SUFFIXES = (".add", ".commit", ".determinism", ".inforecall")
74
EXCLUDED_SAMPLE_OP_PREFIXES = ("mode.setup",)
75
RANDOMIZATION_FIELDS = ("randomized_subject_order", "randomize_subject_order", "subject_order_randomized")
76
SUBJECT_ORDER_FIELDS = ("subject_order", "run_subject_order")
77
78
79
def load_rows(path: Path) -> list[dict]:
80
    rows = []
81
    for line in path.read_text().splitlines():
82
        line = line.strip()
83
        if line:
84
            rows.append(json.loads(line))
85
    return rows
86
87
88
def is_oak_subject(row: dict) -> bool:
89
    subject = str(row.get("subject", ""))
90
    if subject.startswith("oak"):
91
        return True
92
    if row.get("subject_kind") == "oak":
93
        return True
94
    details = row.get("subject_details")
95
    if isinstance(details, dict):
96
        subject_detail = details.get(subject)
97
        if isinstance(subject_detail, dict):
98
            return subject_detail.get("kind") == "oak" or str(
99
                subject_detail.get("role", "")
100
            ).startswith("oak_")
101
    return False
102
103
104
def source_status_is_clean(status: object) -> bool:
105
    if not isinstance(status, str):
106
        return False
107
    normalized = " ".join(status.strip().lower().split())
108
    return normalized in {
109
        "",
110
        "clean",
111
        "no changes",
112
        "nothing to commit",
113
        "nothing to commit, working tree clean",
114
    }
115
116
117
def randomization_value(row: dict) -> object:
118
    for field in RANDOMIZATION_FIELDS:
119
        if field in row:
120
            return row[field]
121
    return None
122
123
124
def subject_order(row: dict) -> object:
125
    for field in SUBJECT_ORDER_FIELDS:
126
        if field in row:
127
            return row[field]
128
    return None
129
130
131
def is_skip(row: dict) -> bool:
132
    return row_returncode(row) == 77 or bool(row.get("skipped"))
133
134
135
def is_excluded_sample_operation(operation: str) -> bool:
136
    return operation.endswith(EXCLUDED_SAMPLE_OP_SUFFIXES) or operation.startswith(
137
        EXCLUDED_SAMPLE_OP_PREFIXES
138
    )
139
140
141
def sample_run_id(row: dict, fallback: int) -> str:
142
    for field in ("run", "run_index"):
143
        value = row.get(field)
144
        if value is not None:
145
            return str(value)
146
    return f"row:{fallback}"
147
148
149
def oak_binary_identity(row: dict) -> str | None:
150
    """SHA-256 of the Oak binary that produced a row, from any lane's identity field."""
151
    for key in ("binary_sha256", "subject_binary_sha256", "workflow_subject_binary_sha256"):
152
        value = row.get(key)
153
        if isinstance(value, str) and len(value) == 64:
154
            return value
155
    details = row.get("subject_details")
156
    if isinstance(details, dict):
157
        item = details.get(str(row.get("subject")))
158
        if isinstance(item, dict) and isinstance(item.get("binary_sha256"), str) and len(item["binary_sha256"]) == 64:
159
            return item["binary_sha256"]
160
    return None
161
162
163
def conformance_gate_lines(all_rows: list[tuple[Path, dict]]) -> tuple[list[str], list[str]]:
164
    """Check 14: every published Oak binary passes the conformance gate on ITS OWN rows."""
165
    from oakbench import conformance_gate
166
    from oakbench.conformance import SCENARIOS
167
    from oakbench.conformance_matrix import BEHAVIOURS
168
    conformance_rows = [row for _, row in all_rows if row.get("evidence_class") == "diagnostic_conformance"]
169
    oak_rows = [(path, row) for path, row in all_rows
170
                if is_oak_subject(row) and row.get("evidence_class") != "diagnostic_conformance"]
171
    if not oak_rows:
172
        return [], ["PASS   conformance: no Oak rows among inputs"]
173
    anonymous = [(str(path), row.get("subject"), row.get("operation")) for path, row in oak_rows
174
                 if oak_binary_identity(row) is None]
175
    failures = []
176
    if anonymous:
177
        failures.append("FAIL   conformance: Oak rows lack binary identity (binary_sha256 or subject_details), so "
178
                        f"their conformance evidence cannot be matched: {anonymous[:5]}")
179
    published = sorted({oak_binary_identity(row) for _, row in oak_rows} - {None})
180
    if not conformance_rows:
181
        failures.append("FAIL   conformance: Oak rows published without diagnostic conformance rows; run "
182
                        "scripts/vcs_conformance.py --output <file> with the published Oak binary and pass it here")
183
        return failures, []
184
    try:
185
        expected = conformance_gate.load_expected()
186
    except (OSError, ValueError) as exc:
187
        return failures + [f"FAIL   conformance: expected-failures list unreadable: {exc}"], []
188
    pending = conformance_gate.pending_tickets(expected)
189
    if pending:
190
        # A pending:<slug> ticket is a placeholder while the bug is being filed;
191
        # publication needs every expected failure to cite a filed fb-N
192
        # (especially intermittent ones, whose passes are never FIXED).
193
        failures.append("FAIL   conformance: expected-failures list has unfiled pending: tickets; file them and "
194
                        f"cite fb-N before publishing: {[f'{b} ({t}, {o})' for b, t, o in pending][:5]}")
195
    required = list(SCENARIOS) + [behaviour.id for behaviour in BEHAVIOURS]
196
    notes = []
197
    for sha in published:
198
        # Only this binary's subject rows (plus reference rows) are evaluated:
199
        # rows of another Oak build can neither satisfy nor fail this one.
200
        rows = [row for row in conformance_rows
201
                if row.get("subject") != expected["subject"] or row.get("binary_sha256") == sha]
202
        result = conformance_gate.evaluate(rows, expected, required)
203
        if not result.get("profile_recorded"):
204
            failures.append(f"FAIL   conformance[{sha[:12]}]: filesystem profile {result['profiles'] or 'missing'} "
205
                            "has no recorded coverage in config/conformance_expected_failures.json; publication "
206
                            "requires a reviewed coverage record for the host profile")
207
        if result["verdict"] != "PASS":
208
            failures.append(f"FAIL   conformance[{sha[:12]}]: {result['verdict']}: "
209
                            f"{(result['regressions'] + result['unmeasured'])[:5]}")
210
        if result["fixed"]:
211
            failures.append(f"FAIL   conformance[{sha[:12]}]: expected-failures list is stale (now passing): "
212
                            f"{result['fixed'][:5]}")
213
        if result["verdict"] == "PASS" and not result["fixed"] and result.get("profile_recorded"):
214
            notes.append(f"PASS   [{sha[:12]}] " + conformance_gate.summary_lines(result)[0])
215
    return failures, ([] if failures else notes)
216
217
218
def main(paths: list[str]) -> int:
219
    failures: list[str] = []
220
    notes: list[str] = []
221
222
    if CALIBRATION_DOC.exists():
223
        notes.append(f"PASS   calibration: {CALIBRATION_DOC.name} present")
224
    else:
225
        failures.append(
226
            "FAIL   calibration: docs/token-calibration-factors.md missing — run "
227
            "token_calibration.py per output style before publishing token deltas"
228
        )
229
230
    all_rows: list[tuple[Path, dict]] = []
231
    for raw in paths:
232
        path = Path(raw)
233
        if not path.exists():
234
            failures.append(f"FAIL   missing result file: {path}")
235
            continue
236
        for row in load_rows(path):
237
            all_rows.append((path, row))
238
239
    core_rows = [row for _, row in all_rows if row.get("profile") in CORE_PROFILES]
240
    if core_rows:
241
        subjects = {
242
            str(row.get("subject"))
243
            for row in core_rows
244
            if row_returncode(row) == 0
245
            and not is_excluded_sample_operation(str(row.get("operation") or ""))
246
        }
247
        missing = REQUIRED_TUNED_GIT_SUBJECTS - subjects
248
        if missing:
249
            failures.append(
250
                f"FAIL   tuned-git: core rows lack {sorted(missing)} — rerun with "
251
                "--git-modes untracked_cache,fsmonitor (verify fsmonitor--daemon health on darwin)"
252
            )
253
        else:
254
            notes.append("PASS   tuned-git: untracked_cache and fsmonitor rows present")
255
256
        bad_tuned_setup = [
257
            (row.get("subject"), row.get("operation"), row.get("returncode"))
258
            for row in core_rows
259
            if str(row.get("subject")) in TUNED_GIT_SUBJECTS
260
            and str(row.get("operation") or "").startswith(EXCLUDED_SAMPLE_OP_PREFIXES)
261
            and row_returncode(row) != 0
262
        ]
263
        if bad_tuned_setup:
264
            failures.append(
265
                "FAIL   tuned-git: tuned Git setup failed, so tuned rows are not publishable: "
266
                f"{bad_tuned_setup[:5]}"
267
            )
268
    else:
269
        notes.append("MANUAL tuned-git: no core-lane rows among inputs; check the core table separately")
270
271
    # Scale lane (suites/scale): claimable only when the calibration campaign's
272
    # own JSONL is among the inputs (matched by content sha256) and every
273
    # number is RECOMPUTED from it with the P1 cell machinery; the record's
274
    # stated values are never trusted (oakbench.scale_calibration).
275
    scale_rows = [(str(path), row) for path, row in all_rows if row.get("profile") == "scale"]
276
    if scale_rows:
277
        from oakbench import scale_calibration
278
        inputs: dict = {}
279
        input_sha: dict = {}
280
        for path, row in all_rows:
281
            inputs.setdefault(str(path), []).append(row)
282
        for path in inputs:
283
            input_sha[path] = scale_calibration.file_sha256(Path(path))
284
        try:
285
            registry = json.loads((ROOT / "config" / "fixtures.json").read_text()).get("fixtures", {})
286
        except (OSError, ValueError):
287
            registry = {}
288
        refused = scale_calibration.gate(scale_rows, inputs, input_sha, registry)
289
        if refused:
290
            failures.append(
291
                f"FAIL   scale-calibration: {len(refused)} scale row(s) are not verified quiet-host calibrated "
292
                f"evidence: {refused[:5]}"
293
            )
294
        else:
295
            notes.append("PASS   scale-calibration: every scale row verified against its recomputed calibration campaign")
296
297
    oak_provenance_failures = []
298
    for path, row in all_rows:
299
        if not is_oak_subject(row) or row.get("evidence_class") == "diagnostic_conformance":
300
            continue  # conformance rows carry binary identity, checked by the conformance gate
301
        source = row.get("source")
302
        source = source if isinstance(source, dict) else {}
303
        oak_hash = source.get("oak_hash")
304
        oak_status = source.get("oak_status")
305
        if not oak_hash or not source_status_is_clean(oak_status):
306
            oak_provenance_failures.append(
307
                (str(path), row.get("subject"), row.get("operation"), oak_hash, oak_status)
308
            )
309
    if oak_provenance_failures:
310
        failures.append(
311
            "FAIL   provenance: published Oak rows lack clean Oak source provenance: "
312
            f"{oak_provenance_failures[:5]}"
313
        )
314
    elif any(is_oak_subject(row) for _, row in all_rows):
315
        notes.append("PASS   provenance: Oak subject rows carry clean source hash/status")
316
317
    fake_provider_rows = [
318
        (str(path), row.get("platform"), row.get("driver"), row.get("scenario"), row.get("operation"))
319
        for path, row in all_rows
320
        if row.get("driver") == "fake-provider" or row.get("branch_triage_provider") == "fake"
321
    ]
322
    if fake_provider_rows:
323
        failures.append(
324
            "FAIL   fake-provider: simulated provider rows are not publishable: "
325
            f"{fake_provider_rows[:5]}"
326
        )
327
328
    public_core_rows = [
329
        (path, row)
330
        for path, row in all_rows
331
        if row.get("profile") in PUBLIC_CORE_PROFILES and not is_skip(row)
332
    ]
333
    public_failures = [
334
        (str(path), row.get("subject"), row.get("scenario"), row.get("operation"), row.get("returncode"))
335
        for path, row in all_rows
336
        if row.get("profile") in PUBLIC_CORE_PROFILES
337
        and not is_skip(row)
338
        and row_returncode(row) != 0
339
    ]
340
    if public_failures:
341
        failures.append(
342
            "FAIL   failures: public core rows contain failed operations: "
343
            f"{public_failures[:5]}"
344
        )
345
346
    workflow_evidence = workflow_evidence_failures([row for _, row in all_rows])
347
    workflow_evidence.extend(workflow_qualification_failures([row for _, row in all_rows], PUBLIC_CORE_MIN_SAMPLES))
348
    if workflow_evidence:
349
        failures.append("FAIL   workflow-evidence: " + "; ".join(workflow_evidence[:5]))
350
351
    unsupported_output = [
352
        (str(path), row.get("subject"), row.get("scenario"), row.get("operation"), reasons)
353
        for path, row in public_core_rows
354
        for reasons in [output_evidence_failures(row)]
355
        if reasons
356
    ]
357
    if unsupported_output:
358
        failures.append(
359
            "FAIL   output-evidence: public output usefulness claims lack exact evidence: "
360
            f"{unsupported_output[:5]}"
361
        )
362
363
    weak_content_trust = [
364
        (
365
            str(path),
366
            row.get("subject"),
367
            row.get("scenario"),
368
            row.get("operation"),
369
            row.get("content_integrity_source"),
370
            row.get("content_integrity_sources"),
371
        )
372
        for path, row in public_core_rows
373
        if row.get("content_integrity_check_passed") is True
374
        and not content_integrity_public_trust_passed(row)
375
    ]
376
    if weak_content_trust:
377
        failures.append(
378
            "FAIL   content-trust: public core rows claim passing content integrity "
379
            "from weak or mixed sources: "
380
            f"{weak_content_trust[:5]}"
381
        )
382
    elif any(row.get("content_integrity_check_passed") is True for _, row in public_core_rows):
383
        notes.append("PASS   content-trust: passing public content checks use strong sources")
384
385
    env_versions = {
386
        str(row.get("env_isolation_version"))
387
        for _, row in public_core_rows
388
        if isinstance(row.get("env_isolation_version"), str)
389
        and str(row.get("env_isolation_version")).strip()
390
    }
391
    missing_env_version = [
392
        (
393
            str(path),
394
            row.get("subject"),
395
            row.get("scenario"),
396
            row.get("operation"),
397
            row.get("run", row.get("run_index")),
398
        )
399
        for path, row in public_core_rows
400
        if not isinstance(row.get("env_isolation_version"), str)
401
        or not str(row.get("env_isolation_version")).strip()
402
    ]
403
    if missing_env_version:
404
        failures.append(
405
            "FAIL   env-isolation: public core rows missing env_isolation_version: "
406
            f"{missing_env_version[:5]}"
407
        )
408
    elif len(env_versions) > 1:
409
        failures.append(
410
            "FAIL   env-isolation: public core rows mix env_isolation_version values: "
411
            f"{sorted(env_versions)}"
412
        )
413
    elif env_versions:
414
        notes.append(f"PASS   env-isolation: public core rows use version {next(iter(env_versions))}")
415
416
    measured_groups: dict[tuple[str, str, str, str, str, str], set[str]] = {}
417
    sample_groups: dict[tuple[str, str, str, str, str, str], set[str]] = {}
418
    for index, (path, row) in enumerate(public_core_rows):
419
        operation = str(row.get("operation") or "")
420
        if is_excluded_sample_operation(operation):
421
            continue
422
        key = (
423
            str(path),
424
            str(row.get("profile")),
425
            str(row.get("benchmark_track", "")),
426
            str(row.get("scenario", "")),
427
            operation,
428
            str(row.get("subject", "")),
429
        )
430
        run_id = sample_run_id(row, index)
431
        measured_groups.setdefault(key, set()).add(run_id)
432
        if row_returncode(row) == 0:
433
            sample_groups.setdefault(key, set()).add(run_id)
434
    thin_groups = {
435
        "/".join(key[1:]): len(runs)
436
        for key, runs in measured_groups.items()
437
        if len(runs) < PUBLIC_CORE_MIN_SAMPLES
438
    }
439
    zero_success_groups = {
440
        "/".join(key[1:]): len(runs)
441
        for key, runs in measured_groups.items()
442
        if not sample_groups.get(key)
443
    }
444
    if thin_groups:
445
        failures.append(
446
            f"FAIL   samples: public core groups below n={PUBLIC_CORE_MIN_SAMPLES}: "
447
            f"{dict(list(thin_groups.items())[:5])}"
448
        )
449
    if zero_success_groups:
450
        failures.append(
451
            "FAIL   samples: public core groups with zero successful rows: "
452
            f"{dict(list(zero_success_groups.items())[:5])}"
453
        )
454
    if public_core_rows and not thin_groups and not zero_success_groups:
455
        notes.append(f"PASS   samples: public core groups have n>={PUBLIC_CORE_MIN_SAMPLES}")
456
457
    missing_randomization = [
458
        (
459
            str(path),
460
            row.get("subject"),
461
            row.get("scenario"),
462
            row.get("operation"),
463
            row.get("run", row.get("run_index")),
464
        )
465
        for path, row in public_core_rows
466
        if randomization_value(row) is None
467
    ]
468
    if missing_randomization:
469
        failures.append(
470
            "FAIL   randomization: public core rows missing randomization metadata: "
471
            f"{missing_randomization[:5]}"
472
        )
473
    else:
474
        not_randomized = [
475
            (
476
                str(path),
477
                row.get("subject"),
478
                row.get("scenario"),
479
                row.get("operation"),
480
                row.get("run", row.get("run_index")),
481
            )
482
            for path, row in public_core_rows
483
            if randomization_value(row) is not True
484
        ]
485
        randomized_without_order = []
486
        if not_randomized:
487
            failures.append(
488
                "FAIL   randomization: public core rows were not randomized: "
489
                f"{not_randomized[:5]}"
490
            )
491
        else:
492
            for path, row in public_core_rows:
493
                order = subject_order(row)
494
                if not isinstance(order, list) or not order or row.get("subject") not in order:
495
                    randomized_without_order.append(
496
                        (
497
                            str(path),
498
                            row.get("subject"),
499
                            row.get("scenario"),
500
                            row.get("operation"),
501
                            row.get("run", row.get("run_index")),
502
                        )
503
                    )
504
        if randomized_without_order:
505
            failures.append(
506
                "FAIL   randomization: randomized public core rows lack per-run subject order: "
507
                f"{randomized_without_order[:5]}"
508
            )
509
        elif public_core_rows:
510
            notes.append("PASS   randomization: public core rows state run-order metadata")
511
512
    tracks_by_file: dict[Path, set[str]] = {}
513
    for path, row in all_rows:
514
        track = row.get("benchmark_track")
515
        if track:
516
            tracks_by_file.setdefault(path, set()).add(str(track))
517
    mixed_tracks = {str(path): sorted(tracks) for path, tracks in tracks_by_file.items() if len(tracks) > 1}
518
    if mixed_tracks:
519
        failures.append(f"FAIL   tracks: files mix benchmark_track values: {mixed_tracks}")
520
    elif tracks_by_file:
521
        notes.append("PASS   tracks: each result file holds a single benchmark_track")
522
523
    # Transport hygiene: remote-touching rows must state their transport, and
524
    # one subject's operation must not mix transports. Side-by-side tables may
525
    # contain the same operation name for network and local_file subjects.
526
    missing_transport = [
527
        (str(path), row.get("subject"), row.get("operation"))
528
        for path, row in all_rows
529
        if (row.get("remote_repo") or row.get("remote_server"))
530
        and not (row.get("remote_transport") or row.get("workspace_transport"))
531
    ]
532
    if missing_transport:
533
        failures.append(f"FAIL   transports: remote rows without transport: {missing_transport[:5]}")
534
535
    op_transports: dict[tuple[str, str], set[str]] = {}
536
    for _, row in all_rows:
537
        transport = row.get("remote_transport") or row.get("workspace_transport")
538
        if transport:
539
            key = (str(row.get("subject")), str(row.get("operation")))
540
            op_transports.setdefault(key, set()).add(str(transport))
541
    mixed = {f"{subject} {op}": sorted(ts) for (subject, op), ts in op_transports.items() if len(ts) > 1}
542
    if mixed:
543
        failures.append(f"FAIL   transports: operations span multiple transports: {mixed}")
544
    elif op_transports:
545
        notes.append(f"PASS   transports: {len(op_transports)} remote-touching operations, one transport each")
546
547
    levels_by_file: dict[Path, set[str]] = {}
548
    for path, row in all_rows:
549
        level = row.get("instruction_level")
550
        if level is None and isinstance(row.get("agent"), dict):
551
            level = row["agent"].get("instruction_level")
552
        if level:
553
            levels_by_file.setdefault(path, set()).add(str(level))
554
    multi = {str(p): sorted(ls) for p, ls in levels_by_file.items() if len(ls) > 1}
555
    if multi:
556
        failures.append(f"FAIL   levels: files mix instruction levels (never aggregate): {multi}")
557
    elif levels_by_file:
558
        notes.append("PASS   levels: each agent result file holds a single instruction level")
559
560
    bad_skips = [
561
        (str(path), row.get("operation"))
562
        for path, row in all_rows
563
        if row_returncode(row) == 77 and not row.get("skip_reason")
564
    ]
565
    skip_count = sum(1 for _, row in all_rows if row_returncode(row) == 77)
566
    if bad_skips:
567
        failures.append(f"FAIL   skips: returncode-77 rows without skip_reason: {bad_skips[:5]}")
568
    else:
569
        notes.append(f"PASS   skips: {skip_count} skip rows, all carrying skip_reason (account for each in prose)")
570
571
    for path, row in all_rows:
572
        tail = (row.get("parallel_metrics") or {}).get("commit_latency_tail")
573
        if isinstance(tail, dict) and "samples" not in tail and "n" not in tail and "sample_count" not in tail:
574
            failures.append(f"FAIL   tails: {path.name} {row.get('operation')} tail summary lacks sample count")
575
            break
576
    else:
577
        notes.append("PASS   tails: tail summaries carry sample counts (or none present)")
578
579
    notes.append("MANUAL nulls: confirm summaries render null as 'unmeasured', never 0")
580
    notes.append("MANUAL prose: state transport asymmetries (oak network vs git local) next to every side-by-side")
581
582
    conformance_failures, conformance_notes = conformance_gate_lines(all_rows)
583
    failures += conformance_failures
584
    notes += conformance_notes
585
586
    for line in notes:
587
        print(line)
588
    for line in failures:
589
        print(line)
590
    print(f"\n{'GATE FAIL' if failures else 'GATE PASS'} ({len(failures)} failure(s), inputs: {len(paths)})")
591
    return 1 if failures else 0
592
593
594
if __name__ == "__main__":
595
    raise SystemExit(main(sys.argv[1:]))