From 71984766129b9ab047c5df739b9bda86e9f63e68 Mon Sep 17 00:00:00 2001 From: ledger Date: Sun, 1 Nov 2026 07:21:26 +0000 Subject: [PATCH] ledger: todo-census extraction from JSONPlaceholder /todos --- .../ledger/2026-11-01-todo-census/CHECK | 5 + .../extract_todo_census.py | 128 ++++++++++ .../todo-census-2026-11-01.csv | 201 ++++++++++++++++ .../todo-census-2026-11-01.md | 227 ++++++++++++++++++ .../verify_todo_census.py | 74 ++++++ 5 files changed, 635 insertions(+) create mode 100644 wizard-work/ledger/2026-11-01-todo-census/CHECK create mode 100644 wizard-work/ledger/2026-11-01-todo-census/extract_todo_census.py create mode 100644 wizard-work/ledger/2026-11-01-todo-census/todo-census-2026-11-01.csv create mode 100644 wizard-work/ledger/2026-11-01-todo-census/todo-census-2026-11-01.md create mode 100644 wizard-work/ledger/2026-11-01-todo-census/verify_todo_census.py diff --git a/wizard-work/ledger/2026-11-01-todo-census/CHECK b/wizard-work/ledger/2026-11-01-todo-census/CHECK new file mode 100644 index 0000000..18ffe21 --- /dev/null +++ b/wizard-work/ledger/2026-11-01-todo-census/CHECK @@ -0,0 +1,5 @@ +# VERDICT CHECK for 2026-11-01-todo-census + +Single bare command whose exit code is the verdict (0 = correct, nonzero = wrong): + + python3 verify_todo_census.py diff --git a/wizard-work/ledger/2026-11-01-todo-census/extract_todo_census.py b/wizard-work/ledger/2026-11-01-todo-census/extract_todo_census.py new file mode 100644 index 0000000..7f314df --- /dev/null +++ b/wizard-work/ledger/2026-11-01-todo-census/extract_todo_census.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +"""Extract the JSONPlaceholder /todos collection into a pipe-delimited CSV and a +markdown census table, then print a summary so the fetch result is observable. + +Source: https://jsonplaceholder.typicode.com/todos +Fetched live at run time (no hardcoded values). +""" +import csv +import json +import sys +from datetime import date, datetime, timezone +from urllib.request import urlopen +from urllib.error import URLError + +API_URL = "https://jsonplaceholder.typicode.com/todos" +OUT_DIR = "/root/troupe-standup/wizard-work/ledger/2026-11-01-todo-census" +CSV_NAME = "todo-census-2026-11-01.csv" +MD_NAME = "todo-census-2026-11-01.md" + + +def fetch(path): + req = urlopen(path, timeout=30) + raw = req.read() + try: + return json.loads(raw.decode("utf-8")) + finally: + req.close() + + +def build_csv(rows): + """Pipe-delimited CSV: id|user_id|title|completed""" + lines = ["id|user_id|title|completed"] + for r in rows: + lines.append("|".join([ + str(r["id"]), + str(r["userId"]), + r["title"], + "1" if r["completed"] else "0", + ])) + return lines + + +def build_md(rows, stats): + """Markdown table + census summary block.""" + total = stats["total"] + done = stats["completed"] + pend = stats["pending"] + lines = [ + "# JSONPlaceholder /todos extraction census", + "", + f"Fetched {date.today().isoformat()} (run {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%SZ')}) from " + f"{API_URL}. Record count: {total}.", + "", + "| id | user_id | title | completed |", + "|---|---|---|---|", + ] + for r in rows: + lines.append( + f"| {r['id']} | {r['userId']} | {r['title']} | {'yes' if r['completed'] else 'no'} |" + ) + lines += [ + "", + "## Census summary", + "", + f"| total | completed | pending |", + f"|---|---|---|", + f"| {total} | {done} | {pend} |", + "", + "## Per-user completion rate", + "", + "| user_id | tasks | completed | rate |", + "|---|---|---|---|", + ] + by_user = {} + for r in rows: + u = by_user.setdefault(r["userId"], {"n": 0, "d": 0}) + u["n"] += 1 + if r["completed"]: + u["d"] += 1 + for uid in sorted(by_user): + u = by_user[uid] + rate = u["d"] / u["n"] + lines.append(f"| {uid} | {u['n']} | {u['d']} | {rate:.2f} |") + return "\n".join(lines) + "\n" + + +def main(): + try: + data = fetch(API_URL) + except URLError as e: + print(f"FETCH ERROR: {e}", file=sys.stderr) + sys.exit(1) + except (ValueError, UnicodeDecodeError) as e: + print(f"PARSE ERROR: {e}", file=sys.stderr) + sys.exit(1) + + if not isinstance(data, list): + print(f"UNEXPECTED SHAPE: {type(data).__name__}", file=sys.stderr) + sys.exit(1) + + rows = [] + for item in data: + if not all(k in item for k in ("id", "userId", "title", "completed")): + print(f"SKIPPING MALFORMED ROW: {item!r}", file=sys.stderr) + continue + rows.append(item) + + stats = { + "total": len(rows), + "completed": sum(1 for r in rows if r["completed"]), + "pending": sum(1 for r in rows if not r["completed"]), + } + csv_text = "\n".join(build_csv(rows)) + "\n" + md_text = build_md(rows, stats) + + with open(f"{OUT_DIR}/{CSV_NAME}", "w", encoding="utf-8") as f: + f.write(csv_text) + with open(f"{OUT_DIR}/{MD_NAME}", "w", encoding="utf-8") as f: + f.write(md_text) + + print(f"OK: fetched {len(rows)} rows from {API_URL}") + print(f" total={stats['total']} completed={stats['completed']} pending={stats['pending']}") + print(f" wrote {OUT_DIR}/{CSV_NAME}") + print(f" wrote {OUT_DIR}/{MD_NAME}") + + +if __name__ == "__main__": + main() diff --git a/wizard-work/ledger/2026-11-01-todo-census/todo-census-2026-11-01.csv b/wizard-work/ledger/2026-11-01-todo-census/todo-census-2026-11-01.csv new file mode 100644 index 0000000..1b0ff76 --- /dev/null +++ b/wizard-work/ledger/2026-11-01-todo-census/todo-census-2026-11-01.csv @@ -0,0 +1,201 @@ +id|user_id|title|completed +1|1|delectus aut autem|0 +2|1|quis ut nam facilis et officia qui|0 +3|1|fugiat veniam minus|0 +4|1|et porro tempora|1 +5|1|laboriosam mollitia et enim quasi adipisci quia provident illum|0 +6|1|qui ullam ratione quibusdam voluptatem quia omnis|0 +7|1|illo expedita consequatur quia in|0 +8|1|quo adipisci enim quam ut ab|1 +9|1|molestiae perspiciatis ipsa|0 +10|1|illo est ratione doloremque quia maiores aut|1 +11|1|vero rerum temporibus dolor|1 +12|1|ipsa repellendus fugit nisi|1 +13|1|et doloremque nulla|0 +14|1|repellendus sunt dolores architecto voluptatum|1 +15|1|ab voluptatum amet voluptas|1 +16|1|accusamus eos facilis sint et aut voluptatem|1 +17|1|quo laboriosam deleniti aut qui|1 +18|1|dolorum est consequatur ea mollitia in culpa|0 +19|1|molestiae ipsa aut voluptatibus pariatur dolor nihil|1 +20|1|ullam nobis libero sapiente ad optio sint|1 +21|2|suscipit repellat esse quibusdam voluptatem incidunt|0 +22|2|distinctio vitae autem nihil ut molestias quo|1 +23|2|et itaque necessitatibus maxime molestiae qui quas velit|0 +24|2|adipisci non ad dicta qui amet quaerat doloribus ea|0 +25|2|voluptas quo tenetur perspiciatis explicabo natus|1 +26|2|aliquam aut quasi|1 +27|2|veritatis pariatur delectus|1 +28|2|nesciunt totam sit blanditiis sit|0 +29|2|laborum aut in quam|0 +30|2|nemo perspiciatis repellat ut dolor libero commodi blanditiis omnis|1 +31|2|repudiandae totam in est sint facere fuga|0 +32|2|earum doloribus ea doloremque quis|0 +33|2|sint sit aut vero|0 +34|2|porro aut necessitatibus eaque distinctio|0 +35|2|repellendus veritatis molestias dicta incidunt|1 +36|2|excepturi deleniti adipisci voluptatem et neque optio illum ad|1 +37|2|sunt cum tempora|0 +38|2|totam quia non|0 +39|2|doloremque quibusdam asperiores libero corrupti illum qui omnis|0 +40|2|totam atque quo nesciunt|1 +41|3|aliquid amet impedit consequatur aspernatur placeat eaque fugiat suscipit|0 +42|3|rerum perferendis error quia ut eveniet|0 +43|3|tempore ut sint quis recusandae|1 +44|3|cum debitis quis accusamus doloremque ipsa natus sapiente omnis|1 +45|3|velit soluta adipisci molestias reiciendis harum|0 +46|3|vel voluptatem repellat nihil placeat corporis|0 +47|3|nam qui rerum fugiat accusamus|0 +48|3|sit reprehenderit omnis quia|0 +49|3|ut necessitatibus aut maiores debitis officia blanditiis velit et|0 +50|3|cupiditate necessitatibus ullam aut quis dolor voluptate|1 +51|3|distinctio exercitationem ab doloribus|0 +52|3|nesciunt dolorum quis recusandae ad pariatur ratione|0 +53|3|qui labore est occaecati recusandae aliquid quam|0 +54|3|quis et est ut voluptate quam dolor|1 +55|3|voluptatum omnis minima qui occaecati provident nulla voluptatem ratione|1 +56|3|deleniti ea temporibus enim|1 +57|3|pariatur et magnam ea doloribus similique voluptatem rerum quia|0 +58|3|est dicta totam qui explicabo doloribus qui dignissimos|0 +59|3|perspiciatis velit id laborum placeat iusto et aliquam odio|0 +60|3|et sequi qui architecto ut adipisci|1 +61|4|odit optio omnis qui sunt|1 +62|4|et placeat et tempore aspernatur sint numquam|0 +63|4|doloremque aut dolores quidem fuga qui nulla|1 +64|4|voluptas consequatur qui ut quia magnam nemo esse|0 +65|4|fugiat pariatur ratione ut asperiores necessitatibus magni|0 +66|4|rerum eum molestias autem voluptatum sit optio|0 +67|4|quia voluptatibus voluptatem quos similique maiores repellat|0 +68|4|aut id perspiciatis voluptatem iusto|0 +69|4|doloribus sint dolorum ab adipisci itaque dignissimos aliquam suscipit|0 +70|4|ut sequi accusantium et mollitia delectus sunt|0 +71|4|aut velit saepe ullam|0 +72|4|praesentium facilis facere quis harum voluptatibus voluptatem eum|0 +73|4|sint amet quia totam corporis qui exercitationem commodi|1 +74|4|expedita tempore nobis eveniet laborum maiores|0 +75|4|occaecati adipisci est possimus totam|0 +76|4|sequi dolorem sed|1 +77|4|maiores aut nesciunt delectus exercitationem vel assumenda eligendi at|0 +78|4|reiciendis est magnam amet nemo iste recusandae impedit quaerat|0 +79|4|eum ipsa maxime ut|1 +80|4|tempore molestias dolores rerum sequi voluptates ipsum consequatur|1 +81|5|suscipit qui totam|1 +82|5|voluptates eum voluptas et dicta|0 +83|5|quidem at rerum quis ex aut sit quam|1 +84|5|sunt veritatis ut voluptate|0 +85|5|et quia ad iste a|1 +86|5|incidunt ut saepe autem|1 +87|5|laudantium quae eligendi consequatur quia et vero autem|1 +88|5|vitae aut excepturi laboriosam sint aliquam et et accusantium|0 +89|5|sequi ut omnis et|1 +90|5|molestiae nisi accusantium tenetur dolorem et|1 +91|5|nulla quis consequatur saepe qui id expedita|1 +92|5|in omnis laboriosam|1 +93|5|odio iure consequatur molestiae quibusdam necessitatibus quia sint|1 +94|5|facilis modi saepe mollitia|0 +95|5|vel nihil et molestiae iusto assumenda nemo quo ut|1 +96|5|nobis suscipit ducimus enim asperiores voluptas|0 +97|5|dolorum laboriosam eos qui iure aliquam|0 +98|5|debitis accusantium ut quo facilis nihil quis sapiente necessitatibus|1 +99|5|neque voluptates ratione|0 +100|5|excepturi a et neque qui expedita vel voluptate|0 +101|6|explicabo enim cumque porro aperiam occaecati minima|0 +102|6|sed ab consequatur|0 +103|6|non sunt delectus illo nulla tenetur enim omnis|0 +104|6|excepturi non laudantium quo|0 +105|6|totam quia dolorem et illum repellat voluptas optio|1 +106|6|ad illo quis voluptatem temporibus|1 +107|6|praesentium facilis omnis laudantium fugit ad iusto nihil nesciunt|0 +108|6|a eos eaque nihil et exercitationem incidunt delectus|1 +109|6|autem temporibus harum quisquam in culpa|1 +110|6|aut aut ea corporis|1 +111|6|magni accusantium labore et id quis provident|0 +112|6|consectetur impedit quisquam qui deserunt non rerum consequuntur eius|0 +113|6|quia atque aliquam sunt impedit voluptatum rerum assumenda nisi|0 +114|6|cupiditate quos possimus corporis quisquam exercitationem beatae|0 +115|6|sed et ea eum|0 +116|6|ipsa dolores vel facilis ut|1 +117|6|sequi quae est et qui qui eveniet asperiores|0 +118|6|quia modi consequatur vero fugiat|0 +119|6|corporis ducimus ea perspiciatis iste|0 +120|6|dolorem laboriosam vel voluptas et aliquam quasi|0 +121|7|inventore aut nihil minima laudantium hic qui omnis|1 +122|7|provident aut nobis culpa|1 +123|7|esse et quis iste est earum aut impedit|0 +124|7|qui consectetur id|0 +125|7|aut quasi autem iste tempore illum possimus|0 +126|7|ut asperiores perspiciatis veniam ipsum rerum saepe|1 +127|7|voluptatem libero consectetur rerum ut|1 +128|7|eius omnis est qui voluptatem autem|0 +129|7|rerum culpa quis harum|0 +130|7|nulla aliquid eveniet harum laborum libero alias ut unde|1 +131|7|qui ea incidunt quis|0 +132|7|qui molestiae voluptatibus velit iure harum quisquam|1 +133|7|et labore eos enim rerum consequatur sunt|1 +134|7|molestiae doloribus et laborum quod ea|0 +135|7|facere ipsa nam eum voluptates reiciendis vero qui|0 +136|7|asperiores illo tempora fuga sed ut quasi adipisci|0 +137|7|qui sit non|0 +138|7|placeat minima consequatur rem qui ut|1 +139|7|consequatur doloribus id possimus voluptas a voluptatem|0 +140|7|aut consectetur in blanditiis deserunt quia sed laboriosam|1 +141|8|explicabo consectetur debitis voluptates quas quae culpa rerum non|1 +142|8|maiores accusantium architecto necessitatibus reiciendis ea aut|1 +143|8|eum non recusandae cupiditate animi|0 +144|8|ut eum exercitationem sint|0 +145|8|beatae qui ullam incidunt voluptatem non nisi aliquam|0 +146|8|molestiae suscipit ratione nihil odio libero impedit vero totam|1 +147|8|eum itaque quod reprehenderit et facilis dolor autem ut|1 +148|8|esse quas et quo quasi exercitationem|0 +149|8|animi voluptas quod perferendis est|0 +150|8|eos amet tempore laudantium fugit a|0 +151|8|accusamus adipisci dicta qui quo ea explicabo sed vero|1 +152|8|odit eligendi recusandae doloremque cumque non|0 +153|8|ea aperiam consequatur qui repellat eos|0 +154|8|rerum non ex sapiente|1 +155|8|voluptatem nobis consequatur et assumenda magnam|1 +156|8|nam quia quia nulla repellat assumenda quibusdam sit nobis|1 +157|8|dolorem veniam quisquam deserunt repellendus|1 +158|8|debitis vitae delectus et harum accusamus aut deleniti a|1 +159|8|debitis adipisci quibusdam aliquam sed dolore ea praesentium nobis|1 +160|8|et praesentium aliquam est|0 +161|9|ex hic consequuntur earum omnis alias ut occaecati culpa|1 +162|9|omnis laboriosam molestias animi sunt dolore|1 +163|9|natus corrupti maxime laudantium et voluptatem laboriosam odit|0 +164|9|reprehenderit quos aut aut consequatur est sed|0 +165|9|fugiat perferendis sed aut quidem|0 +166|9|quos quo possimus suscipit minima ut|0 +167|9|et quis minus quo a asperiores molestiae|0 +168|9|recusandae quia qui sunt libero|0 +169|9|ea odio perferendis officiis|1 +170|9|quisquam aliquam quia doloribus aut|0 +171|9|fugiat aut voluptatibus corrupti deleniti velit iste odio|1 +172|9|et provident amet rerum consectetur et voluptatum|0 +173|9|harum ad aperiam quis|0 +174|9|similique aut quo|0 +175|9|laudantium eius officia perferendis provident perspiciatis asperiores|1 +176|9|magni soluta corrupti ut maiores rem quidem|0 +177|9|et placeat temporibus voluptas est tempora quos quibusdam|0 +178|9|nesciunt itaque commodi tempore|1 +179|9|omnis consequuntur cupiditate impedit itaque ipsam quo|1 +180|9|debitis nisi et dolorem repellat et|1 +181|10|ut cupiditate sequi aliquam fuga maiores|0 +182|10|inventore saepe cumque et aut illum enim|1 +183|10|omnis nulla eum aliquam distinctio|1 +184|10|molestias modi perferendis perspiciatis|0 +185|10|voluptates dignissimos sed doloribus animi quaerat aut|0 +186|10|explicabo odio est et|0 +187|10|consequuntur animi possimus|0 +188|10|vel non beatae est|1 +189|10|culpa eius et voluptatem et|1 +190|10|accusamus sint iusto et voluptatem exercitationem|1 +191|10|temporibus atque distinctio omnis eius impedit tempore molestias pariatur|1 +192|10|ut quas possimus exercitationem sint voluptates|0 +193|10|rerum debitis voluptatem qui eveniet tempora distinctio a|1 +194|10|sed ut vero sit molestiae|0 +195|10|rerum ex veniam mollitia voluptatibus pariatur|1 +196|10|consequuntur aut ut fugit similique|1 +197|10|dignissimos quo nobis earum saepe|1 +198|10|quis eius est sint explicabo|1 +199|10|numquam repellendus a magnam|1 +200|10|ipsam aperiam voluptates qui|0 diff --git a/wizard-work/ledger/2026-11-01-todo-census/todo-census-2026-11-01.md b/wizard-work/ledger/2026-11-01-todo-census/todo-census-2026-11-01.md new file mode 100644 index 0000000..79aff5f --- /dev/null +++ b/wizard-work/ledger/2026-11-01-todo-census/todo-census-2026-11-01.md @@ -0,0 +1,227 @@ +# JSONPlaceholder /todos extraction census + +Fetched 2026-11-01 (run 2026-11-01 07:19:40Z) from https://jsonplaceholder.typicode.com/todos. Record count: 200. + +| id | user_id | title | completed | +|---|---|---|---| +| 1 | 1 | delectus aut autem | no | +| 2 | 1 | quis ut nam facilis et officia qui | no | +| 3 | 1 | fugiat veniam minus | no | +| 4 | 1 | et porro tempora | yes | +| 5 | 1 | laboriosam mollitia et enim quasi adipisci quia provident illum | no | +| 6 | 1 | qui ullam ratione quibusdam voluptatem quia omnis | no | +| 7 | 1 | illo expedita consequatur quia in | no | +| 8 | 1 | quo adipisci enim quam ut ab | yes | +| 9 | 1 | molestiae perspiciatis ipsa | no | +| 10 | 1 | illo est ratione doloremque quia maiores aut | yes | +| 11 | 1 | vero rerum temporibus dolor | yes | +| 12 | 1 | ipsa repellendus fugit nisi | yes | +| 13 | 1 | et doloremque nulla | no | +| 14 | 1 | repellendus sunt dolores architecto voluptatum | yes | +| 15 | 1 | ab voluptatum amet voluptas | yes | +| 16 | 1 | accusamus eos facilis sint et aut voluptatem | yes | +| 17 | 1 | quo laboriosam deleniti aut qui | yes | +| 18 | 1 | dolorum est consequatur ea mollitia in culpa | no | +| 19 | 1 | molestiae ipsa aut voluptatibus pariatur dolor nihil | yes | +| 20 | 1 | ullam nobis libero sapiente ad optio sint | yes | +| 21 | 2 | suscipit repellat esse quibusdam voluptatem incidunt | no | +| 22 | 2 | distinctio vitae autem nihil ut molestias quo | yes | +| 23 | 2 | et itaque necessitatibus maxime molestiae qui quas velit | no | +| 24 | 2 | adipisci non ad dicta qui amet quaerat doloribus ea | no | +| 25 | 2 | voluptas quo tenetur perspiciatis explicabo natus | yes | +| 26 | 2 | aliquam aut quasi | yes | +| 27 | 2 | veritatis pariatur delectus | yes | +| 28 | 2 | nesciunt totam sit blanditiis sit | no | +| 29 | 2 | laborum aut in quam | no | +| 30 | 2 | nemo perspiciatis repellat ut dolor libero commodi blanditiis omnis | yes | +| 31 | 2 | repudiandae totam in est sint facere fuga | no | +| 32 | 2 | earum doloribus ea doloremque quis | no | +| 33 | 2 | sint sit aut vero | no | +| 34 | 2 | porro aut necessitatibus eaque distinctio | no | +| 35 | 2 | repellendus veritatis molestias dicta incidunt | yes | +| 36 | 2 | excepturi deleniti adipisci voluptatem et neque optio illum ad | yes | +| 37 | 2 | sunt cum tempora | no | +| 38 | 2 | totam quia non | no | +| 39 | 2 | doloremque quibusdam asperiores libero corrupti illum qui omnis | no | +| 40 | 2 | totam atque quo nesciunt | yes | +| 41 | 3 | aliquid amet impedit consequatur aspernatur placeat eaque fugiat suscipit | no | +| 42 | 3 | rerum perferendis error quia ut eveniet | no | +| 43 | 3 | tempore ut sint quis recusandae | yes | +| 44 | 3 | cum debitis quis accusamus doloremque ipsa natus sapiente omnis | yes | +| 45 | 3 | velit soluta adipisci molestias reiciendis harum | no | +| 46 | 3 | vel voluptatem repellat nihil placeat corporis | no | +| 47 | 3 | nam qui rerum fugiat accusamus | no | +| 48 | 3 | sit reprehenderit omnis quia | no | +| 49 | 3 | ut necessitatibus aut maiores debitis officia blanditiis velit et | no | +| 50 | 3 | cupiditate necessitatibus ullam aut quis dolor voluptate | yes | +| 51 | 3 | distinctio exercitationem ab doloribus | no | +| 52 | 3 | nesciunt dolorum quis recusandae ad pariatur ratione | no | +| 53 | 3 | qui labore est occaecati recusandae aliquid quam | no | +| 54 | 3 | quis et est ut voluptate quam dolor | yes | +| 55 | 3 | voluptatum omnis minima qui occaecati provident nulla voluptatem ratione | yes | +| 56 | 3 | deleniti ea temporibus enim | yes | +| 57 | 3 | pariatur et magnam ea doloribus similique voluptatem rerum quia | no | +| 58 | 3 | est dicta totam qui explicabo doloribus qui dignissimos | no | +| 59 | 3 | perspiciatis velit id laborum placeat iusto et aliquam odio | no | +| 60 | 3 | et sequi qui architecto ut adipisci | yes | +| 61 | 4 | odit optio omnis qui sunt | yes | +| 62 | 4 | et placeat et tempore aspernatur sint numquam | no | +| 63 | 4 | doloremque aut dolores quidem fuga qui nulla | yes | +| 64 | 4 | voluptas consequatur qui ut quia magnam nemo esse | no | +| 65 | 4 | fugiat pariatur ratione ut asperiores necessitatibus magni | no | +| 66 | 4 | rerum eum molestias autem voluptatum sit optio | no | +| 67 | 4 | quia voluptatibus voluptatem quos similique maiores repellat | no | +| 68 | 4 | aut id perspiciatis voluptatem iusto | no | +| 69 | 4 | doloribus sint dolorum ab adipisci itaque dignissimos aliquam suscipit | no | +| 70 | 4 | ut sequi accusantium et mollitia delectus sunt | no | +| 71 | 4 | aut velit saepe ullam | no | +| 72 | 4 | praesentium facilis facere quis harum voluptatibus voluptatem eum | no | +| 73 | 4 | sint amet quia totam corporis qui exercitationem commodi | yes | +| 74 | 4 | expedita tempore nobis eveniet laborum maiores | no | +| 75 | 4 | occaecati adipisci est possimus totam | no | +| 76 | 4 | sequi dolorem sed | yes | +| 77 | 4 | maiores aut nesciunt delectus exercitationem vel assumenda eligendi at | no | +| 78 | 4 | reiciendis est magnam amet nemo iste recusandae impedit quaerat | no | +| 79 | 4 | eum ipsa maxime ut | yes | +| 80 | 4 | tempore molestias dolores rerum sequi voluptates ipsum consequatur | yes | +| 81 | 5 | suscipit qui totam | yes | +| 82 | 5 | voluptates eum voluptas et dicta | no | +| 83 | 5 | quidem at rerum quis ex aut sit quam | yes | +| 84 | 5 | sunt veritatis ut voluptate | no | +| 85 | 5 | et quia ad iste a | yes | +| 86 | 5 | incidunt ut saepe autem | yes | +| 87 | 5 | laudantium quae eligendi consequatur quia et vero autem | yes | +| 88 | 5 | vitae aut excepturi laboriosam sint aliquam et et accusantium | no | +| 89 | 5 | sequi ut omnis et | yes | +| 90 | 5 | molestiae nisi accusantium tenetur dolorem et | yes | +| 91 | 5 | nulla quis consequatur saepe qui id expedita | yes | +| 92 | 5 | in omnis laboriosam | yes | +| 93 | 5 | odio iure consequatur molestiae quibusdam necessitatibus quia sint | yes | +| 94 | 5 | facilis modi saepe mollitia | no | +| 95 | 5 | vel nihil et molestiae iusto assumenda nemo quo ut | yes | +| 96 | 5 | nobis suscipit ducimus enim asperiores voluptas | no | +| 97 | 5 | dolorum laboriosam eos qui iure aliquam | no | +| 98 | 5 | debitis accusantium ut quo facilis nihil quis sapiente necessitatibus | yes | +| 99 | 5 | neque voluptates ratione | no | +| 100 | 5 | excepturi a et neque qui expedita vel voluptate | no | +| 101 | 6 | explicabo enim cumque porro aperiam occaecati minima | no | +| 102 | 6 | sed ab consequatur | no | +| 103 | 6 | non sunt delectus illo nulla tenetur enim omnis | no | +| 104 | 6 | excepturi non laudantium quo | no | +| 105 | 6 | totam quia dolorem et illum repellat voluptas optio | yes | +| 106 | 6 | ad illo quis voluptatem temporibus | yes | +| 107 | 6 | praesentium facilis omnis laudantium fugit ad iusto nihil nesciunt | no | +| 108 | 6 | a eos eaque nihil et exercitationem incidunt delectus | yes | +| 109 | 6 | autem temporibus harum quisquam in culpa | yes | +| 110 | 6 | aut aut ea corporis | yes | +| 111 | 6 | magni accusantium labore et id quis provident | no | +| 112 | 6 | consectetur impedit quisquam qui deserunt non rerum consequuntur eius | no | +| 113 | 6 | quia atque aliquam sunt impedit voluptatum rerum assumenda nisi | no | +| 114 | 6 | cupiditate quos possimus corporis quisquam exercitationem beatae | no | +| 115 | 6 | sed et ea eum | no | +| 116 | 6 | ipsa dolores vel facilis ut | yes | +| 117 | 6 | sequi quae est et qui qui eveniet asperiores | no | +| 118 | 6 | quia modi consequatur vero fugiat | no | +| 119 | 6 | corporis ducimus ea perspiciatis iste | no | +| 120 | 6 | dolorem laboriosam vel voluptas et aliquam quasi | no | +| 121 | 7 | inventore aut nihil minima laudantium hic qui omnis | yes | +| 122 | 7 | provident aut nobis culpa | yes | +| 123 | 7 | esse et quis iste est earum aut impedit | no | +| 124 | 7 | qui consectetur id | no | +| 125 | 7 | aut quasi autem iste tempore illum possimus | no | +| 126 | 7 | ut asperiores perspiciatis veniam ipsum rerum saepe | yes | +| 127 | 7 | voluptatem libero consectetur rerum ut | yes | +| 128 | 7 | eius omnis est qui voluptatem autem | no | +| 129 | 7 | rerum culpa quis harum | no | +| 130 | 7 | nulla aliquid eveniet harum laborum libero alias ut unde | yes | +| 131 | 7 | qui ea incidunt quis | no | +| 132 | 7 | qui molestiae voluptatibus velit iure harum quisquam | yes | +| 133 | 7 | et labore eos enim rerum consequatur sunt | yes | +| 134 | 7 | molestiae doloribus et laborum quod ea | no | +| 135 | 7 | facere ipsa nam eum voluptates reiciendis vero qui | no | +| 136 | 7 | asperiores illo tempora fuga sed ut quasi adipisci | no | +| 137 | 7 | qui sit non | no | +| 138 | 7 | placeat minima consequatur rem qui ut | yes | +| 139 | 7 | consequatur doloribus id possimus voluptas a voluptatem | no | +| 140 | 7 | aut consectetur in blanditiis deserunt quia sed laboriosam | yes | +| 141 | 8 | explicabo consectetur debitis voluptates quas quae culpa rerum non | yes | +| 142 | 8 | maiores accusantium architecto necessitatibus reiciendis ea aut | yes | +| 143 | 8 | eum non recusandae cupiditate animi | no | +| 144 | 8 | ut eum exercitationem sint | no | +| 145 | 8 | beatae qui ullam incidunt voluptatem non nisi aliquam | no | +| 146 | 8 | molestiae suscipit ratione nihil odio libero impedit vero totam | yes | +| 147 | 8 | eum itaque quod reprehenderit et facilis dolor autem ut | yes | +| 148 | 8 | esse quas et quo quasi exercitationem | no | +| 149 | 8 | animi voluptas quod perferendis est | no | +| 150 | 8 | eos amet tempore laudantium fugit a | no | +| 151 | 8 | accusamus adipisci dicta qui quo ea explicabo sed vero | yes | +| 152 | 8 | odit eligendi recusandae doloremque cumque non | no | +| 153 | 8 | ea aperiam consequatur qui repellat eos | no | +| 154 | 8 | rerum non ex sapiente | yes | +| 155 | 8 | voluptatem nobis consequatur et assumenda magnam | yes | +| 156 | 8 | nam quia quia nulla repellat assumenda quibusdam sit nobis | yes | +| 157 | 8 | dolorem veniam quisquam deserunt repellendus | yes | +| 158 | 8 | debitis vitae delectus et harum accusamus aut deleniti a | yes | +| 159 | 8 | debitis adipisci quibusdam aliquam sed dolore ea praesentium nobis | yes | +| 160 | 8 | et praesentium aliquam est | no | +| 161 | 9 | ex hic consequuntur earum omnis alias ut occaecati culpa | yes | +| 162 | 9 | omnis laboriosam molestias animi sunt dolore | yes | +| 163 | 9 | natus corrupti maxime laudantium et voluptatem laboriosam odit | no | +| 164 | 9 | reprehenderit quos aut aut consequatur est sed | no | +| 165 | 9 | fugiat perferendis sed aut quidem | no | +| 166 | 9 | quos quo possimus suscipit minima ut | no | +| 167 | 9 | et quis minus quo a asperiores molestiae | no | +| 168 | 9 | recusandae quia qui sunt libero | no | +| 169 | 9 | ea odio perferendis officiis | yes | +| 170 | 9 | quisquam aliquam quia doloribus aut | no | +| 171 | 9 | fugiat aut voluptatibus corrupti deleniti velit iste odio | yes | +| 172 | 9 | et provident amet rerum consectetur et voluptatum | no | +| 173 | 9 | harum ad aperiam quis | no | +| 174 | 9 | similique aut quo | no | +| 175 | 9 | laudantium eius officia perferendis provident perspiciatis asperiores | yes | +| 176 | 9 | magni soluta corrupti ut maiores rem quidem | no | +| 177 | 9 | et placeat temporibus voluptas est tempora quos quibusdam | no | +| 178 | 9 | nesciunt itaque commodi tempore | yes | +| 179 | 9 | omnis consequuntur cupiditate impedit itaque ipsam quo | yes | +| 180 | 9 | debitis nisi et dolorem repellat et | yes | +| 181 | 10 | ut cupiditate sequi aliquam fuga maiores | no | +| 182 | 10 | inventore saepe cumque et aut illum enim | yes | +| 183 | 10 | omnis nulla eum aliquam distinctio | yes | +| 184 | 10 | molestias modi perferendis perspiciatis | no | +| 185 | 10 | voluptates dignissimos sed doloribus animi quaerat aut | no | +| 186 | 10 | explicabo odio est et | no | +| 187 | 10 | consequuntur animi possimus | no | +| 188 | 10 | vel non beatae est | yes | +| 189 | 10 | culpa eius et voluptatem et | yes | +| 190 | 10 | accusamus sint iusto et voluptatem exercitationem | yes | +| 191 | 10 | temporibus atque distinctio omnis eius impedit tempore molestias pariatur | yes | +| 192 | 10 | ut quas possimus exercitationem sint voluptates | no | +| 193 | 10 | rerum debitis voluptatem qui eveniet tempora distinctio a | yes | +| 194 | 10 | sed ut vero sit molestiae | no | +| 195 | 10 | rerum ex veniam mollitia voluptatibus pariatur | yes | +| 196 | 10 | consequuntur aut ut fugit similique | yes | +| 197 | 10 | dignissimos quo nobis earum saepe | yes | +| 198 | 10 | quis eius est sint explicabo | yes | +| 199 | 10 | numquam repellendus a magnam | yes | +| 200 | 10 | ipsam aperiam voluptates qui | no | + +## Census summary + +| total | completed | pending | +|---|---|---| +| 200 | 90 | 110 | + +## Per-user completion rate + +| user_id | tasks | completed | rate | +|---|---|---|---| +| 1 | 20 | 11 | 0.55 | +| 2 | 20 | 8 | 0.40 | +| 3 | 20 | 7 | 0.35 | +| 4 | 20 | 6 | 0.30 | +| 5 | 20 | 12 | 0.60 | +| 6 | 20 | 6 | 0.30 | +| 7 | 20 | 9 | 0.45 | +| 8 | 20 | 11 | 0.55 | +| 9 | 20 | 8 | 0.40 | +| 10 | 20 | 12 | 0.60 | diff --git a/wizard-work/ledger/2026-11-01-todo-census/verify_todo_census.py b/wizard-work/ledger/2026-11-01-todo-census/verify_todo_census.py new file mode 100644 index 0000000..70524f3 --- /dev/null +++ b/wizard-work/ledger/2026-11-01-todo-census/verify_todo_census.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +"""Verify the todo-census artifact: re-fetch the live API and assert the on-disk +CSV/markdown match it, then exit 0 only if everything is consistent. + +Usage: python3 verify_todo_census.py +""" +import csv +import json +import sys +from urllib.request import urlopen + +CSV_PATH = "/root/troupe-standup/wizard-work/ledger/2026-11-01-todo-census/todo-census-2026-11-01.csv" +API_URL = "https://jsonplaceholder.typicode.com/todos" + + +def fetch(path): + req = urlopen(path, timeout=30) + raw = req.read() + req.close() + return json.loads(raw.decode("utf-8")) + + +def read_csv_rows(path): + with open(path, encoding="utf-8") as f: + return list(csv.DictReader(f, delimiter="|")) + + +def main(): + errors = [] + + live = fetch(API_URL) + if not isinstance(live, list): + print("FAIL: API did not return a list", file=sys.stderr) + sys.exit(1) + + disk = read_csv_rows(CSV_PATH) + + # 1. Row count + if len(live) != len(disk): + errors.append(f"row count mismatch: API={len(live)} CSV={len(disk)}") + + # 2. Completed/pending tallies + live_done = sum(1 for r in live if r["completed"]) + if live_done != sum(1 for r in disk if r["completed"] == "1"): + errors.append("completed tally mismatch") + + # 3. Every disk row exists in the live set (id+user_id+title+completed) + live_map = {(str(r["id"]), str(r["userId"]), r["title"], "1" if r["completed"] else "0"): 1 + for r in live} + for i, r in enumerate(disk, start=1): + key = (r["id"], r["user_id"], r["title"], r["completed"]) + if key not in live_map: + errors.append(f"row {i} not present in live API: {key}") + + # 4. Sampling: first, mid, last ids match the live API + for idx in (0, len(disk) // 2, len(disk) - 1): + r = disk[idx] + live_row = next((x for x in live if x["id"] == int(r["id"])), None) + if live_row is None or live_row["title"] != r["title"]: + errors.append(f"sample id={r['id']} mismatch") + + if errors: + print("VERIFY FAILED") + for e in errors: + print(" -", e) + sys.exit(1) + + print(f"VERIFY OK: {len(disk)} rows match the live API " + f"(completed={sum(1 for r in disk if r['completed']=='1')})") + sys.exit(0) + + +if __name__ == "__main__": + main()