diff --git a/wizard-work/ledger/2026-10-23-jpv-users.csv b/wizard-work/ledger/2026-10-23-jpv-users.csv new file mode 100644 index 0000000..1f8ab48 --- /dev/null +++ b/wizard-work/ledger/2026-10-23-jpv-users.csv @@ -0,0 +1,11 @@ +id,name,username,email,city,phone,website,company +1,Leanne Graham,Bret,Sincere@april.biz,Gwenborough,1-770-736-8031 x56442,hildegard.org,Romaguera-Crona +2,Ervin Howell,Antonette,Shanna@melissa.tv,Wisokyburgh,010-692-6593 x09125,anastasia.net,Deckow-Crist +3,Clementine Bauch,Samantha,Nathan@yesenia.net,McKenziehaven,1-463-123-4447,ramiro.info,Romaguera-Jacobson +4,Patricia Lebsack,Karianne,Julianne.OConner@kory.org,South Elvis,493-170-9623 x156,kale.biz,Robel-Corkery +5,Chelsey Dietrich,Kamren,Lucio_Hettinger@annie.ca,Roscoeview,(254)954-1289,demarco.info,Keebler LLC +6,Mrs. Dennis Schulist,Leopoldo_Corkery,Karley_Dach@jasper.info,South Christy,1-477-935-8478 x6430,ola.org,Considine-Lockman +7,Kurtis Weissnat,Elwyn.Skiles,Telly.Hoeger@billy.biz,Howemouth,210.067.6132,elvis.io,Johns Group +8,Nicholas Runolfsdottir V,Maxime_Nienow,Sherwood@rosamond.me,Aliyaview,586.493.6943 x140,jacynthe.com,Abernathy Group +9,Glenna Reichert,Delphine,Chaim_McDermott@dana.io,Bartholomebury,(775)976-6794 x41206,conrad.com,Yost and Sons +10,Clementina DuBuque,Moriah.Stanton,Rey.Padberg@karina.biz,Lebsackbury,024-648-3804,ambrose.net,Hoeger LLC diff --git a/wizard-work/ledger/2026-10-23-jpv-users.json b/wizard-work/ledger/2026-10-23-jpv-users.json new file mode 100644 index 0000000..fb41fff --- /dev/null +++ b/wizard-work/ledger/2026-10-23-jpv-users.json @@ -0,0 +1,102 @@ +[ + { + "id": 1, + "name": "Leanne Graham", + "username": "Bret", + "email": "Sincere@april.biz", + "city": "Gwenborough", + "phone": "1-770-736-8031 x56442", + "website": "hildegard.org", + "company": "Romaguera-Crona" + }, + { + "id": 2, + "name": "Ervin Howell", + "username": "Antonette", + "email": "Shanna@melissa.tv", + "city": "Wisokyburgh", + "phone": "010-692-6593 x09125", + "website": "anastasia.net", + "company": "Deckow-Crist" + }, + { + "id": 3, + "name": "Clementine Bauch", + "username": "Samantha", + "email": "Nathan@yesenia.net", + "city": "McKenziehaven", + "phone": "1-463-123-4447", + "website": "ramiro.info", + "company": "Romaguera-Jacobson" + }, + { + "id": 4, + "name": "Patricia Lebsack", + "username": "Karianne", + "email": "Julianne.OConner@kory.org", + "city": "South Elvis", + "phone": "493-170-9623 x156", + "website": "kale.biz", + "company": "Robel-Corkery" + }, + { + "id": 5, + "name": "Chelsey Dietrich", + "username": "Kamren", + "email": "Lucio_Hettinger@annie.ca", + "city": "Roscoeview", + "phone": "(254)954-1289", + "website": "demarco.info", + "company": "Keebler LLC" + }, + { + "id": 6, + "name": "Mrs. Dennis Schulist", + "username": "Leopoldo_Corkery", + "email": "Karley_Dach@jasper.info", + "city": "South Christy", + "phone": "1-477-935-8478 x6430", + "website": "ola.org", + "company": "Considine-Lockman" + }, + { + "id": 7, + "name": "Kurtis Weissnat", + "username": "Elwyn.Skiles", + "email": "Telly.Hoeger@billy.biz", + "city": "Howemouth", + "phone": "210.067.6132", + "website": "elvis.io", + "company": "Johns Group" + }, + { + "id": 8, + "name": "Nicholas Runolfsdottir V", + "username": "Maxime_Nienow", + "email": "Sherwood@rosamond.me", + "city": "Aliyaview", + "phone": "586.493.6943 x140", + "website": "jacynthe.com", + "company": "Abernathy Group" + }, + { + "id": 9, + "name": "Glenna Reichert", + "username": "Delphine", + "email": "Chaim_McDermott@dana.io", + "city": "Bartholomebury", + "phone": "(775)976-6794 x41206", + "website": "conrad.com", + "company": "Yost and Sons" + }, + { + "id": 10, + "name": "Clementina DuBuque", + "username": "Moriah.Stanton", + "email": "Rey.Padberg@karina.biz", + "city": "Lebsackbury", + "phone": "024-648-3804", + "website": "ambrose.net", + "company": "Hoeger LLC" + } +] \ No newline at end of file diff --git a/wizard-work/ledger/2026-10-23-jpv-users.md b/wizard-work/ledger/2026-10-23-jpv-users.md new file mode 100644 index 0000000..3c22628 --- /dev/null +++ b/wizard-work/ledger/2026-10-23-jpv-users.md @@ -0,0 +1,12 @@ +| id | name | username | email | city | phone | website | company | +|---|---|---|---|---|---|---|---| +| 1 | Leanne Graham | Bret | Sincere@april.biz | Gwenborough | 1-770-736-8031 x56442 | hildegard.org | Romaguera-Crona | +| 2 | Ervin Howell | Antonette | Shanna@melissa.tv | Wisokyburgh | 010-692-6593 x09125 | anastasia.net | Deckow-Crist | +| 3 | Clementine Bauch | Samantha | Nathan@yesenia.net | McKenziehaven | 1-463-123-4447 | ramiro.info | Romaguera-Jacobson | +| 4 | Patricia Lebsack | Karianne | Julianne.OConner@kory.org | South Elvis | 493-170-9623 x156 | kale.biz | Robel-Corkery | +| 5 | Chelsey Dietrich | Kamren | Lucio_Hettinger@annie.ca | Roscoeview | (254)954-1289 | demarco.info | Keebler LLC | +| 6 | Mrs. Dennis Schulist | Leopoldo_Corkery | Karley_Dach@jasper.info | South Christy | 1-477-935-8478 x6430 | ola.org | Considine-Lockman | +| 7 | Kurtis Weissnat | Elwyn.Skiles | Telly.Hoeger@billy.biz | Howemouth | 210.067.6132 | elvis.io | Johns Group | +| 8 | Nicholas Runolfsdottir V | Maxime_Nienow | Sherwood@rosamond.me | Aliyaview | 586.493.6943 x140 | jacynthe.com | Abernathy Group | +| 9 | Glenna Reichert | Delphine | Chaim_McDermott@dana.io | Bartholomebury | (775)976-6794 x41206 | conrad.com | Yost and Sons | +| 10 | Clementina DuBuque | Moriah.Stanton | Rey.Padberg@karina.biz | Lebsackbury | 024-648-3804 | ambrose.net | Hoeger LLC | diff --git a/wizard-work/ledger/2026-10-23-jpv-users.raw.json b/wizard-work/ledger/2026-10-23-jpv-users.raw.json new file mode 100644 index 0000000..79b699a --- /dev/null +++ b/wizard-work/ledger/2026-10-23-jpv-users.raw.json @@ -0,0 +1,232 @@ +[ + { + "id": 1, + "name": "Leanne Graham", + "username": "Bret", + "email": "Sincere@april.biz", + "address": { + "street": "Kulas Light", + "suite": "Apt. 556", + "city": "Gwenborough", + "zipcode": "92998-3874", + "geo": { + "lat": "-37.3159", + "lng": "81.1496" + } + }, + "phone": "1-770-736-8031 x56442", + "website": "hildegard.org", + "company": { + "name": "Romaguera-Crona", + "catchPhrase": "Multi-layered client-server neural-net", + "bs": "harness real-time e-markets" + } + }, + { + "id": 2, + "name": "Ervin Howell", + "username": "Antonette", + "email": "Shanna@melissa.tv", + "address": { + "street": "Victor Plains", + "suite": "Suite 879", + "city": "Wisokyburgh", + "zipcode": "90566-7771", + "geo": { + "lat": "-43.9509", + "lng": "-34.4618" + } + }, + "phone": "010-692-6593 x09125", + "website": "anastasia.net", + "company": { + "name": "Deckow-Crist", + "catchPhrase": "Proactive didactic contingency", + "bs": "synergize scalable supply-chains" + } + }, + { + "id": 3, + "name": "Clementine Bauch", + "username": "Samantha", + "email": "Nathan@yesenia.net", + "address": { + "street": "Douglas Extension", + "suite": "Suite 847", + "city": "McKenziehaven", + "zipcode": "59590-4157", + "geo": { + "lat": "-68.6102", + "lng": "-47.0653" + } + }, + "phone": "1-463-123-4447", + "website": "ramiro.info", + "company": { + "name": "Romaguera-Jacobson", + "catchPhrase": "Face to face bifurcated interface", + "bs": "e-enable strategic applications" + } + }, + { + "id": 4, + "name": "Patricia Lebsack", + "username": "Karianne", + "email": "Julianne.OConner@kory.org", + "address": { + "street": "Hoeger Mall", + "suite": "Apt. 692", + "city": "South Elvis", + "zipcode": "53919-4257", + "geo": { + "lat": "29.4572", + "lng": "-164.2990" + } + }, + "phone": "493-170-9623 x156", + "website": "kale.biz", + "company": { + "name": "Robel-Corkery", + "catchPhrase": "Multi-tiered zero tolerance productivity", + "bs": "transition cutting-edge web services" + } + }, + { + "id": 5, + "name": "Chelsey Dietrich", + "username": "Kamren", + "email": "Lucio_Hettinger@annie.ca", + "address": { + "street": "Skiles Walks", + "suite": "Suite 351", + "city": "Roscoeview", + "zipcode": "33263", + "geo": { + "lat": "-31.8129", + "lng": "62.5342" + } + }, + "phone": "(254)954-1289", + "website": "demarco.info", + "company": { + "name": "Keebler LLC", + "catchPhrase": "User-centric fault-tolerant solution", + "bs": "revolutionize end-to-end systems" + } + }, + { + "id": 6, + "name": "Mrs. Dennis Schulist", + "username": "Leopoldo_Corkery", + "email": "Karley_Dach@jasper.info", + "address": { + "street": "Norberto Crossing", + "suite": "Apt. 950", + "city": "South Christy", + "zipcode": "23505-1337", + "geo": { + "lat": "-71.4197", + "lng": "71.7478" + } + }, + "phone": "1-477-935-8478 x6430", + "website": "ola.org", + "company": { + "name": "Considine-Lockman", + "catchPhrase": "Synchronised bottom-line interface", + "bs": "e-enable innovative applications" + } + }, + { + "id": 7, + "name": "Kurtis Weissnat", + "username": "Elwyn.Skiles", + "email": "Telly.Hoeger@billy.biz", + "address": { + "street": "Rex Trail", + "suite": "Suite 280", + "city": "Howemouth", + "zipcode": "58804-1099", + "geo": { + "lat": "24.8918", + "lng": "21.8984" + } + }, + "phone": "210.067.6132", + "website": "elvis.io", + "company": { + "name": "Johns Group", + "catchPhrase": "Configurable multimedia task-force", + "bs": "generate enterprise e-tailers" + } + }, + { + "id": 8, + "name": "Nicholas Runolfsdottir V", + "username": "Maxime_Nienow", + "email": "Sherwood@rosamond.me", + "address": { + "street": "Ellsworth Summit", + "suite": "Suite 729", + "city": "Aliyaview", + "zipcode": "45169", + "geo": { + "lat": "-14.3990", + "lng": "-120.7677" + } + }, + "phone": "586.493.6943 x140", + "website": "jacynthe.com", + "company": { + "name": "Abernathy Group", + "catchPhrase": "Implemented secondary concept", + "bs": "e-enable extensible e-tailers" + } + }, + { + "id": 9, + "name": "Glenna Reichert", + "username": "Delphine", + "email": "Chaim_McDermott@dana.io", + "address": { + "street": "Dayna Park", + "suite": "Suite 449", + "city": "Bartholomebury", + "zipcode": "76495-3109", + "geo": { + "lat": "24.6463", + "lng": "-168.8889" + } + }, + "phone": "(775)976-6794 x41206", + "website": "conrad.com", + "company": { + "name": "Yost and Sons", + "catchPhrase": "Switchable contextually-based project", + "bs": "aggregate real-time technologies" + } + }, + { + "id": 10, + "name": "Clementina DuBuque", + "username": "Moriah.Stanton", + "email": "Rey.Padberg@karina.biz", + "address": { + "street": "Kattie Turnpike", + "suite": "Suite 198", + "city": "Lebsackbury", + "zipcode": "31428-2261", + "geo": { + "lat": "-38.2386", + "lng": "57.2232" + } + }, + "phone": "024-648-3804", + "website": "ambrose.net", + "company": { + "name": "Hoeger LLC", + "catchPhrase": "Centralized empowering task-force", + "bs": "target end-to-end models" + } + } +] \ No newline at end of file diff --git a/wizard-work/ledger/USERS-extraction.md b/wizard-work/ledger/USERS-extraction.md new file mode 100644 index 0000000..1efb04c --- /dev/null +++ b/wizard-work/ledger/USERS-extraction.md @@ -0,0 +1,45 @@ +# Ledger — JSONPlaceholder /users extraction (2026-10-23) + +## What landed +A finished data-extraction artifact: the public `https://jsonplaceholder.typicode.com/users` +table (10 records) pulled into a normalized CSV table, a Markdown table, a JSON blob, +and the raw HTTP response used as ground truth. + +## Real tool call +- `fetch` via `urllib.request` (Python stdlib, no third-party deps) against the live + endpoint. HTTP 200, 5645 bytes received (verified in `2026-10-23-jpv-users.raw.json`). +- No auth, no paywall, no paid credits (free-tier only). + +## Artifact files (primary location) +- `/root/.hermes/wizard-outputs/ledger/2026-10-23-jpv-users.raw.json` — untouched response body (ground truth) +- `/root/.hermes/wizard-outputs/ledger/2026-10-23-jpv-users.csv` — normalized table (8 columns) +- `/root/.hermes/wizard-outputs/ledger/2026-10-23-jpv-users.md` — Markdown table +- `/root/.hermes/wizard-outputs/ledger/2026-10-23-jpv-users.json` — normalized records +- `/root/.hermes/wizard-outputs/ledger/extract_jpv_users.py` — extraction script (provenance of the transform) + +Committed next to this file in the troupe repo at +`/root/troupe-standup/wizard-work/ledger/`. + +## Method +For each of the 10 records, the script flattens the nested `address` and `company` +objects into flat columns and writes CSV + Markdown table + JSON. + +## Verification (the CHECK) +Run: +``` +python3 /root/troupe-standup/wizard-work/ledger/verify_users.py +``` +It asserts: header row is exactly the 8 expected columns; exactly 10 data rows; and three +spot rows (ids 1, 3, 10) match values re-derivable from the fetched response. + +Result (exit code): **0** — +`OK: header exact, 10 rows, 3 spot rows verified` + +## Spot-checked rows (from the fetched data) +- id 1: Leanne Graham / Bret / Sincere@april.biz / Gwenborough / hildegard.org / Romaguera-Crona +- id 3: Clementine Bauch / Samantha / Nathan@yesenia.net / McKenziehaven / ramiro.info / Romaguera-Jacobson +- id 10: Clementina DuBuque / Moriah.Stanton / Rey.Padberg@karina.biz / Lebsackbury / ambrose.net / Hoeger LLC + +## Notes +- The `CHECK:` line above is the machine-enforced completion condition (Ralph loop); it + exits 0 on the committed artifact and non-zero on any mismatch. diff --git a/wizard-work/ledger/extract_jpv_users.py b/wizard-work/ledger/extract_jpv_users.py new file mode 100644 index 0000000..0498270 --- /dev/null +++ b/wizard-work/ledger/extract_jpv_users.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""Extract the JSONPlaceholder /users table (10 records) into structured files. + +Real tool call: urllib.request against a live public endpoint (no auth, no +paywall, no paid credits). Produces raw JSON, a CSV table, a Markdown table, +and a normalised JSON blob. + +Output (in /root/.hermes/wizard-outputs/ledger/): + 2026-10-23-jpv-users.raw.json - untouched HTTP response body + 2026-10-23-jpv-users.csv - normalised table (8 columns) + 2026-10-23-jpv-users.md - Markdown table + 2026-10-23-jpv-users.json - normalised records (JSON) +""" +import csv +import json +import os +import urllib.request + +SRC = "https://jsonplaceholder.typicode.com/users" +OUTDIR = "/root/.hermes/wizard-outputs/ledger" +RAW = os.path.join(OUTDIR, "2026-10-23-jpv-users.raw.json") +CSV = os.path.join(OUTDIR, "2026-10-23-jpv-users.csv") +MD = os.path.join(OUTDIR, "2026-10-23-jpv-users.md") +JSOUT = os.path.join(OUTDIR, "2026-10-23-jpv-users.json") + +FIELDS = ["id", "name", "username", "email", "city", "phone", "website", "company"] + + +def fetch(): + req = urllib.request.Request( + SRC, headers={"User-Agent": "ledger-extract/1.0"} + ) + with urllib.request.urlopen(req, timeout=30) as r: + return r.read().decode("utf-8") + + +def main(): + os.makedirs(OUTDIR, exist_ok=True) + raw = fetch() + with open(RAW, "w") as f: + f.write(raw) + + recs = json.loads(raw) + rows = [] + for rec in recs: + addr = rec.get("address") or {} + comp = rec.get("company") or {} + rows.append({ + "id": rec["id"], + "name": rec["name"], + "username": rec["username"], + "email": rec["email"], + "city": addr.get("city"), + "phone": rec["phone"], + "website": rec["website"], + "company": comp.get("name"), + }) + + with open(CSV, "w", newline="") as f: + w = csv.DictWriter(f, fieldnames=FIELDS) + w.writeheader() + w.writerows(rows) + + lines = [ + "| id | name | username | email | city | phone | website | company |", + "|---|---|---|---|---|---|---|---|", + ] + for r in rows: + lines.append("| " + " | ".join(str(r[c]) for c in FIELDS) + " |") + with open(MD, "w") as f: + f.write("\n".join(lines) + "\n") + + with open(JSOUT, "w") as f: + json.dump(rows, f, indent=2) + + print("fetched", len(rows), "users from", SRC) + print("raw:", RAW) + print("csv:", CSV) + print("md:", MD) + print("json:", JSOUT) + + +if __name__ == "__main__": + main() diff --git a/wizard-work/ledger/verify_users.py b/wizard-work/ledger/verify_users.py new file mode 100644 index 0000000..ef9b73c --- /dev/null +++ b/wizard-work/ledger/verify_users.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +"""CHECK — verify the JSONPlaceholder /users extraction artifact. + +Reads users.csv (defaults to the committed copy in the troupe repo) and +asserts: + * header row is exactly the 8 expected columns + * there are exactly 10 data rows + * three spot rows match values re-derivable from the HTTP response + +Exit 0 only if every assertion holds; non-zero otherwise. +""" +import csv +import sys + +# Committed artifact path (what ships to the repo). +DEFAULT_CSV = "/root/troupe-standup/wizard-work/ledger/2026-10-23-jpv-users.csv" + +HEADER = ["id", "name", "username", "email", "city", "phone", "website", "company"] + +# (name, username, email, city, website, company) +EXPECTED = { + "1": ("Leanne Graham", "Bret", "Sincere@april.biz", "Gwenborough", + "hildegard.org", "Romaguera-Crona"), + "3": ("Clementine Bauch", "Samantha", "Nathan@yesenia.net", + "McKenziehaven", "ramiro.info", "Romaguera-Jacobson"), + "10": ("Clementina DuBuque", "Moriah.Stanton", "Rey.Padberg@karina.biz", + "Lebsackbury", "ambrose.net", "Hoeger LLC"), +} + + +def main(): + csv_path = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_CSV + with open(csv_path, newline="") as f: + reader = csv.DictReader(f) + if reader.fieldnames != HEADER: + print("HEADER MISMATCH: got %r" % (reader.fieldnames,)) + return 1 + rows = list(reader) + + if len(rows) != 10: + print("ROW COUNT MISMATCH: %d" % len(rows)) + return 1 + + for r in rows: + key = r["id"] + if key in EXPECTED: + want = EXPECTED[key] + got = (r["name"], r["username"], r["email"], r["city"], + r["website"], r["company"]) + if got != want: + print("ROW %s MISMATCH: got %r want %r" % (key, got, want)) + return 1 + print("OK: header exact, 10 rows, 3 spot rows verified") + return 0 + + +if __name__ == "__main__": + sys.exit(main())