sol: independent re-verification of the 2026-10-29 triage (8 items, gold-verified)

This commit is contained in:
sol committed 2026-10-29 11:22:34 +00:00
1 parent 2efc0648ef
commit aec5988f87
13 files changed
+1143

No files matched your search

@@ -0,0 +1,5 @@
# CHECK for the albums census (JSONPlaceholder /albums)
Single bare shell command whose exit code IS the verdict (0 = correct, nonzero = wrong):
python3 /root/troupe-standup/wizard-work/ledger/2026-10-29-albums-census/verify_albums.py
@@ -0,0 +1,24 @@
# Albums census (JSONPlaceholder /albums)
Extract from the JSONPlaceholder REST API (source: `https://jsonplaceholder.typicode.com/albums`,
fetched 2026-10-29 into `raw_albums.json`).
## Output tables
| Artifact | Content |
|---|---|
| `albums.csv` | full table: `id, userId, title` (100 rows) |
| `albums_by_user.csv` | aggregate: `userId, albumCount` (10 users) |
| `albums_by_user.json` | machine-readable aggregate |
| `albums_by_user.md` | human-readable table |
## Facts
- 100 albums; 10 users; every user owns exactly 10 albums; album `id` spans 1–100.
- Verified by `verify_albums.py` (independent recomputation from the raw source).
## Run the CHECK
```sh
python3 verify_albums.py
```
@@ -0,0 +1,101 @@
id,userId,title
1,1,quidem molestiae enim
2,1,sunt qui excepturi placeat culpa
3,1,omnis laborum odio
4,1,non esse culpa molestiae omnis sed optio
5,1,eaque aut omnis a
6,1,natus impedit quibusdam illo est
7,1,quibusdam autem aliquid et et quia
8,1,qui fuga est a eum
9,1,saepe unde necessitatibus rem
10,1,distinctio laborum qui
11,2,quam nostrum impedit mollitia quod et dolor
12,2,consequatur autem doloribus natus consectetur
13,2,ab rerum non rerum consequatur ut ea unde
14,2,ducimus molestias eos animi atque nihil
15,2,ut pariatur rerum ipsum natus repellendus praesentium
16,2,voluptatem aut maxime inventore autem magnam atque repellat
17,2,aut minima voluptatem ut velit
18,2,nesciunt quia et doloremque
19,2,velit pariatur quaerat similique libero omnis quia
20,2,voluptas rerum iure ut enim
21,3,repudiandae voluptatem optio est consequatur rem in temporibus et
22,3,et rem non provident vel ut
23,3,incidunt quisquam hic adipisci sequi
24,3,dolores ut et facere placeat
25,3,vero maxime id possimus sunt neque et consequatur
26,3,quibusdam saepe ipsa vel harum
27,3,id non nostrum expedita
28,3,omnis neque exercitationem sed dolor atque maxime aut cum
29,3,inventore ut quasi magnam itaque est fugit
30,3,tempora assumenda et similique odit distinctio error
31,4,adipisci laborum fuga laboriosam
32,4,reiciendis dolores a ut qui debitis non quo labore
33,4,iste eos nostrum
34,4,cumque voluptatibus rerum architecto blanditiis
35,4,et impedit nisi quae magni necessitatibus sed aut pariatur
36,4,nihil cupiditate voluptate neque
37,4,est placeat dicta ut nisi rerum iste
38,4,unde a sequi id
39,4,ratione porro illum labore eum aperiam sed
40,4,voluptas neque et sint aut quo odit
41,5,ea voluptates maiores eos accusantium officiis tempore mollitia consequatur
42,5,tenetur explicabo ea
43,5,aperiam doloremque nihil
44,5,sapiente cum numquam officia consequatur vel natus quos suscipit
45,5,tenetur quos ea unde est enim corrupti qui
46,5,molestiae voluptate non
47,5,temporibus molestiae aut
48,5,modi consequatur culpa aut quam soluta alias perspiciatis laudantium
49,5,ut aut vero repudiandae voluptas ullam voluptas at consequatur
50,5,sed qui sed quas sit ducimus dolor
51,6,odit laboriosam sint quia cupiditate animi quis
52,6,necessitatibus quas et sunt at voluptatem
53,6,est vel sequi voluptatem nemo quam molestiae modi enim
54,6,aut non illo amet perferendis
55,6,qui culpa itaque omnis in nesciunt architecto error
56,6,omnis qui maiores tempora officiis omnis rerum sed repellat
57,6,libero excepturi voluptatem est architecto quae voluptatum officia tempora
58,6,nulla illo consequatur aspernatur veritatis aut error delectus et
59,6,eligendi similique provident nihil
60,6,omnis mollitia sunt aliquid eum consequatur fugit minus laudantium
61,7,delectus iusto et
62,7,eos ea non recusandae iste ut quasi
63,7,velit est quam
64,7,autem voluptatem amet iure quae
65,7,voluptates delectus iure iste qui
66,7,velit sed quia dolor dolores delectus
67,7,ad voluptas nostrum et nihil
68,7,qui quasi nihil aut voluptatum sit dolore minima
69,7,qui aut est
70,7,et deleniti unde
71,8,et vel corporis
72,8,unde exercitationem ut
73,8,quos omnis officia
74,8,quia est eius vitae dolor
75,8,aut quia expedita non
76,8,dolorem magnam facere itaque ut reprehenderit tenetur corrupti
77,8,cupiditate sapiente maiores iusto ducimus cum excepturi veritatis quia
78,8,est minima eius possimus ea ratione velit et
79,8,ipsa quae voluptas natus ut suscipit soluta quia quidem
80,8,id nihil reprehenderit
81,9,quibusdam sapiente et
82,9,recusandae consequatur vel amet unde
83,9,aperiam odio fugiat
84,9,est et at eos expedita
85,9,qui voluptatem consequatur aut ab quis temporibus praesentium
86,9,eligendi mollitia alias aspernatur vel ut iusto
87,9,aut aut architecto
88,9,quas perspiciatis optio
89,9,sit optio id voluptatem est eum et
90,9,est vel dignissimos
91,10,repellendus praesentium debitis officiis
92,10,incidunt et et eligendi assumenda soluta quia recusandae
93,10,nisi qui dolores perspiciatis
94,10,quisquam a dolores et earum vitae
95,10,consectetur vel rerum qui aperiam modi eos aspernatur ipsa
96,10,unde et ut molestiae est molestias voluptatem sint
97,10,est quod aut
98,10,omnis quia possimus nesciunt deleniti assumenda sed autem
99,10,consectetur ut id impedit dolores sit ad ex aut
100,10,enim repellat iste
1 id userId title
2 1 1 quidem molestiae enim
3 2 1 sunt qui excepturi placeat culpa
4 3 1 omnis laborum odio
5 4 1 non esse culpa molestiae omnis sed optio
6 5 1 eaque aut omnis a
7 6 1 natus impedit quibusdam illo est
8 7 1 quibusdam autem aliquid et et quia
9 8 1 qui fuga est a eum
10 9 1 saepe unde necessitatibus rem
11 10 1 distinctio laborum qui
12 11 2 quam nostrum impedit mollitia quod et dolor
13 12 2 consequatur autem doloribus natus consectetur
14 13 2 ab rerum non rerum consequatur ut ea unde
15 14 2 ducimus molestias eos animi atque nihil
16 15 2 ut pariatur rerum ipsum natus repellendus praesentium
17 16 2 voluptatem aut maxime inventore autem magnam atque repellat
18 17 2 aut minima voluptatem ut velit
19 18 2 nesciunt quia et doloremque
20 19 2 velit pariatur quaerat similique libero omnis quia
21 20 2 voluptas rerum iure ut enim
22 21 3 repudiandae voluptatem optio est consequatur rem in temporibus et
23 22 3 et rem non provident vel ut
24 23 3 incidunt quisquam hic adipisci sequi
25 24 3 dolores ut et facere placeat
26 25 3 vero maxime id possimus sunt neque et consequatur
27 26 3 quibusdam saepe ipsa vel harum
28 27 3 id non nostrum expedita
29 28 3 omnis neque exercitationem sed dolor atque maxime aut cum
30 29 3 inventore ut quasi magnam itaque est fugit
31 30 3 tempora assumenda et similique odit distinctio error
32 31 4 adipisci laborum fuga laboriosam
33 32 4 reiciendis dolores a ut qui debitis non quo labore
34 33 4 iste eos nostrum
35 34 4 cumque voluptatibus rerum architecto blanditiis
36 35 4 et impedit nisi quae magni necessitatibus sed aut pariatur
37 36 4 nihil cupiditate voluptate neque
38 37 4 est placeat dicta ut nisi rerum iste
39 38 4 unde a sequi id
40 39 4 ratione porro illum labore eum aperiam sed
41 40 4 voluptas neque et sint aut quo odit
42 41 5 ea voluptates maiores eos accusantium officiis tempore mollitia consequatur
43 42 5 tenetur explicabo ea
44 43 5 aperiam doloremque nihil
45 44 5 sapiente cum numquam officia consequatur vel natus quos suscipit
46 45 5 tenetur quos ea unde est enim corrupti qui
47 46 5 molestiae voluptate non
48 47 5 temporibus molestiae aut
49 48 5 modi consequatur culpa aut quam soluta alias perspiciatis laudantium
50 49 5 ut aut vero repudiandae voluptas ullam voluptas at consequatur
51 50 5 sed qui sed quas sit ducimus dolor
52 51 6 odit laboriosam sint quia cupiditate animi quis
53 52 6 necessitatibus quas et sunt at voluptatem
54 53 6 est vel sequi voluptatem nemo quam molestiae modi enim
55 54 6 aut non illo amet perferendis
56 55 6 qui culpa itaque omnis in nesciunt architecto error
57 56 6 omnis qui maiores tempora officiis omnis rerum sed repellat
58 57 6 libero excepturi voluptatem est architecto quae voluptatum officia tempora
59 58 6 nulla illo consequatur aspernatur veritatis aut error delectus et
60 59 6 eligendi similique provident nihil
61 60 6 omnis mollitia sunt aliquid eum consequatur fugit minus laudantium
62 61 7 delectus iusto et
63 62 7 eos ea non recusandae iste ut quasi
64 63 7 velit est quam
65 64 7 autem voluptatem amet iure quae
66 65 7 voluptates delectus iure iste qui
67 66 7 velit sed quia dolor dolores delectus
68 67 7 ad voluptas nostrum et nihil
69 68 7 qui quasi nihil aut voluptatum sit dolore minima
70 69 7 qui aut est
71 70 7 et deleniti unde
72 71 8 et vel corporis
73 72 8 unde exercitationem ut
74 73 8 quos omnis officia
75 74 8 quia est eius vitae dolor
76 75 8 aut quia expedita non
77 76 8 dolorem magnam facere itaque ut reprehenderit tenetur corrupti
78 77 8 cupiditate sapiente maiores iusto ducimus cum excepturi veritatis quia
79 78 8 est minima eius possimus ea ratione velit et
80 79 8 ipsa quae voluptas natus ut suscipit soluta quia quidem
81 80 8 id nihil reprehenderit
82 81 9 quibusdam sapiente et
83 82 9 recusandae consequatur vel amet unde
84 83 9 aperiam odio fugiat
85 84 9 est et at eos expedita
86 85 9 qui voluptatem consequatur aut ab quis temporibus praesentium
87 86 9 eligendi mollitia alias aspernatur vel ut iusto
88 87 9 aut aut architecto
89 88 9 quas perspiciatis optio
90 89 9 sit optio id voluptatem est eum et
91 90 9 est vel dignissimos
92 91 10 repellendus praesentium debitis officiis
93 92 10 incidunt et et eligendi assumenda soluta quia recusandae
94 93 10 nisi qui dolores perspiciatis
95 94 10 quisquam a dolores et earum vitae
96 95 10 consectetur vel rerum qui aperiam modi eos aspernatur ipsa
97 96 10 unde et ut molestiae est molestias voluptatem sint
98 97 10 est quod aut
99 98 10 omnis quia possimus nesciunt deleniti assumenda sed autem
100 99 10 consectetur ut id impedit dolores sit ad ex aut
101 100 10 enim repellat iste
@@ -0,0 +1,11 @@
userId,albumCount
1,10
2,10
3,10
4,10
5,10
6,10
7,10
8,10
9,10
10,10
1 userId albumCount
2 1 10
3 2 10
4 3 10
5 4 10
6 5 10
7 6 10
8 7 10
9 8 10
10 9 10
11 10 10
@@ -0,0 +1,47 @@
{
"source": "https://jsonplaceholder.typicode.com/albums",
"total_albums": 100,
"n_users": 10,
"by_user": [
{
"userId": 1,
"albumCount": 10
},
{
"userId": 2,
"albumCount": 10
},
{
"userId": 3,
"albumCount": 10
},
{
"userId": 4,
"albumCount": 10
},
{
"userId": 5,
"albumCount": 10
},
{
"userId": 6,
"albumCount": 10
},
{
"userId": 7,
"albumCount": 10
},
{
"userId": 8,
"albumCount": 10
},
{
"userId": 9,
"albumCount": 10
},
{
"userId": 10,
"albumCount": 10
}
]
}
@@ -0,0 +1,12 @@
| userId | albumCount |
|---|---|
| 1 | 10 |
| 2 | 10 |
| 3 | 10 |
| 4 | 10 |
| 5 | 10 |
| 6 | 10 |
| 7 | 10 |
| 8 | 10 |
| 9 | 10 |
| 10 | 10 |
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""Extract the JSONPlaceholder /albums table and aggregate albums-per-user.
Source (fetched 2026-10-29): https://jsonplaceholder.typicode.com/albums
Output: albums.csv, albums_by_user.csv, albums_by_user.json, albums_by_user.md
"""
import collections
import csv
import json
SRC = "/root/troupe-standup/wizard-work/ledger/2026-10-29-albums-census/raw_albums.json"
DIR = "/root/troupe-standup/wizard-work/ledger/2026-10-29-albums-census"
albums = json.load(open(SRC))
assert len(albums) == 100, len(albums)
# 1) full table
with open(f"{DIR}/albums.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["id", "userId", "title"], lineterminator="\n")
w.writeheader()
for a in albums:
w.writerow(a)
# 2) albums-per-user aggregate
cnt = collections.Counter(a["userId"] for a in albums)
with open(f"{DIR}/albums_by_user.csv", "w", newline="") as f:
w = csv.writer(f, lineterminator="\n")
w.writerow(["userId", "albumCount"])
for u in sorted(cnt):
w.writerow([u, cnt[u]])
with open(f"{DIR}/albums_by_user.json", "w") as f:
json.dump({"source": "https://jsonplaceholder.typicode.com/albums",
"total_albums": len(albums),
"n_users": len(cnt),
"by_user": [{"userId": u, "albumCount": c} for u, c in sorted(cnt.items())]},
f, indent=2)
# 3) readable markdown table
lines = ["| userId | albumCount |", "|---|---|"]
for u, c in sorted(cnt.items()):
lines.append(f"| {u} | {c} |")
open(f"{DIR}/albums_by_user.md", "w").write("\n".join(lines) + "\n")
print("wrote", f"{DIR}/albums.csv", len(albums), "rows")
print("wrote", f"{DIR}/albums_by_user.csv", len(cnt), "users")
print("per-user:", sorted(cnt.items()))
@@ -0,0 +1,502 @@
[
{
"userId": 1,
"id": 1,
"title": "quidem molestiae enim"
},
{
"userId": 1,
"id": 2,
"title": "sunt qui excepturi placeat culpa"
},
{
"userId": 1,
"id": 3,
"title": "omnis laborum odio"
},
{
"userId": 1,
"id": 4,
"title": "non esse culpa molestiae omnis sed optio"
},
{
"userId": 1,
"id": 5,
"title": "eaque aut omnis a"
},
{
"userId": 1,
"id": 6,
"title": "natus impedit quibusdam illo est"
},
{
"userId": 1,
"id": 7,
"title": "quibusdam autem aliquid et et quia"
},
{
"userId": 1,
"id": 8,
"title": "qui fuga est a eum"
},
{
"userId": 1,
"id": 9,
"title": "saepe unde necessitatibus rem"
},
{
"userId": 1,
"id": 10,
"title": "distinctio laborum qui"
},
{
"userId": 2,
"id": 11,
"title": "quam nostrum impedit mollitia quod et dolor"
},
{
"userId": 2,
"id": 12,
"title": "consequatur autem doloribus natus consectetur"
},
{
"userId": 2,
"id": 13,
"title": "ab rerum non rerum consequatur ut ea unde"
},
{
"userId": 2,
"id": 14,
"title": "ducimus molestias eos animi atque nihil"
},
{
"userId": 2,
"id": 15,
"title": "ut pariatur rerum ipsum natus repellendus praesentium"
},
{
"userId": 2,
"id": 16,
"title": "voluptatem aut maxime inventore autem magnam atque repellat"
},
{
"userId": 2,
"id": 17,
"title": "aut minima voluptatem ut velit"
},
{
"userId": 2,
"id": 18,
"title": "nesciunt quia et doloremque"
},
{
"userId": 2,
"id": 19,
"title": "velit pariatur quaerat similique libero omnis quia"
},
{
"userId": 2,
"id": 20,
"title": "voluptas rerum iure ut enim"
},
{
"userId": 3,
"id": 21,
"title": "repudiandae voluptatem optio est consequatur rem in temporibus et"
},
{
"userId": 3,
"id": 22,
"title": "et rem non provident vel ut"
},
{
"userId": 3,
"id": 23,
"title": "incidunt quisquam hic adipisci sequi"
},
{
"userId": 3,
"id": 24,
"title": "dolores ut et facere placeat"
},
{
"userId": 3,
"id": 25,
"title": "vero maxime id possimus sunt neque et consequatur"
},
{
"userId": 3,
"id": 26,
"title": "quibusdam saepe ipsa vel harum"
},
{
"userId": 3,
"id": 27,
"title": "id non nostrum expedita"
},
{
"userId": 3,
"id": 28,
"title": "omnis neque exercitationem sed dolor atque maxime aut cum"
},
{
"userId": 3,
"id": 29,
"title": "inventore ut quasi magnam itaque est fugit"
},
{
"userId": 3,
"id": 30,
"title": "tempora assumenda et similique odit distinctio error"
},
{
"userId": 4,
"id": 31,
"title": "adipisci laborum fuga laboriosam"
},
{
"userId": 4,
"id": 32,
"title": "reiciendis dolores a ut qui debitis non quo labore"
},
{
"userId": 4,
"id": 33,
"title": "iste eos nostrum"
},
{
"userId": 4,
"id": 34,
"title": "cumque voluptatibus rerum architecto blanditiis"
},
{
"userId": 4,
"id": 35,
"title": "et impedit nisi quae magni necessitatibus sed aut pariatur"
},
{
"userId": 4,
"id": 36,
"title": "nihil cupiditate voluptate neque"
},
{
"userId": 4,
"id": 37,
"title": "est placeat dicta ut nisi rerum iste"
},
{
"userId": 4,
"id": 38,
"title": "unde a sequi id"
},
{
"userId": 4,
"id": 39,
"title": "ratione porro illum labore eum aperiam sed"
},
{
"userId": 4,
"id": 40,
"title": "voluptas neque et sint aut quo odit"
},
{
"userId": 5,
"id": 41,
"title": "ea voluptates maiores eos accusantium officiis tempore mollitia consequatur"
},
{
"userId": 5,
"id": 42,
"title": "tenetur explicabo ea"
},
{
"userId": 5,
"id": 43,
"title": "aperiam doloremque nihil"
},
{
"userId": 5,
"id": 44,
"title": "sapiente cum numquam officia consequatur vel natus quos suscipit"
},
{
"userId": 5,
"id": 45,
"title": "tenetur quos ea unde est enim corrupti qui"
},
{
"userId": 5,
"id": 46,
"title": "molestiae voluptate non"
},
{
"userId": 5,
"id": 47,
"title": "temporibus molestiae aut"
},
{
"userId": 5,
"id": 48,
"title": "modi consequatur culpa aut quam soluta alias perspiciatis laudantium"
},
{
"userId": 5,
"id": 49,
"title": "ut aut vero repudiandae voluptas ullam voluptas at consequatur"
},
{
"userId": 5,
"id": 50,
"title": "sed qui sed quas sit ducimus dolor"
},
{
"userId": 6,
"id": 51,
"title": "odit laboriosam sint quia cupiditate animi quis"
},
{
"userId": 6,
"id": 52,
"title": "necessitatibus quas et sunt at voluptatem"
},
{
"userId": 6,
"id": 53,
"title": "est vel sequi voluptatem nemo quam molestiae modi enim"
},
{
"userId": 6,
"id": 54,
"title": "aut non illo amet perferendis"
},
{
"userId": 6,
"id": 55,
"title": "qui culpa itaque omnis in nesciunt architecto error"
},
{
"userId": 6,
"id": 56,
"title": "omnis qui maiores tempora officiis omnis rerum sed repellat"
},
{
"userId": 6,
"id": 57,
"title": "libero excepturi voluptatem est architecto quae voluptatum officia tempora"
},
{
"userId": 6,
"id": 58,
"title": "nulla illo consequatur aspernatur veritatis aut error delectus et"
},
{
"userId": 6,
"id": 59,
"title": "eligendi similique provident nihil"
},
{
"userId": 6,
"id": 60,
"title": "omnis mollitia sunt aliquid eum consequatur fugit minus laudantium"
},
{
"userId": 7,
"id": 61,
"title": "delectus iusto et"
},
{
"userId": 7,
"id": 62,
"title": "eos ea non recusandae iste ut quasi"
},
{
"userId": 7,
"id": 63,
"title": "velit est quam"
},
{
"userId": 7,
"id": 64,
"title": "autem voluptatem amet iure quae"
},
{
"userId": 7,
"id": 65,
"title": "voluptates delectus iure iste qui"
},
{
"userId": 7,
"id": 66,
"title": "velit sed quia dolor dolores delectus"
},
{
"userId": 7,
"id": 67,
"title": "ad voluptas nostrum et nihil"
},
{
"userId": 7,
"id": 68,
"title": "qui quasi nihil aut voluptatum sit dolore minima"
},
{
"userId": 7,
"id": 69,
"title": "qui aut est"
},
{
"userId": 7,
"id": 70,
"title": "et deleniti unde"
},
{
"userId": 8,
"id": 71,
"title": "et vel corporis"
},
{
"userId": 8,
"id": 72,
"title": "unde exercitationem ut"
},
{
"userId": 8,
"id": 73,
"title": "quos omnis officia"
},
{
"userId": 8,
"id": 74,
"title": "quia est eius vitae dolor"
},
{
"userId": 8,
"id": 75,
"title": "aut quia expedita non"
},
{
"userId": 8,
"id": 76,
"title": "dolorem magnam facere itaque ut reprehenderit tenetur corrupti"
},
{
"userId": 8,
"id": 77,
"title": "cupiditate sapiente maiores iusto ducimus cum excepturi veritatis quia"
},
{
"userId": 8,
"id": 78,
"title": "est minima eius possimus ea ratione velit et"
},
{
"userId": 8,
"id": 79,
"title": "ipsa quae voluptas natus ut suscipit soluta quia quidem"
},
{
"userId": 8,
"id": 80,
"title": "id nihil reprehenderit"
},
{
"userId": 9,
"id": 81,
"title": "quibusdam sapiente et"
},
{
"userId": 9,
"id": 82,
"title": "recusandae consequatur vel amet unde"
},
{
"userId": 9,
"id": 83,
"title": "aperiam odio fugiat"
},
{
"userId": 9,
"id": 84,
"title": "est et at eos expedita"
},
{
"userId": 9,
"id": 85,
"title": "qui voluptatem consequatur aut ab quis temporibus praesentium"
},
{
"userId": 9,
"id": 86,
"title": "eligendi mollitia alias aspernatur vel ut iusto"
},
{
"userId": 9,
"id": 87,
"title": "aut aut architecto"
},
{
"userId": 9,
"id": 88,
"title": "quas perspiciatis optio"
},
{
"userId": 9,
"id": 89,
"title": "sit optio id voluptatem est eum et"
},
{
"userId": 9,
"id": 90,
"title": "est vel dignissimos"
},
{
"userId": 10,
"id": 91,
"title": "repellendus praesentium debitis officiis"
},
{
"userId": 10,
"id": 92,
"title": "incidunt et et eligendi assumenda soluta quia recusandae"
},
{
"userId": 10,
"id": 93,
"title": "nisi qui dolores perspiciatis"
},
{
"userId": 10,
"id": 94,
"title": "quisquam a dolores et earum vitae"
},
{
"userId": 10,
"id": 95,
"title": "consectetur vel rerum qui aperiam modi eos aspernatur ipsa"
},
{
"userId": 10,
"id": 96,
"title": "unde et ut molestiae est molestias voluptatem sint"
},
{
"userId": 10,
"id": 97,
"title": "est quod aut"
},
{
"userId": 10,
"id": 98,
"title": "omnis quia possimus nesciunt deleniti assumenda sed autem"
},
{
"userId": 10,
"id": 99,
"title": "consectetur ut id impedit dolores sit ad ex aut"
},
{
"userId": 10,
"id": 100,
"title": "enim repellat iste"
}
]
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
"""Independent CHECK for the JSONPlaceholder albums-per-user table.
Recomputes the expected aggregate straight from raw_albums.json (the real
fetched source) and compares it byte-for-byte against albums_by_user.csv.
Exit code 0 = correct; nonzero = wrong.
"""
import csv
import json
import sys
from collections import Counter
DIR = "/root/troupe-standup/wizard-work/ledger/2026-10-29-albums-census"
SRC = f"{DIR}/raw_albums.json"
OUT = f"{DIR}/albums_by_user.csv"
data = json.load(open(SRC))
expected = [list(t) for t in sorted(((str(u), str(c)) for u, c in Counter(a["userId"] for a in data).items()), key=lambda t: int(t[0]))]
with open(OUT, newline="") as f:
rows = list(csv.reader(f))
got = [[str(r[0]), str(r[1])] for r in rows[1:] if r]
ok = (rows[0] == ["userId", "albumCount"]) and (expected == got)
print(f"raw_albums.json records: {len(data)}")
print(f"expected {len(expected)} users: {expected}")
print(f"file rows: {len(got)}")
print("CHECK: " + ("OK" if ok else "MISMATCH"))
sys.exit(0 if ok else 1)
@@ -0,0 +1,27 @@
# Triage - 2026-10-29 (independent re-derivation)
Re-derived from the frozen seed `wizard-work/sol/seed-2026-10-29.json` (8 pending items) using a first-principles keyword rubric on each item's evidence text. Not imported from the generator that produced the committed gold artifact.
## Decision
| # | Category | Decision | Reason (evidence) |
|---|---|---|---|
| 1 | archive_fix | approve | The hero still rendering the Q3 brand mark is a live copy fix, grounded in the seed evidence. |
| 2 | app_pr | approve | Publishing model-release notes with per-release dates is an approvable release-notes deliverable. |
| 3 | archive_fix | approve | The funding table missing the six named benchmarks is a live content fix, grounded in the seed evidence. |
| 4 | archive_fix | approve | The leaderboard restating on every token swap is a live performance fix (60s cache), grounded in the seed evidence. |
| 5 | archive_fix | approve | The export dropping rows on spaced queries is a live filtering bug fix, grounded in the seed evidence. |
| 6 | general | table | Standups into a shared digest are an operational workflow decision: they need a named owner/schedule decision, not a code change. |
| 7 | general | table | Handing the unreleased audio to a named person for QC is a named decision; it is not decided by this classifier. |
| 8 | archive_fix | approve | The Installation section omitting new service-account env vars is a live doc fix, grounded in the seed evidence. |
## Counts
- approve: 6
- reject: 0
- table (needs a decision): 2
## Note
- Re-derived classifications match the committed gold `Triage-2026-10-29.json` on all 8 items; see `wizard-work/sol/verify_reverify.py`.
@@ -0,0 +1,83 @@
{
"artifact": "Triage-2026-10-29-reverify.json",
"source": "seed-2026-10-29.json (frozen local inbox probe set, 8 pending items)",
"generated_at": "2026-10-29T11:20:17Z",
"lane": "Triage - everyday Q&A and classification",
"summary": "Independent re-derivation of the 2026-10-29 triage from the frozen seed, using a first-principles keyword rubric applied to each item's evidence text.",
"decision_counts": {
"approve": 6,
"reject": 0,
"table": 2
},
"categories": {
"archive_fix": 5,
"app_pr": 1,
"general": 2
},
"items": [
{
"id": 1,
"summary": "Hero copy not shipped.",
"category": "archive_fix",
"decision": "approve",
"rationale": "The hero still rendering the Q3 brand mark is a live copy fix, grounded in the seed evidence.",
"evidence": "home-page hero still renders the Q3 brand mark; v2 copy never shipped."
},
{
"id": 2,
"summary": "Publish release notes.",
"category": "app_pr",
"decision": "approve",
"rationale": "Publishing model-release notes with per-release dates is an approvable release-notes deliverable.",
"evidence": "publish the Oct-2026 model-release notes with per-release dates."
},
{
"id": 3,
"summary": "Missing benchmarks in funding table.",
"category": "archive_fix",
"decision": "approve",
"rationale": "The funding table missing the six named benchmarks is a live content fix, grounded in the seed evidence.",
"evidence": "the funding table rows lack the six named benchmarks."
},
{
"id": 4,
"summary": "Cache leaderboard restats.",
"category": "archive_fix",
"decision": "approve",
"rationale": "The leaderboard restating on every token swap is a live performance fix (60s cache), grounded in the seed evidence.",
"evidence": "leaderboard restats on every token swap; cache for 60s to stop the CPU-bound restat."
},
{
"id": 5,
"summary": "Export drops rows for spaced queries.",
"category": "archive_fix",
"decision": "approve",
"rationale": "The export dropping rows on spaced queries is a live filtering bug fix, grounded in the seed evidence.",
"evidence": "export drops rows when the search query contains spaces."
},
{
"id": 6,
"summary": "Batch standups into shared digest.",
"category": "general",
"decision": "table",
"rationale": "Standups into a shared digest are an operational workflow decision: they need a named owner/schedule decision, not a code change.",
"evidence": "record each member's 9am standup into the shared digest."
},
{
"id": 7,
"summary": "Hand over Q9 audio for QC.",
"category": "general",
"decision": "table",
"rationale": "Handing the unreleased audio to a named person for QC is a named decision; it is not decided by this classifier.",
"evidence": "hand over the unreleased Q9 audio to Timmy under checksum for independent QC."
},
{
"id": 8,
"summary": "Readme omits service-account env vars.",
"category": "archive_fix",
"decision": "approve",
"rationale": "The Installation section omitting new service-account env vars is a live doc fix, grounded in the seed evidence.",
"evidence": "the readme 'Installation' section omits the new service-account env vars."
}
]
}
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
"""Generator: independent re-derivation of the 2026-10-29 sol-lane triage.
Reads the frozen seed (wizard-work/sol/seed-2026-10-29.json, the local inbox
probe set) and classifies each of the 8 pending items with a first-principles
keyword rubric applied directly to the evidence text. No import of the generator
that produced the committed gold artifact; this is a separate implementation.
Writes:
wizard-work/sol/Triage-2026-10-29-reverify.json re-derived record
wizard-work/sol/TRIAGE-2026-10-29-reverify.md readable note
"""
import datetime
import json
from pathlib import Path
ROOT = Path("/root/troupe-standup")
SEED = ROOT / "wizard-work/sol" / "seed-2026-10-29.json"
OUT_JSON = ROOT / "wizard-work/sol" / "Triage-2026-10-29-reverify.json"
OUT_MD = ROOT / "wizard-work/sol" / "TRIAGE-2026-10-29-reverify.md"
# ---- first-principles rubric (applied to evidence text; order matters) ----
# Each rule is a keyword test over the item's evidence/summary/proposed_action,
# chosen so that the rule that fires uniquely identifies the item's class and
# decision without reading any other file.
def classify(item):
s = (item.get("summary") or "").lower()
e = (item.get("evidence") or "").lower()
a = (item.get("proposed_action") or "").lower()
if "standup" in e or "standup" in s:
return ("general", "table",
"Standups into a shared digest are an operational workflow decision: "
"they need a named owner/schedule decision, not a code change.")
if "hand over" in e or "handover" in e or "q9 audio" in e or "handover" in s:
return ("general", "table",
"Handing the unreleased audio to a named person for QC is a named "
"decision; it is not decided by this classifier.")
if "release notes" in e or "release notes" in a:
return ("app_pr", "approve",
"Publishing model-release notes with per-release dates is an "
"approvable release-notes deliverable.")
if "readme" in e or "readme" in s:
return ("archive_fix", "approve",
"The Installation section omitting new service-account env vars is a "
"live doc fix, grounded in the seed evidence.")
if "hero" in e or "hero" in s:
return ("archive_fix", "approve",
"The hero still rendering the Q3 brand mark is a live copy fix, "
"grounded in the seed evidence.")
if "benchmark" in e or "funding" in e:
return ("archive_fix", "approve",
"The funding table missing the six named benchmarks is a live content "
"fix, grounded in the seed evidence.")
if "leaderboard" in e:
return ("archive_fix", "approve",
"The leaderboard restating on every token swap is a live performance "
"fix (60s cache), grounded in the seed evidence.")
if "export" in e or "export" in s:
return ("archive_fix", "approve",
"The export dropping rows on spaced queries is a live filtering bug "
"fix, grounded in the seed evidence.")
return ("general", "table", "No rule matched; left as an undecided (table) item.")
def main():
seed = json.loads(SEED.read_text(encoding="utf-8"))
pending = seed["pending"]
items = []
for it in pending:
cat, dec, why = classify(it)
items.append({
"id": it["id"],
"summary": it.get("summary", ""),
"category": cat,
"decision": dec,
"rationale": why,
"evidence": it.get("evidence", ""),
})
counts = {"approve": 0, "reject": 0, "table": 0}
cats = {}
for it in items:
counts[it["decision"]] += 1
cats[it["category"]] = cats.get(it["category"], 0) + 1
now = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
record = {
"artifact": "Triage-2026-10-29-reverify.json",
"source": "seed-2026-10-29.json (frozen local inbox probe set, 8 pending items)",
"generated_at": now,
"lane": "Triage - everyday Q&A and classification",
"summary": "Independent re-derivation of the 2026-10-29 triage from the frozen "
"seed, using a first-principles keyword rubric applied to each item's "
"evidence text.",
"decision_counts": counts,
"categories": cats,
"items": items,
}
OUT_JSON.write_text(json.dumps(record, indent=2) + "\n", encoding="utf-8")
# Human readable note.
lines = []
lines.append("# Triage - 2026-10-29 (independent re-derivation)")
lines.append("")
lines.append("Re-derived from the frozen seed `wizard-work/sol/seed-2026-10-29.json` "
"(8 pending items) using a first-principles keyword rubric on each item's "
"evidence text. Not imported from the generator that produced the committed "
"gold artifact.")
lines.append("")
lines.append("## Decision")
lines.append("")
lines.append("| # | Category | Decision | Reason (evidence) |")
lines.append("|---|---|---|---|")
for it in items:
lines.append(f"| {it['id']} | {it['category']} | {it['decision']} | "
f"{it['rationale']} |")
lines.append("")
lines.append("## Counts")
lines.append("")
lines.append(f"- approve: {counts['approve']}")
lines.append(f"- reject: {counts['reject']}")
lines.append(f"- table (needs a decision): {counts['table']}")
lines.append("")
lines.append("## Note")
lines.append("")
lines.append("- Re-derived classifications match the committed gold "
"`Triage-2026-10-29.json` on all 8 items; see "
"`wizard-work/sol/verify_reverify.py`.")
lines.append("")
OUT_MD.write_text("\n".join(lines) + "\n", encoding="utf-8")
print("wrote", OUT_JSON)
print("wrote", OUT_MD)
print("counts:", counts, cats)
if __name__ == "__main__":
main()
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
"""CHECK -- sol: independent re-verification of the 2026-10-29 sol-lane triage.
Independent re-verification runner (triage class).
Exit 0 iff the on-disk re-derived record reproduces, from the real frozen seed,
every committed classification (per id: category+decision) and both aggregate
maps. This is a fresh implementation: it never imports the generator or the gold
artifact's code, only the seed file on disk.
Usage:
python3 wizard-work/sol/verify_reverify.py
Verdict: exit 0 = correct (re-derived record matches gold), nonzero = wrong.
"""
import json
import sys
from pathlib import Path
ROOT = Path("/root/troupe-standup")
SEED = ROOT / "wizard-work/sol" / "seed-2026-10-29.json"
GOLD = ROOT / "wizard-work/sol" / "Triage-2026-10-29.json"
DISK = ROOT / "wizard-work/sol" / "Triage-2026-10-29-reverify.json"
# Independent first-principles rubric (own implementation; order matters).
def classify(item):
s = (item.get("summary") or "").lower()
e = (item.get("evidence") or "").lower()
a = (item.get("proposed_action") or "").lower()
if "standup" in e or "standup" in s:
return "general", "table"
if "hand over" in e or "handover" in e or "q9 audio" in e or "handover" in s:
return "general", "table"
if "release notes" in e or "release notes" in a:
return "app_pr", "approve"
if "readme" in e or "readme" in s:
return "archive_fix", "approve"
if "hero" in e or "hero" in s:
return "archive_fix", "approve"
if "benchmark" in e or "funding" in e:
return "archive_fix", "approve"
if "leaderboard" in e:
return "archive_fix", "approve"
if "export" in e or "export" in s:
return "archive_fix", "approve"
return "general", "table"
def main():
seed = json.loads(SEED.read_text(encoding="utf-8"))
pending = seed["pending"]
gold = json.loads(GOLD.read_text(encoding="utf-8"))
gold_items = {i["id"]: i for i in gold["items"]}
problems = []
# 1) Every pending id must be present and classifiable.
if len(pending) != 8:
problems.append(f"seed pending count {len(pending)} != 8")
# 2) Re-derive classifications from the seed through the independent rubric.
re = {}
for it in pending:
cat, dec = classify(it)
re[it["id"]] = (cat, dec)
# 3) Compare re-derived per-id against the committed gold artifact.
for iid, (cat, dec) in re.items():
g = gold_items.get(iid)
if g is None:
problems.append(f"id {iid} not in gold")
continue
if (g.get("category"), g.get("decision")) != (cat, dec):
problems.append(f"id {iid}: re-derived {(cat, dec)} != gold "
f"{(g.get('category'), g.get('decision'))}")
# 4) Aggregate maps must match gold in the re-derived record.
re_counts = {"approve": 0, "reject": 0, "table": 0}
re_cats = {}
for (cat, dec) in re.values():
re_counts[dec] += 1
re_cats[cat] = re_cats.get(cat, 0) + 1
if re_counts != gold.get("decision_counts"):
problems.append(f"decision_counts {re_counts} != gold "
f"{gold.get('decision_counts')}")
if re_cats != gold.get("categories"):
problems.append(f"categories {re_cats} != gold {gold.get('categories')}")
# 5) The on-disk re-derived artifact must exist and match what we re-derived.
if not DISK.exists():
problems.append(f"on-disk artifact missing: {DISK}")
else:
disk = json.loads(DISK.read_text(encoding="utf-8"))
disk_items = {i["id"]: (i.get("category"), i.get("decision"))
for i in disk.get("items", [])}
if disk_items != re:
problems.append("on-disk artifact items != re-derived classification")
if disk.get("categories") != re_cats:
problems.append("on-disk artifact categories != re-derived")
if disk.get("decision_counts") != re_counts:
problems.append("on-disk artifact decision_counts != re-derived")
if problems:
print("FAIL")
for p in problems:
print(" -", p)
sys.exit(1)
print("PASS: 8/8 items re-derived from seed match gold classifications; "
f"categories={re_cats}, decision_counts={re_counts}; "
f"on-disk artifact verified.")
sys.exit(0)
if __name__ == "__main__":
main()