ledger: JSONPlaceholder /users extraction (10 records) -> csv/md/json

This commit is contained in:
ledger committed 2026-10-23 12:26:06 +00:00
1 parent 2d0dda600f
commit cc3b45975f
7 files changed
+544

No files matched your search

@@ -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
1 id name username email city phone website company
2 1 Leanne Graham Bret Sincere@april.biz Gwenborough 1-770-736-8031 x56442 hildegard.org Romaguera-Crona
3 2 Ervin Howell Antonette Shanna@melissa.tv Wisokyburgh 010-692-6593 x09125 anastasia.net Deckow-Crist
4 3 Clementine Bauch Samantha Nathan@yesenia.net McKenziehaven 1-463-123-4447 ramiro.info Romaguera-Jacobson
5 4 Patricia Lebsack Karianne Julianne.OConner@kory.org South Elvis 493-170-9623 x156 kale.biz Robel-Corkery
6 5 Chelsey Dietrich Kamren Lucio_Hettinger@annie.ca Roscoeview (254)954-1289 demarco.info Keebler LLC
7 6 Mrs. Dennis Schulist Leopoldo_Corkery Karley_Dach@jasper.info South Christy 1-477-935-8478 x6430 ola.org Considine-Lockman
8 7 Kurtis Weissnat Elwyn.Skiles Telly.Hoeger@billy.biz Howemouth 210.067.6132 elvis.io Johns Group
9 8 Nicholas Runolfsdottir V Maxime_Nienow Sherwood@rosamond.me Aliyaview 586.493.6943 x140 jacynthe.com Abernathy Group
10 9 Glenna Reichert Delphine Chaim_McDermott@dana.io Bartholomebury (775)976-6794 x41206 conrad.com Yost and Sons
11 10 Clementina DuBuque Moriah.Stanton Rey.Padberg@karina.biz Lebsackbury 024-648-3804 ambrose.net Hoeger LLC
@@ -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"
}
]
@@ -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 |
@@ -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"
}
}
]
+45
View File
@@ -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.
+84
View File
@@ -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()
+58
View File
@@ -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())