betterwithage commited on
Commit
b3d6b17
·
verified ·
1 Parent(s): 5f36c96

nemotron(signed-corpus): add missing ingest/corpus/verify modules (race fix)

Browse files

Direct HF commit of the three modules that the prior commit raced with the GitHub->HF backend mirror. Dockerfile COPY already references them. ADDITIVE; honest SAMPLE corpus; CC BY 4.0 NVIDIA attribution.

Files changed (3) hide show
  1. szl_nemo_verify.py +116 -0
  2. szl_nemotron_corpus.py +406 -0
  3. szl_nemotron_ingest.py +365 -0
szl_nemo_verify.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ # © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11/v12
4
+ # Authored by the NEMOTRON SIGNED-TRAJECTORY build team. Co-Authored-By: Perplexity Computer Agent.
5
+ """
6
+ szl_nemo_verify — standalone verifier for the SZL-Nemo signed-trajectory corpus.
7
+
8
+ Anyone can run this against a downloaded corpus JSONL to independently check:
9
+ 1. CONTENT INTEGRITY — recompute each step's sha256 step_hash and compare.
10
+ 2. SIGNATURE — if a step carries a DSSE signature, verify it against the
11
+ published SZLHOLDINGS cosign public key (cosign.pub).
12
+
13
+ USAGE:
14
+ python szl_nemo_verify.py path/to/corpus.jsonl
15
+ cat corpus.jsonl | python szl_nemo_verify.py -
16
+
17
+ EXIT CODE: 0 if every present signature verifies AND every hash matches; else 1.
18
+
19
+ HONEST: when the corpus was emitted in an environment without the private signing
20
+ key, the receipts are UNSIGNED (signatures: []) — this verifier reports that
21
+ transparently and does NOT treat "unsigned" as a pass of the signature check. The
22
+ hash check still applies and proves content integrity / tamper-evidence.
23
+
24
+ Prefers the shipped szl_trajectory_sign + szl_dsse modules when importable (full
25
+ DSSE verification). Falls back to a self-contained hash-only check if they are not
26
+ on the path, so the script still runs standalone. NO network required.
27
+ """
28
+ from __future__ import annotations
29
+
30
+ import hashlib
31
+ import json
32
+ import sys
33
+
34
+
35
+ def _canon(obj) -> bytes:
36
+ return json.dumps(obj, sort_keys=True, separators=(",", ":"),
37
+ ensure_ascii=False).encode("utf-8")
38
+
39
+
40
+ def _step_hash(action, observation, restraint_verdict: str) -> str:
41
+ body = _canon({"action": action, "observation": observation,
42
+ "restraint_verdict": restraint_verdict})
43
+ return "sha256:" + hashlib.sha256(body).hexdigest()
44
+
45
+
46
+ def _verify_full(text: str):
47
+ """Full verification using the shipped modules (DSSE + hash)."""
48
+ import szl_trajectory_sign as sts # type: ignore
49
+ return sts.verify_jsonl(text)
50
+
51
+
52
+ def _verify_hash_only(text: str):
53
+ """Self-contained hash-only fallback (no DSSE module on path)."""
54
+ results = []
55
+ for ln in text.splitlines():
56
+ ln = ln.strip()
57
+ if not ln:
58
+ continue
59
+ try:
60
+ d = json.loads(ln)
61
+ except Exception as exc:
62
+ results.append({"parse_error": str(exc)})
63
+ continue
64
+ recomputed = _step_hash(d.get("action"), d.get("observation", ""),
65
+ d.get("restraint_verdict", "ALLOW"))
66
+ env = d.get("signature") or {}
67
+ sigs = env.get("signatures") or []
68
+ results.append({
69
+ "trajectory_id": d.get("trajectory_id"),
70
+ "step": d.get("step"),
71
+ "hash_ok": recomputed == d.get("step_hash"),
72
+ "signed": bool(sigs),
73
+ "sig_ok": False, # cannot DSSE-verify without the module
74
+ })
75
+ total = len(results)
76
+ hash_ok = sum(1 for r in results if r.get("hash_ok"))
77
+ signed = sum(1 for r in results if r.get("signed"))
78
+ return {
79
+ "total_steps": total, "hash_ok": hash_ok, "signed": signed, "sig_ok": 0,
80
+ "all_hash_ok": hash_ok == total and total > 0,
81
+ "all_sig_ok": False, "results": results,
82
+ "note": "hash-only fallback (szl_dsse not importable; signatures not checked)",
83
+ }
84
+
85
+
86
+ def main(argv) -> int:
87
+ if len(argv) < 2:
88
+ print(__doc__)
89
+ return 2
90
+ src = argv[1]
91
+ text = sys.stdin.read() if src == "-" else open(src, encoding="utf-8").read()
92
+ try:
93
+ res = _verify_full(text)
94
+ mode = "full (DSSE + hash)"
95
+ except Exception:
96
+ res = _verify_hash_only(text)
97
+ mode = "hash-only fallback"
98
+ summary = {k: res[k] for k in ("total_steps", "hash_ok", "signed", "sig_ok",
99
+ "all_hash_ok", "all_sig_ok") if k in res}
100
+ summary["verify_mode"] = mode
101
+ print(json.dumps(summary, indent=2))
102
+ # PASS iff every hash matches AND (no signatures present OR all verify).
103
+ hashes_ok = res.get("all_hash_ok", False)
104
+ sig_present = res.get("signed", 0) > 0
105
+ sigs_ok = res.get("sig_ok", 0) == res.get("signed", 0)
106
+ ok = hashes_ok and (not sig_present or sigs_ok)
107
+ print("RESULT:", "PASS" if ok else "FAIL")
108
+ if sig_present and not sigs_ok:
109
+ print(" (signatures present but not all verified)")
110
+ if not sig_present:
111
+ print(" (no signatures present — UNSIGNED corpus; hash integrity only)")
112
+ return 0 if ok else 1
113
+
114
+
115
+ if __name__ == "__main__":
116
+ sys.exit(main(sys.argv))
szl_nemotron_corpus.py ADDED
@@ -0,0 +1,406 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11/v12
3
+ # Authored by the NEMOTRON SIGNED-TRAJECTORY build team. Co-Authored-By: Perplexity Computer Agent.
4
+ """
5
+ szl_nemotron_corpus — served SIGNED-CORPUS tab + verify/stats endpoints for a11oy.
6
+
7
+ WHAT THIS SERVES (honest framing — read before extending):
8
+ A single, self-contained "Signed Corpus" surface that lets anyone:
9
+ 1. SEE sample DSSE-signed agent-trajectory receipts (one JSONL line per
10
+ agent step: action / observation / restraint_verdict / step_hash /
11
+ signature), mapped from nvidia/Nemotron-Agentic-v1 (CC BY 4.0, NVIDIA).
12
+ 2. RUN a signature/integrity check IN-BROWSER against any pasted JSONL,
13
+ calling POST /api/a11oy/v1/nemo/verify (server-side szl_dsse verify).
14
+ 3. READ honest corpus stats (counts, verdict/pattern mix, signing status).
15
+
16
+ Routes (all registered BEFORE the SPA catch-all so explicit paths win):
17
+ GET /signed-corpus -> premium HTML tab
18
+ GET /api/a11oy/v1/nemo/stats -> corpus stats JSON
19
+ GET /api/a11oy/v1/nemo/sample -> the sample signed JSONL (text)
20
+ POST /api/a11oy/v1/nemo/verify -> {jsonl} -> aggregate verify JSON
21
+
22
+ A small idempotent nav-injection middleware appends a floating "Signed Corpus"
23
+ link to every served HTML surface (so the tab is reachable from the console
24
+ without editing the React SPA). Additive, never rewrites page content.
25
+
26
+ HONEST LABELS (Doctrine gates — never weaken):
27
+ - "QLoRA-ready corpus; training = ROADMAP (needs 2x80GB GPU)."
28
+ - DATASET property, NOT a model claim. Not an Ultra reproduction. Not from
29
+ scratch. Trust is never 100%. Data labeled LIVE / SAMPLE / MODELED.
30
+ - CC BY 4.0 attribution to NVIDIA is shown on the page and in /stats.
31
+ - Real ECDSA-P256 signatures only when SZL_COSIGN_PRIVATE_KEY_PEM is present;
32
+ else honest UNSIGNED — the verifier reports this transparently.
33
+
34
+ ADDITIVE · FastAPI + szl_trajectory_sign + szl_nemotron_ingest · 0 runtime CDN.
35
+ """
36
+ from __future__ import annotations
37
+
38
+ import html as _html
39
+ import json
40
+ from typing import Any, Dict, Optional
41
+
42
+ from fastapi import FastAPI, Request
43
+ from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse
44
+
45
+ import szl_trajectory_sign as sts
46
+ import szl_nemotron_ingest as ingest
47
+
48
+ LEAN_SHA = "c7c0ba17"
49
+ DOCTRINE = {"version": "v11/v12", "counts": "749/14/163", "lambda": "Conjecture 1"}
50
+
51
+ # Build the SAMPLE corpus ONCE at import (CPU-only, deterministic content).
52
+ try:
53
+ _CORPUS = ingest.build_sample_corpus(label="SAMPLE")
54
+ except Exception as _exc: # never crash registration
55
+ _CORPUS = {"trajectories": [], "jsonl": "", "stats": {
56
+ "label": "SAMPLE", "trajectory_count": 0, "total_steps": 0,
57
+ "verdict_counts": {}, "pattern_counts": {},
58
+ "signing_available": False, "attribution": ingest.ATTRIBUTION,
59
+ "build_error": f"{type(_exc).__name__}: {_exc}"}}
60
+
61
+
62
+ def _stats() -> Dict[str, Any]:
63
+ st = dict(_CORPUS["stats"])
64
+ # Verify the shipped sample so /stats reports honest live integrity numbers.
65
+ v = sts.verify_jsonl(_CORPUS["jsonl"])
66
+ st["verify"] = {k: v[k] for k in
67
+ ("total_steps", "hash_ok", "signed", "sig_ok",
68
+ "all_hash_ok", "all_sig_ok")}
69
+ st["doctrine"] = DOCTRINE
70
+ st["step_schema"] = sts.STEP_SCHEMA
71
+ st["payload_type"] = sts.STEP_PAYLOAD_TYPE
72
+ st["source_total_samples"] = ingest.SOURCE_TOTAL
73
+ st["honesty"] = (
74
+ "QLoRA-ready signed-trajectory corpus (DATASET property, not a model claim). "
75
+ "Actual QLoRA/GRPO training = ROADMAP (needs 2x80GB GPU). Not an Ultra "
76
+ "reproduction; not trained from scratch. SAMPLE shown is a representative "
77
+ "schema-faithful mapping of nvidia/Nemotron-Agentic-v1 (CC BY 4.0, NVIDIA); "
78
+ "the full 335,122 samples are re-derivable locally from the open source."
79
+ )
80
+ return st
81
+
82
+
83
+ # --------------------------------------------------------------------------- #
84
+ # HTML tab
85
+ # --------------------------------------------------------------------------- #
86
+ def _sample_cards() -> str:
87
+ cards = []
88
+ for traj in _CORPUS["trajectories"]:
89
+ prov = traj["provenance"]
90
+ steps = traj["steps"]
91
+ rows = []
92
+ for s in steps:
93
+ act = s.get("action")
94
+ act_str = json.dumps(act) if not isinstance(act, str) else act
95
+ if len(act_str) > 140:
96
+ act_str = act_str[:140] + "…"
97
+ obs = s.get("observation") or ""
98
+ if len(obs) > 100:
99
+ obs = obs[:100] + "…"
100
+ verdict = s.get("restraint_verdict", "ALLOW")
101
+ vclass = {"ALLOW": "ok", "HOLD": "warn", "MONITOR": "exp",
102
+ "DECLINE": "bad"}.get(verdict, "exp")
103
+ corr = " ⟲ correction" if s.get("is_correction") else ""
104
+ rows.append(f"""
105
+ <tr>
106
+ <td class="num">{s.get('step')}</td>
107
+ <td><span class="pat">{_html.escape(s.get('pattern',''))}</span>{corr}</td>
108
+ <td class="role">{_html.escape(s.get('role',''))}</td>
109
+ <td class="act"><code>{_html.escape(act_str)}</code></td>
110
+ <td class="obs">{_html.escape(obs)}</td>
111
+ <td><span class="badge {vclass}">{_html.escape(verdict)}</span></td>
112
+ <td class="hash"><code>{_html.escape((s.get('step_hash') or '')[:18])}…</code></td>
113
+ </tr>""")
114
+ signed_badge = ('<span class="badge ok">SIGNED</span>'
115
+ if prov.get("all_signed")
116
+ else '<span class="badge warn">UNSIGNED (no key in env — honest)</span>')
117
+ cards.append(f"""
118
+ <article class="tcard">
119
+ <header>
120
+ <h3>trajectory {_html.escape(prov.get('trajectory_id','')[:8])}…</h3>
121
+ <span class="label">{_html.escape(prov.get('label','SAMPLE'))}</span>
122
+ {signed_badge}
123
+ </header>
124
+ <p class="task">📋 {_html.escape(str(prov.get('task',''))[:160])}</p>
125
+ <p class="meta">source: <b>{_html.escape(prov.get('source',''))}</b> ·
126
+ steps: {prov.get('total_steps')} · corrections: {prov.get('corrections')} ·
127
+ reasoning: {_html.escape(str(prov.get('reasoning_mode','')))} ·
128
+ used_in: {_html.escape(json.dumps(prov.get('used_in',[])))}</p>
129
+ <table class="steps">
130
+ <thead><tr><th>#</th><th>pattern</th><th>role</th><th>action</th>
131
+ <th>observation</th><th>verdict</th><th>step_hash</th></tr></thead>
132
+ <tbody>{''.join(rows)}</tbody>
133
+ </table>
134
+ </article>""")
135
+ return "\n".join(cards)
136
+
137
+
138
+ def _page_html(ns: str = "a11oy") -> str:
139
+ st = _stats()
140
+ attr = st["attribution"]
141
+ vc = st.get("verdict_counts", {})
142
+ pc = st.get("pattern_counts", {})
143
+ verify = st.get("verify", {})
144
+ sample_jsonl = _CORPUS["jsonl"]
145
+ chips = "".join(
146
+ f'<span class="chip">{_html.escape(k)}: <b>{v}</b></span>'
147
+ for k, v in {**vc, **{f"pat:{p}": n for p, n in pc.items()}}.items())
148
+ return f"""<!doctype html>
149
+ <html lang="en"><head>
150
+ <meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/>
151
+ <title>A11oy — Signed Corpus (SZL-Nemo)</title>
152
+ <style>
153
+ :root {{ --bg:#0a0f1e; --panel:#111a2e; --ink:#e8eef7; --muted:#8aa0bd;
154
+ --indigo:#4d8fcc; --terra:#c8643c; --gold:#d8a23c; --ok:#3fae7a;
155
+ --warn:#c8893c; --bad:#cc5a5a; --exp:#9fb0e6; }}
156
+ * {{ box-sizing:border-box; }}
157
+ body {{ margin:0; font-family:ui-sans-serif,system-ui,Segoe UI,Roboto,sans-serif;
158
+ background:radial-gradient(1200px 600px at 70% -10%, #16223c, var(--bg)); color:var(--ink); }}
159
+ .wrap {{ max-width:1180px; margin:0 auto; padding:2.5rem 1.25rem 4rem; }}
160
+ .plaque {{ font-family:ui-monospace,monospace; font-size:.72rem; letter-spacing:.12em;
161
+ color:var(--muted); text-transform:uppercase; }}
162
+ .plaque b {{ color:var(--gold); }}
163
+ h1 {{ font-size:clamp(1.8rem,4vw,2.6rem); margin:.4rem 0 .2rem; }}
164
+ h1 .accent {{ color:var(--terra); }}
165
+ .sub {{ color:var(--muted); max-width:74ch; line-height:1.55; }}
166
+ .honest {{ background:rgba(200,137,60,.10); border:1px solid rgba(200,137,60,.35);
167
+ border-radius:10px; padding:.8rem 1rem; margin:1.1rem 0; color:#e7c98f;
168
+ font-size:.85rem; line-height:1.5; }}
169
+ .attr {{ background:rgba(77,143,204,.08); border:1px solid rgba(77,143,204,.3);
170
+ border-radius:10px; padding:.7rem 1rem; margin:.8rem 0; font-size:.8rem; color:#bcd; }}
171
+ .attr a {{ color:var(--indigo); }}
172
+ .chips {{ display:flex; flex-wrap:wrap; gap:.45rem; margin:1rem 0; }}
173
+ .chip {{ background:var(--panel); border:1px solid #21304d; border-radius:999px;
174
+ padding:.3rem .7rem; font-size:.74rem; color:var(--muted); }}
175
+ .chip b {{ color:var(--ink); }}
176
+ .bignum {{ display:flex; gap:1.4rem; flex-wrap:wrap; margin:1.2rem 0; }}
177
+ .bignum .n {{ font-size:2rem; font-weight:800; color:var(--gold); line-height:1; }}
178
+ .bignum .l {{ font-size:.72rem; color:var(--muted); text-transform:uppercase; letter-spacing:.08em; }}
179
+ .tcard {{ background:var(--panel); border:1px solid #21304d; border-radius:12px;
180
+ padding:1.1rem 1.15rem; margin:1rem 0; box-shadow:0 18px 40px -28px #000; }}
181
+ .tcard header {{ display:flex; align-items:center; gap:.6rem; flex-wrap:wrap; }}
182
+ .tcard h3 {{ margin:0; font-family:ui-monospace,monospace; color:var(--indigo); font-size:1rem; }}
183
+ .label {{ font-size:.62rem; padding:.18rem .5rem; border-radius:999px; background:rgba(216,162,60,.16);
184
+ color:var(--gold); border:1px solid rgba(216,162,60,.4); letter-spacing:.08em; }}
185
+ .task {{ color:var(--ink); font-size:.86rem; margin:.6rem 0 .2rem; }}
186
+ .meta {{ color:var(--muted); font-size:.76rem; margin:.1rem 0 .7rem; }}
187
+ table.steps {{ width:100%; border-collapse:collapse; font-size:.74rem; }}
188
+ table.steps th {{ text-align:left; color:var(--muted); font-weight:600; border-bottom:1px solid #21304d;
189
+ padding:.3rem .4rem; text-transform:uppercase; font-size:.64rem; letter-spacing:.06em; }}
190
+ table.steps td {{ padding:.32rem .4rem; border-bottom:1px solid #16213a; vertical-align:top; }}
191
+ td.num {{ color:var(--muted); }} td.act code {{ color:#bcd; word-break:break-word; }}
192
+ td.obs {{ color:var(--muted); }} td.hash code {{ color:var(--gold); font-size:.68rem; }}
193
+ .pat {{ color:var(--indigo); font-weight:600; }} .role {{ color:var(--muted); }}
194
+ .badge {{ font-size:.6rem; padding:.16rem .45rem; border-radius:999px; letter-spacing:.05em; }}
195
+ .badge.ok {{ background:rgba(63,174,122,.16); color:var(--ok); border:1px solid rgba(63,174,122,.4); }}
196
+ .badge.warn {{ background:rgba(200,137,60,.16); color:var(--warn); border:1px solid rgba(200,137,60,.4); }}
197
+ .badge.exp {{ background:rgba(120,140,210,.16); color:var(--exp); border:1px solid rgba(120,140,210,.45); }}
198
+ .badge.bad {{ background:rgba(204,90,90,.16); color:var(--bad); border:1px solid rgba(204,90,90,.45); }}
199
+ h2 {{ margin-top:2.2rem; font-size:1.25rem; }}
200
+ textarea {{ width:100%; min-height:140px; background:#070c17; border:1px solid #1a2742; border-radius:8px;
201
+ color:#bcd; font-family:ui-monospace,monospace; font-size:.72rem; padding:.7rem; }}
202
+ button.verify {{ background:var(--terra); color:#0a0f1e; border:0; border-radius:8px; padding:.5rem .9rem;
203
+ font-weight:700; cursor:pointer; font-size:.85rem; margin-top:.6rem; }}
204
+ button.verify:hover {{ filter:brightness(1.08); }}
205
+ pre.out {{ background:#070c17; border:1px solid #1a2742; border-radius:8px; padding:.7rem; margin-top:.7rem;
206
+ font-size:.74rem; color:#bcd; overflow:auto; max-height:300px; white-space:pre-wrap; }}
207
+ a.back {{ color:var(--muted); text-decoration:none; font-size:.85rem; }}
208
+ code.ep {{ color:var(--gold); }}
209
+ </style></head>
210
+ <body>
211
+ <main class="wrap" id="main">
212
+ <div class="plaque">SZL HOLDINGS / A11OY / SZL-NEMO / DOCTRINE <b>{DOCTRINE['version']} · LOCKED</b>
213
+ / {DOCTRINE['counts']} / Λ = CONJECTURE 1 / SLSA L1 (L2/L3 ROADMAP)</div>
214
+ <h1>The <span class="accent">signed corpus</span> is verifiable.</h1>
215
+ <p class="sub">A cryptographically-signed, provenance-attested agent-trajectory corpus.
216
+ Each JSONL line is one agent step — <code>action</code>, <code>observation</code>,
217
+ <code>restraint_verdict</code>, <code>step_hash</code>, <code>signature</code> — emitted by
218
+ instrumenting the SZL ReAct + Reflexion + Restraint + Auto-Review loop. Anyone can verify
219
+ every signature below. <a class="back" href="/">← back to console</a></p>
220
+
221
+ <div class="honest">⚖️ <b>Honest scope:</b> {_html.escape(st['honesty'])}</div>
222
+
223
+ <div class="attr">📚 <b>Attribution (CC BY 4.0):</b> sample trajectories are a schema-faithful
224
+ mapping of <a href="{_html.escape(attr['url'])}" target="_blank" rel="noopener">{_html.escape(attr['source_dataset'])}</a>
225
+ © {_html.escape(attr['source_owner'])}, licensed {_html.escape(attr['license_full'])}.
226
+ Source totals: {attr['subsets']['interactive_agent']:,} interactive_agent +
227
+ {attr['subsets']['tool_calling']:,} tool_calling = {attr['total_source_samples']:,} samples.
228
+ Attribution is required and does not imply endorsement.</div>
229
+
230
+ <div class="bignum">
231
+ <div><div class="n">{st['trajectory_count']}</div><div class="l">sample trajectories</div></div>
232
+ <div><div class="n">{st['total_steps']}</div><div class="l">signed steps</div></div>
233
+ <div><div class="n">{verify.get('hash_ok',0)}/{verify.get('total_steps',0)}</div><div class="l">hash-verified</div></div>
234
+ <div><div class="n">{'YES' if st['signing_available'] else 'NO'}</div><div class="l">private key in env</div></div>
235
+ <div><div class="n">{ingest.SOURCE_TOTAL:,}</div><div class="l">source samples (CC BY 4.0)</div></div>
236
+ </div>
237
+ <div class="chips">{chips}</div>
238
+
239
+ <h2>Sample signed trajectories</h2>
240
+ {_sample_cards()}
241
+
242
+ <h2>Verify it yourself</h2>
243
+ <p class="sub">Paste signed-trajectory JSONL (or use the loaded sample) and run the integrity +
244
+ signature check. It calls <code class="ep">POST /api/{ns}/v1/nemo/verify</code> server-side,
245
+ which recomputes each <code>step_hash</code> and verifies each DSSE envelope against the
246
+ published <code>cosign.pub</code>. Honest: with no private key in this environment the receipts
247
+ are UNSIGNED and the verifier says so — it never fabricates a pass.</p>
248
+ <textarea id="jsonl"></textarea>
249
+ <div>
250
+ <button class="verify" id="run">Verify signatures &amp; hashes</button>
251
+ <button class="verify" id="load" style="background:var(--indigo);">Load sample JSONL</button>
252
+ </div>
253
+ <pre class="out" id="out" hidden></pre>
254
+ </main>
255
+ <script>
256
+ const NS = {json.dumps(ns)};
257
+ const SAMPLE = {json.dumps(sample_jsonl)};
258
+ document.getElementById('load').addEventListener('click', function() {{
259
+ document.getElementById('jsonl').value = SAMPLE;
260
+ }});
261
+ document.getElementById('run').addEventListener('click', async function() {{
262
+ const out = document.getElementById('out');
263
+ const jsonl = document.getElementById('jsonl').value || SAMPLE;
264
+ out.hidden = false; out.textContent = 'verifying …';
265
+ try {{
266
+ const r = await fetch('/api/' + NS + '/v1/nemo/verify', {{
267
+ method: 'POST', headers: {{ 'Content-Type': 'application/json' }},
268
+ body: JSON.stringify({{ jsonl: jsonl }})
269
+ }});
270
+ const t = await r.text();
271
+ try {{ out.textContent = '[' + r.status + '] ' + JSON.stringify(JSON.parse(t), null, 2); }}
272
+ catch (e) {{ out.textContent = '[' + r.status + '] ' + t.slice(0, 1200); }}
273
+ }} catch (e) {{ out.textContent = 'error: ' + e; }}
274
+ }});
275
+ </script>
276
+ </body></html>"""
277
+
278
+
279
+ # --------------------------------------------------------------------------- #
280
+ # Nav-injection middleware (idempotent; appends a floating link to every HTML
281
+ # surface so the tab is reachable from the console without editing the SPA).
282
+ # --------------------------------------------------------------------------- #
283
+ def _install_nav_injector(app: FastAPI) -> bool:
284
+ try:
285
+ from starlette.middleware.base import BaseHTTPMiddleware
286
+ from starlette.responses import Response as _Resp
287
+ except Exception:
288
+ return False
289
+
290
+ _MARKER = b"szl-nemo-corpus-nav"
291
+ _TAG = (
292
+ b'<a id="szl-nemo-corpus-nav" href="/signed-corpus" '
293
+ b'style="position:fixed;right:14px;bottom:14px;z-index:99998;'
294
+ b'background:#c8643c;color:#0a0f1e;font:600 12px ui-sans-serif,system-ui;'
295
+ b'padding:8px 12px;border-radius:999px;text-decoration:none;'
296
+ b'box-shadow:0 6px 18px -6px #000;" '
297
+ b'title="DSSE-signed agent-trajectory corpus (SZL-Nemo)">'
298
+ b'\xe2\x97\x88 Signed Corpus</a>'
299
+ )
300
+
301
+ class _NemoNavInjector(BaseHTTPMiddleware):
302
+ async def dispatch(self, request: Request, call_next): # noqa: ANN001
303
+ resp = await call_next(request)
304
+ try:
305
+ ct = (resp.headers.get("content-type") or "").lower()
306
+ if "text/html" not in ct:
307
+ return resp
308
+ p = request.url.path
309
+ if (p.startswith("/vendor/") or p.startswith("/api/")
310
+ or p.startswith("/assets/") or p == "/signed-corpus"):
311
+ return resp
312
+ body = b""
313
+ async for chunk in resp.body_iterator:
314
+ body += chunk if isinstance(chunk, (bytes, bytearray)) \
315
+ else str(chunk).encode()
316
+ if _MARKER in body: # idempotent
317
+ new_body = body
318
+ elif b"</body>" in body:
319
+ new_body = body.replace(b"</body>", _TAG + b"</body>", 1)
320
+ elif b"</html>" in body:
321
+ new_body = body.replace(b"</html>", _TAG + b"</html>", 1)
322
+ else:
323
+ new_body = body + _TAG
324
+ headers = dict(resp.headers)
325
+ headers.pop("content-length", None)
326
+ return _Resp(content=new_body, status_code=resp.status_code,
327
+ headers=headers, media_type="text/html")
328
+ except Exception:
329
+ return resp
330
+
331
+ app.add_middleware(_NemoNavInjector)
332
+ return True
333
+
334
+
335
+ # --------------------------------------------------------------------------- #
336
+ # Registration
337
+ # --------------------------------------------------------------------------- #
338
+ def register(app: FastAPI, ns: str = "a11oy") -> str:
339
+ """Mount the Signed-Corpus tab + JSON/verify endpoints + nav injector.
340
+
341
+ ADDITIVE — explicit routes registered before the SPA catch-all; the nav
342
+ injector is idempotent and never rewrites page content. try/except in
343
+ serve.py guarantees a missing dep can never take down the Space.
344
+ """
345
+
346
+ @app.get("/signed-corpus", include_in_schema=False)
347
+ async def signed_corpus_page() -> HTMLResponse: # noqa: ANN202
348
+ return HTMLResponse(_page_html(ns))
349
+
350
+ # Alias under the namespace, mirroring the other genius tabs.
351
+ @app.get(f"/{ns}/signed-corpus", include_in_schema=False)
352
+ async def signed_corpus_page_ns() -> HTMLResponse: # noqa: ANN202
353
+ return HTMLResponse(_page_html(ns))
354
+
355
+ @app.get(f"/api/{ns}/v1/nemo/stats", include_in_schema=False)
356
+ async def nemo_stats() -> JSONResponse: # noqa: ANN202
357
+ return JSONResponse(_stats())
358
+
359
+ @app.get(f"/api/{ns}/v1/nemo/sample", include_in_schema=False)
360
+ async def nemo_sample() -> PlainTextResponse: # noqa: ANN202
361
+ return PlainTextResponse(_CORPUS["jsonl"], media_type="application/x-ndjson")
362
+
363
+ @app.post(f"/api/{ns}/v1/nemo/verify", include_in_schema=False)
364
+ async def nemo_verify(request: Request) -> JSONResponse: # noqa: ANN202
365
+ try:
366
+ payload = await request.json()
367
+ except Exception:
368
+ payload = {}
369
+ jsonl = ""
370
+ if isinstance(payload, dict):
371
+ jsonl = payload.get("jsonl") or payload.get("text") or ""
372
+ if not isinstance(jsonl, str) or not jsonl.strip():
373
+ jsonl = _CORPUS["jsonl"] # default: verify the shipped sample
374
+ result = sts.verify_jsonl(jsonl)
375
+ result["honesty"] = (
376
+ "Integrity check recomputes each step_hash and verifies each DSSE "
377
+ "envelope against the published cosign.pub. 'signed' counts receipts "
378
+ "carrying a real signature; with no private key in this environment "
379
+ "receipts are honestly UNSIGNED (signed=0) — never fabricated."
380
+ )
381
+ result["doctrine"] = DOCTRINE
382
+ return JSONResponse(result)
383
+
384
+ nav_ok = _install_nav_injector(app)
385
+ return (f"nemotron signed-corpus mounted: GET /signed-corpus + "
386
+ f"/api/{ns}/v1/nemo/{{stats,sample,verify}} ; nav-injector={nav_ok}")
387
+
388
+
389
+ if __name__ == "__main__":
390
+ # Pure self-check: render page + verify endpoints without a live server.
391
+ st = _stats()
392
+ page = _page_html("a11oy")
393
+ assert "signed corpus" in page.lower()
394
+ assert "CC BY 4.0" in page or "cc-by-4.0" in page.lower()
395
+ assert "ROADMAP" in page
396
+ assert st["trajectory_count"] >= 1
397
+ print(json.dumps({
398
+ "page_bytes": len(page),
399
+ "trajectory_count": st["trajectory_count"],
400
+ "total_steps": st["total_steps"],
401
+ "verify": st["verify"],
402
+ "verdict_counts": st["verdict_counts"],
403
+ "pattern_counts": st["pattern_counts"],
404
+ "signing_available": st["signing_available"],
405
+ "attribution_license": st["attribution"]["license"],
406
+ }, indent=2))
szl_nemotron_ingest.py ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11/v12
3
+ # Authored by the NEMOTRON SIGNED-TRAJECTORY build team. Co-Authored-By: Perplexity Computer Agent.
4
+ """
5
+ szl_nemotron_ingest — map nvidia/Nemotron-Agentic-v1 into the SZL trajectory schema.
6
+
7
+ WHAT THIS IS (honest framing):
8
+ A pure-CPU mapper that takes rows from NVIDIA's open agentic dataset
9
+ (nvidia/Nemotron-Agentic-v1, 335,122 samples, CC BY 4.0) and re-expresses
10
+ each multi-turn conversation as an SZL trajectory: one signed-step receipt
11
+ per agent/tool turn (see szl_trajectory_sign). The output is QLoRA-ready and
12
+ every step is independently signature-verifiable.
13
+
14
+ ATTRIBUTION (CC BY 4.0 — REQUIRED, never strip):
15
+ Source dataset : nvidia/Nemotron-Agentic-v1
16
+ Owner : NVIDIA Corporation
17
+ License : Creative Commons Attribution 4.0 International (CC BY 4.0)
18
+ Subsets : interactive_agent (19,028) + tool_calling (316,094) = 335,122
19
+ URL : https://huggingface.co/datasets/nvidia/Nemotron-Agentic-v1
20
+ Each emitted trajectory carries source="nvidia", verified=False, signed-status
21
+ per the signer, label="SAMPLE", and the full attribution block above. We do NOT
22
+ redistribute NVIDIA's raw rows here; we ship a representative SAMPLE mapping and
23
+ the mapper so the full 335k can be re-derived locally from the open source.
24
+
25
+ WHAT THIS IS *NOT*:
26
+ - Not a model. Not a training run. Not an Ultra reproduction. The signed corpus
27
+ is a DATASET property. Actual QLoRA/GRPO training = ROADMAP (FORGE order,
28
+ needs >=2x80GB GPU).
29
+ - We do not claim NVIDIA endorses SZL. CC BY 4.0 attribution != endorsement.
30
+
31
+ SOURCE ROW SCHEMA (from the HF dataset card / preview):
32
+ {
33
+ "uuid": str,
34
+ "messages": [ {role, content, [tool_calls], [tool_call_id], ...}, ... ],
35
+ "license": "cc-by-4.0",
36
+ "used_in": ["nano_v3", ...],
37
+ "tools": [ {"type":"function","function":{name,description,parameters}}, ... ],
38
+ "reasoning": "on" | "off"
39
+ }
40
+
41
+ MAPPING (Nemotron message -> SZL trajectory step):
42
+ role "assistant" with tool_calls -> step {role:assistant, pattern:ReAct,
43
+ action: the tool_call(s), restraint_verdict via _verdict_for()}
44
+ role "tool" -> step {role:tool, observation: content}
45
+ role "assistant" plain text -> step {role:assistant, action: text,
46
+ pattern: Reflexion if it looks like a self-correction else AutoReview}
47
+ role "system"/"user" -> recorded as trajectory context (not a
48
+ signed agent action), surfaced in provenance.
49
+
50
+ ADDITIVE · stdlib + szl_trajectory_sign only · CPU-only · no network required.
51
+ """
52
+ from __future__ import annotations
53
+
54
+ import json
55
+ import os
56
+ from typing import Any, Dict, Iterable, List, Optional
57
+
58
+ import szl_trajectory_sign as sts
59
+
60
+ SOURCE_DATASET = "nvidia/Nemotron-Agentic-v1"
61
+ SOURCE_OWNER = "NVIDIA Corporation"
62
+ SOURCE_LICENSE = "CC BY 4.0"
63
+ SOURCE_LICENSE_FULL = "Creative Commons Attribution 4.0 International (CC BY 4.0)"
64
+ SOURCE_URL = "https://huggingface.co/datasets/nvidia/Nemotron-Agentic-v1"
65
+ SOURCE_SUBSETS = {"interactive_agent": 19028, "tool_calling": 316094}
66
+ SOURCE_TOTAL = 335122
67
+
68
+ ATTRIBUTION = {
69
+ "source_dataset": SOURCE_DATASET,
70
+ "source_owner": SOURCE_OWNER,
71
+ "license": SOURCE_LICENSE,
72
+ "license_full": SOURCE_LICENSE_FULL,
73
+ "url": SOURCE_URL,
74
+ "subsets": SOURCE_SUBSETS,
75
+ "total_source_samples": SOURCE_TOTAL,
76
+ "note": (
77
+ "Re-expressed into the SZL trajectory schema under CC BY 4.0. Attribution to "
78
+ "NVIDIA is required and does not imply endorsement. Raw NVIDIA rows are not "
79
+ "redistributed here; this is a representative SAMPLE mapping plus the mapper."
80
+ ),
81
+ }
82
+
83
+ # Reflexion cue words: an assistant turn that reads like a self-correction.
84
+ _REFLEXION_CUES = (
85
+ "let me reconsider", "i was wrong", "correction", "actually,", "on second thought",
86
+ "let me retry", "that was incorrect", "i made an error", "let me fix",
87
+ )
88
+
89
+
90
+ def _verdict_for(msg: Dict[str, Any], tools_present: bool) -> str:
91
+ """Conservative Restraint verdict for a mapped Nemotron turn.
92
+
93
+ Honest defaults ("never engage on doubt"): a tool call with arguments is
94
+ ALLOW; an assistant turn that declines/escalates -> HOLD/DECLINE; ambiguous
95
+ tool environments -> MONITOR.
96
+ """
97
+ content = (msg.get("content") or "")
98
+ low = content.lower() if isinstance(content, str) else ""
99
+ if any(w in low for w in ("cannot", "i'm sorry, but", "not able to", "decline",
100
+ "against policy", "i can't")):
101
+ return "DECLINE"
102
+ if any(w in low for w in ("need to verify", "please confirm", "let me check",
103
+ "i need more information", "could you clarify")):
104
+ return "HOLD"
105
+ if msg.get("tool_calls"):
106
+ return "ALLOW"
107
+ if tools_present and msg.get("role") == "assistant" and not low.strip():
108
+ return "MONITOR"
109
+ return "ALLOW"
110
+
111
+
112
+ def _pattern_for(msg: Dict[str, Any], prev_assistant_text: str) -> str:
113
+ role = msg.get("role")
114
+ content = msg.get("content") or ""
115
+ low = content.lower() if isinstance(content, str) else ""
116
+ # A self-correcting turn is Reflexion even if it also calls a tool (the
117
+ # backtrack is the salient property for the trajectory corpus).
118
+ if role == "assistant" and any(c in low for c in _REFLEXION_CUES):
119
+ return "Reflexion"
120
+ if msg.get("tool_calls"):
121
+ return "ReAct"
122
+ if role == "assistant":
123
+ return "AutoReview"
124
+ return "ReAct"
125
+
126
+
127
+ def _action_of(msg: Dict[str, Any]) -> Any:
128
+ """Extract the agent action: tool_calls if present, else the text content."""
129
+ tcs = msg.get("tool_calls")
130
+ if tcs:
131
+ # Normalise to {name, arguments} pairs (OpenAI-style function tool_calls).
132
+ out = []
133
+ for tc in tcs:
134
+ fn = (tc or {}).get("function", {}) if isinstance(tc, dict) else {}
135
+ out.append({"name": fn.get("name"), "arguments": fn.get("arguments")})
136
+ return {"tool_calls": out}
137
+ return msg.get("content", "")
138
+
139
+
140
+ def map_row(row: Dict[str, Any], *, label: str = "SAMPLE",
141
+ environment: str = "nemotron-agentic") -> Dict[str, Any]:
142
+ """Map ONE Nemotron-Agentic-v1 row to a sealed, DSSE-signed SZL trajectory.
143
+
144
+ Returns the seal() dict: {"provenance", "steps", "jsonl"} with the attribution
145
+ and source UUID embedded in provenance.extra.
146
+ """
147
+ uuid_src = row.get("uuid") or ""
148
+ messages: List[Dict[str, Any]] = row.get("messages") or []
149
+ tools = row.get("tools") or []
150
+ tools_present = bool(tools)
151
+ reasoning = row.get("reasoning", "off")
152
+ used_in = row.get("used_in") or []
153
+
154
+ # Reconstruct a short task descriptor from the first user turn.
155
+ task = ""
156
+ for m in messages:
157
+ if m.get("role") == "user":
158
+ c = m.get("content") or ""
159
+ task = (c[:160] + "…") if isinstance(c, str) and len(c) > 160 else c
160
+ break
161
+
162
+ t = sts.SignedTrajectory(task=task or f"nemotron:{uuid_src[:8]}",
163
+ environment=environment, label=label)
164
+ last_assistant_idx: Optional[int] = None
165
+ last_assistant_text = ""
166
+ context_turns: List[Dict[str, Any]] = []
167
+
168
+ for m in messages:
169
+ role = m.get("role")
170
+ if role in ("system", "user"):
171
+ # Context, not a signed agent action — preserved in provenance.
172
+ context_turns.append({"role": role,
173
+ "content": (m.get("content") or "")[:500]})
174
+ continue
175
+ if role == "tool":
176
+ # Observation turn: attach as a tool observation step.
177
+ t.add(action={"tool_result_for": m.get("tool_call_id")},
178
+ observation=m.get("content", ""), role="tool",
179
+ pattern="ReAct", restraint_verdict="MONITOR")
180
+ continue
181
+ if role == "assistant":
182
+ pattern = _pattern_for(m, last_assistant_text)
183
+ verdict = _verdict_for(m, tools_present)
184
+ is_corr = pattern == "Reflexion"
185
+ t.add(action=_action_of(m), observation="", role="assistant",
186
+ pattern=pattern, restraint_verdict=verdict,
187
+ is_correction=is_corr,
188
+ correction_of=last_assistant_idx if is_corr else None,
189
+ tool_calls=([{"function": (tc or {}).get("function", {})}
190
+ for tc in (m.get("tool_calls") or [])] or None))
191
+ last_assistant_idx = len(t.steps) - 1
192
+ if isinstance(m.get("content"), str):
193
+ last_assistant_text = m["content"]
194
+
195
+ sealed = t.seal(outcome="mapped")
196
+ sealed["provenance"]["source"] = "nvidia"
197
+ sealed["provenance"]["verified"] = False
198
+ sealed["provenance"]["reasoning_mode"] = reasoning
199
+ sealed["provenance"]["used_in"] = used_in
200
+ sealed["provenance"]["source_uuid"] = uuid_src
201
+ sealed["provenance"]["context_turns"] = context_turns
202
+ sealed["provenance"]["tools_count"] = len(tools)
203
+ sealed["provenance"]["attribution"] = ATTRIBUTION
204
+ return sealed
205
+
206
+
207
+ def map_rows(rows: Iterable[Dict[str, Any]], *, label: str = "SAMPLE",
208
+ environment: str = "nemotron-agentic") -> List[Dict[str, Any]]:
209
+ return [map_row(r, label=label, environment=environment) for r in rows]
210
+
211
+
212
+ # --------------------------------------------------------------------------- #
213
+ # Representative SAMPLE rows (faithful to the published schema; NOT NVIDIA's
214
+ # verbatim rows — see ATTRIBUTION.note). Used to ship a demo corpus CPU-only.
215
+ # --------------------------------------------------------------------------- #
216
+ def sample_rows() -> List[Dict[str, Any]]:
217
+ """A handful of schema-faithful representative rows (tool_calling +
218
+ interactive_agent flavours), so the served demo has real content offline."""
219
+ return [
220
+ {
221
+ "uuid": "ff6ab2b0-7551-468c-8606-a7c3b0c75b68",
222
+ "license": "cc-by-4.0",
223
+ "used_in": ["nano_v3"],
224
+ "reasoning": "on",
225
+ "tools": [{"type": "function", "function": {
226
+ "name": "place_order",
227
+ "description": "Create a new food delivery order",
228
+ "parameters": {"type": "object", "properties": {
229
+ "user_id": {"type": "string"},
230
+ "restaurant_id": {"type": "string"}}}}}],
231
+ "messages": [
232
+ {"role": "system", "content": "You are a customer service agent. "
233
+ "Follow the <policy>…</policy>. You may message the user or call a tool."},
234
+ {"role": "user", "content": "Order me a large pepperoni pizza from Tony's."},
235
+ {"role": "assistant", "content": "Let me check the menu first.",
236
+ "tool_calls": [{"type": "function", "function": {
237
+ "name": "get_menu", "arguments": "{\"restaurant_id\":\"tonys\"}"}}]},
238
+ {"role": "tool", "tool_call_id": "c1",
239
+ "content": "{\"items\":[{\"id\":\"p_lg\",\"name\":\"Large Pepperoni\"}]}"},
240
+ {"role": "assistant", "content": "I need to verify your delivery address "
241
+ "before placing the order. Could you confirm it?"},
242
+ {"role": "user", "content": "123 Main St, 10588."},
243
+ {"role": "assistant", "content": "Placing your order now.",
244
+ "tool_calls": [{"type": "function", "function": {
245
+ "name": "place_order",
246
+ "arguments": "{\"user_id\":\"u1\",\"restaurant_id\":\"tonys\"}"}}]},
247
+ {"role": "tool", "tool_call_id": "c2",
248
+ "content": "{\"order_id\":\"o_99\",\"status\":\"confirmed\"}"},
249
+ {"role": "assistant", "content": "Done — order o_99 is confirmed."},
250
+ ],
251
+ },
252
+ {
253
+ "uuid": "a1c9d2e3-0000-4aaa-bbbb-1234567890ab",
254
+ "license": "cc-by-4.0",
255
+ "used_in": ["super_v3"],
256
+ "reasoning": "on",
257
+ "tools": [{"type": "function", "function": {
258
+ "name": "search_flights",
259
+ "description": "Search available flights",
260
+ "parameters": {"type": "object", "properties": {
261
+ "origin": {"type": "string"}, "dest": {"type": "string"}}}}}],
262
+ "messages": [
263
+ {"role": "system", "content": "You are a travel agent. Obey policy."},
264
+ {"role": "user", "content": "Find me a flight JFK to LAX tomorrow."},
265
+ {"role": "assistant", "content": "Searching flights.",
266
+ "tool_calls": [{"type": "function", "function": {
267
+ "name": "search_flights",
268
+ "arguments": "{\"origin\":\"JFK\",\"dest\":\"LAZ\"}"}}]},
269
+ {"role": "tool", "tool_call_id": "c1",
270
+ "content": "{\"error\":\"unknown airport LAZ\"}"},
271
+ {"role": "assistant", "content": "Correction: I mistyped the airport "
272
+ "code. Let me retry with LAX.",
273
+ "tool_calls": [{"type": "function", "function": {
274
+ "name": "search_flights",
275
+ "arguments": "{\"origin\":\"JFK\",\"dest\":\"LAX\"}"}}]},
276
+ {"role": "tool", "tool_call_id": "c2",
277
+ "content": "{\"flights\":[{\"id\":\"f1\",\"dep\":\"08:00\"}]}"},
278
+ {"role": "assistant", "content": "Found flight f1 departing 08:00."},
279
+ ],
280
+ },
281
+ {
282
+ "uuid": "b2d0e4f5-1111-4ccc-dddd-0987654321fe",
283
+ "license": "cc-by-4.0",
284
+ "used_in": ["ultra_v3"],
285
+ "reasoning": "off",
286
+ "tools": [{"type": "function", "function": {
287
+ "name": "issue_refund",
288
+ "description": "Issue a refund subject to policy tier",
289
+ "parameters": {"type": "object", "properties": {
290
+ "order_id": {"type": "string"},
291
+ "refund_tier": {"type": "string", "enum": ["full", "partial"]}}}}}],
292
+ "messages": [
293
+ {"role": "system", "content": "Refund agent. Enforce refund policy strictly."},
294
+ {"role": "user", "content": "I want a full refund on order o_77, no receipt."},
295
+ {"role": "assistant", "content": "I'm sorry, but I cannot issue a full "
296
+ "refund without proof of purchase under policy. I can escalate to a "
297
+ "human reviewer if you'd like."},
298
+ ],
299
+ },
300
+ ]
301
+
302
+
303
+ # --------------------------------------------------------------------------- #
304
+ # Optional: load real NVIDIA rows from a local JSONL (if a user has downloaded
305
+ # the dataset). Network-free; only reads what's on disk.
306
+ # --------------------------------------------------------------------------- #
307
+ def load_local_jsonl(path: str, limit: Optional[int] = None) -> List[Dict[str, Any]]:
308
+ rows: List[Dict[str, Any]] = []
309
+ if not os.path.exists(path):
310
+ return rows
311
+ with open(path, "r", encoding="utf-8") as fh:
312
+ for i, line in enumerate(fh):
313
+ if limit is not None and i >= limit:
314
+ break
315
+ line = line.strip()
316
+ if line:
317
+ try:
318
+ rows.append(json.loads(line))
319
+ except Exception:
320
+ continue
321
+ return rows
322
+
323
+
324
+ def build_sample_corpus(label: str = "SAMPLE") -> Dict[str, Any]:
325
+ """Map the representative sample rows; return {trajectories, jsonl, stats}."""
326
+ sealed = map_rows(sample_rows(), label=label)
327
+ all_steps_jsonl: List[str] = []
328
+ for s in sealed:
329
+ if s["jsonl"]:
330
+ all_steps_jsonl.append(s["jsonl"])
331
+ jsonl = "\n".join(all_steps_jsonl)
332
+ total_steps = sum(s["provenance"]["total_steps"] for s in sealed)
333
+ verdict_counts: Dict[str, int] = {}
334
+ pattern_counts: Dict[str, int] = {}
335
+ for s in sealed:
336
+ for st in s["steps"]:
337
+ verdict_counts[st["restraint_verdict"]] = \
338
+ verdict_counts.get(st["restraint_verdict"], 0) + 1
339
+ pattern_counts[st["pattern"]] = pattern_counts.get(st["pattern"], 0) + 1
340
+ return {
341
+ "trajectories": sealed,
342
+ "jsonl": jsonl,
343
+ "stats": {
344
+ "label": label,
345
+ "trajectory_count": len(sealed),
346
+ "total_steps": total_steps,
347
+ "verdict_counts": verdict_counts,
348
+ "pattern_counts": pattern_counts,
349
+ "signing_available": sts.signing_available(),
350
+ "attribution": ATTRIBUTION,
351
+ },
352
+ }
353
+
354
+
355
+ if __name__ == "__main__":
356
+ corpus = build_sample_corpus()
357
+ v = sts.verify_jsonl(corpus["jsonl"])
358
+ print(json.dumps({
359
+ "trajectories": corpus["stats"]["trajectory_count"],
360
+ "total_steps": corpus["stats"]["total_steps"],
361
+ "verdict_counts": corpus["stats"]["verdict_counts"],
362
+ "pattern_counts": corpus["stats"]["pattern_counts"],
363
+ "verify": {k: v[k] for k in ("total_steps", "all_hash_ok", "signed", "sig_ok")},
364
+ "attribution_license": corpus["stats"]["attribution"]["license"],
365
+ }, indent=2))