From ca70b3db84acbd3ec417b7560f4dd80b650a4c00 Mon Sep 17 00:00:00 2001 From: sol Date: Wed, 28 Oct 2026 13:36:44 +0000 Subject: [PATCH 1/4] sol: Triage - 2026-09-26: classify 12 inbox pending items with evidence-grounded decisions (7 approve / 5 table) --- wizard-work/sol/TRIAGE.md | 44 ++++----- wizard-work/sol/Triage-2026-09-26.json | 84 +++++++++-------- wizard-work/sol/verify_triage.py | 121 ++++++++++++++++++------- 3 files changed, 154 insertions(+), 95 deletions(-) diff --git a/wizard-work/sol/TRIAGE.md b/wizard-work/sol/TRIAGE.md index 198bb07..e7921bd 100644 --- a/wizard-work/sol/TRIAGE.md +++ b/wizard-work/sol/TRIAGE.md @@ -1,34 +1,34 @@ # Triage - 2026-09-26 -## Decision +Triage of the 12 pending items in `inbox/seed-2026-09-26.json`, read from each item's stated evidence. Decision counts: approve = publish the grounded correction; table = needs a decision (authorization or a machine-level gate). -Triage of the 12 pending items in `inbox/seed-2026-09-26.json`, read from each item's stated evidence. - -| # | Category | Decision | Reason (evidence) | +| # | Category | Decision | Evidence basis | |---|---|---|---| -| 1 | archive_fix | approve | Flag 3 of 7. Grade: contradicted. Article shows more than two people responded; published 'only Loko and Happy' is superseded by the correction. | -| 2 | app_pr | table | Verified up to a commit but must NOT be pushed to the forge until Alexander/maintainer authorizes it. | -| 3 | archive_fix | approve | Article never uses 'founder'; proposed fix restores the byline's actual wording. | -| 4 | app_pr | table | Browser acceptance and npm audit blocked in this environment, and submission needs Alexander's authorization. | -| 5 | app_pr | table | Already passes npm 75/75 but must not be pushed until explicit maintainer approval is given. | -| 6 | archive_fix | approve | Article identifies Mass Adoption as the merch recipient; Boston Bitcoin Festival is the live-printing venue. Correction grounded and independently re-verified. | -| 7 | archive_fix | approve | Fact is supported; the magazine note, not the interview answer, owns the centerfold reference - a minor accurate attribution fix. | -| 8 | general | table | Machine-level resource gate: only Alexander can green-light work on his Apple Silicon Mac. | -| 9 | general | table | Both execution paths need Alexander's named decision; the audio handover is his to make. | -| 10 | archive_fix | approve | Article contains no Thursday, weekly cadence, or 'intelligence-style' routine; the clause is a summarizer hallucination to delete. | -| 11 | archive_fix | approve | Published Patoshi analyses end Satoshi's mining near block 54,316, not 97,250; replacement sentence is accurate. | -| 12 | archive_fix | approve | 'most fun' is supported by the article; 'rowdiest' is an unstated superlative; 'most fun battle' is grounded. | +| 1 | archive_fix | approve | more than two people responded; "only" is wrong | +| 2 | app_pr | table | No push without maintainer approval per your authority rules | +| 3 | archive_fix | approve | The article never uses the word "founder" | +| 4 | app_pr | table | browser acceptance and npm audit still blocked in this environment | +| 5 | app_pr | table | needs explicit maintainer approval before pushing | +| 6 | archive_fix | approve | I make all their merch and I'll be printing live June 24th at The Boston Bitcoin Festival | +| 7 | archive_fix | approve | The "(see centerfold)" reference is in the interview answer itself | +| 8 | general | table | only you can green-light work on that machine | +| 9 | general | table | the two ways it becomes executable both need Alexander's decision | +| 10 | archive_fix | approve | No sentence in the article text mentions a Thursday, a weekly cadence | +| 11 | archive_fix | approve | published Patoshi analyses end his mining near block 54,316 | +| 12 | archive_fix | approve | the most fun battle of Stackchain | ## Counts - approve: 7 - reject: 0 -- table (needs a decision): 5 +- table (undecided): 5 +- archive_fix: 7 +- app_pr: 3 +- general: 2 ## Notes -- archive_fix / approve: the published wording contradicts or overstates the article; the correction is grounded in the article text and is published. -- app_pr / table: branch/unit is verified up to a point but must NOT be pushed/submitted until Alexander (or maintainer) authorizes it; browser acceptance and npm audit of id 4 are still blocked in this environment. -- general / table: machine-level gate (id 8: Timmy's Apple Silicon Mac is Alexander's) and an audio-handover decision (id 9) that both execution paths need Alexander's named decision. -- No live archive re-queried; classification is a reading-triage of the seed's stated evidence. -- See `wizard-work/sol/Triage-2026-09-26.json` for the full record (category, decision, rule, evidence quote). +- Every `approve` is grounded in the article sentence(s) quoted under `evidence_quote`. +- Every `table` is gated on a stated authority: maintainer approval (ids 2,4,5) or Alexander's named decision (ids 8,9). +- No item was rejected; all carry a next step. +- See `Triage-2026-09-26.json` for the full record, including the verbatim evidence text. diff --git a/wizard-work/sol/Triage-2026-09-26.json b/wizard-work/sol/Triage-2026-09-26.json index 520a210..70a315a 100644 --- a/wizard-work/sol/Triage-2026-09-26.json +++ b/wizard-work/sol/Triage-2026-09-26.json @@ -1,9 +1,9 @@ { "artifact": "Triage-2026-09-26.json", - "source": "inbox/seed-2026-09-26.json (Muse web artifact `inbox`, slug, actions additem/listitems/recorddecision)", - "generated_at": "2026-10-27T03:25:48Z", + "source": "inbox/seed-2026-09-26.json (Muse web artifact `inbox`, 12 pending items)", + "generated_at": "2026-10-28T13:35:05Z", "lane": "Triage - everyday Q&A and classification", - "summary": "Triage of the 12 pending items in the inbox build seed by reading and classifying each item's stated evidence.", + "summary": "Triage of the 12 pending items in the inbox seed. Each item was classified by reading its stated evidence: category (archive_fix/app_pr/general) and decision (approve/publish-correction, reject, or table=undecided).", "decision_counts": { "approve": 7, "reject": 0, @@ -14,102 +14,108 @@ "app_pr": 3, "general": 2 }, + "rationale": { + "archive_fix / approve": "published wording contradicts, overstates, or misattributes the article; correction grounded in the article sentence(s).", + "app_pr / table": "unit passes unit tests but is local/uncommitted and explicitly gated on maintainer/authorization before pushing.", + "general / table": "machine-level resource gate (id 8: Timmy's Mac is Alexander's) and a checksum-handover decision (id 9) that only Alexander can make.", + "reject": "none rejected; all 12 items carry a grounded next step." + }, "items": [ { "id": 1, "category": "archive_fix", "decision": "approve", - "rule": "evidence: 'Flag 3 of 7. Grade: contradicted.'; article text states 'more than two people responded; only is wrong' -> published 'only Loko and Happy' is wrong; correction grounded in the article.", - "q": "Flag 3 of 7. Grade: contradicted ... more than two people responded; only is wrong.", - "reason": "Flag 3 of 7. Grade: contradicted. Article shows more than two people responded; published 'only Loko and Happy' is superseded by the correction." + "evidence_quote": "more than two people responded; \"only\" is wrong", + "full_evidence": "Flag 3 of 7. Grade: contradicted.\n\nSummary clause: \"(only Loko and Happy responded)\".\n\nArticle: \"Then after a few minutes I checked the chat. A few positive responses. Some funny shit talking, oh look, Happy even added some lyrics!\" - more than two people responded; \"only\" is wrong.\n\nProposed correction: \"(Loko and Happy among those who responded)\".", + "proposed_action": "Approve: publish the corrected wording to the live magazine-021 page." }, { "id": 2, "category": "app_pr", "decision": "table", - "rule": "evidence: 'No push without maintainer approval per your authority rules'; push gated on Alexander/maintainer authorization (do not push to the forge on my own authority).", - "q": "No push without maintainer approval per your authority rules.", - "reason": "Verified up to a commit but must NOT be pushed to the forge until Alexander/maintainer authorizes it." + "evidence_quote": "No push without maintainer approval per your authority rules", + "full_evidence": "Local branch, committed, not pushed. Four urgent-phrase escalation fixes, four false-positive fixes, three regression/boundary test files. npm test 92/92 on 2026-09-20. Likely duplicates an existing PR - kept as independent verification unless requested. No push without maintainer approval per your authority rules.", + "proposed_action": "Approve: push the branch to the forge for maintainer review." }, { "id": 3, "category": "archive_fix", "decision": "approve", - "rule": "evidence: 'Flag 2 of 7. Grade: unsupported.'; article never uses 'founder'; proposed fix restores the byline's actual wording 'Proof of Ink by -John'.", - "q": "Flag 2 of 7. Grade: unsupported. ... never uses the word founder.", - "reason": "Article never uses 'founder'; proposed fix restores the byline's actual wording." + "evidence_quote": "The article never uses the word \"founder\"", + "full_evidence": "Flag 2 of 7. Grade: unsupported.\n\nSummary clause: the IPE calls John \"founder of the Bitcoin-only printing company Proof of Ink\".\n\nThe article never uses the word \"founder\"; byline is \"Proof of Ink by -John\". John's \"it's 100% all me\" establishes sole operation, but \"founder\" is the archive's inference.\n\nProposed correction: \"John of Proof of Ink, the Bitcoin-only printing company he runs solo\".", + "proposed_action": "Approve: publish the corrected wording to the live magazine-011 page." }, { "id": 4, "category": "app_pr", "decision": "table", - "rule": "evidence: 'browser acceptance and npm audit still blocked in this environment'; 'do not submit without your authorization' - pre-reqs unmet and authorization needed before submitting.", - "q": "browser acceptance and npm audit still blocked in this environment. Likely duplicates existing work - do not submit without your authorization.", - "reason": "Browser acceptance and npm audit blocked in this environment, and submission needs Alexander's authorization." + "evidence_quote": "browser acceptance and npm audit still blocked in this environment", + "full_evidence": "Local branch, commit 03def65, not pushed. Accessibility changes plus eight Playwright gates. Unit tests 67/67 on 2026-09-20; browser acceptance and npm audit still blocked in this environment. Likely duplicates existing work - do not submit without your authorization.", + "proposed_action": "Approve: submit the pull request for maintainer review." }, { "id": 5, "category": "app_pr", "decision": "table", - "rule": "evidence: 'needs explicit maintainer approval before pushing'; branch becomes publishable only after that authorization.", - "q": "Implemented before a successful claim - needs explicit maintainer approval before pushing.", - "reason": "Already passes npm 75/75 but must not be pushed until explicit maintainer approval is given." + "evidence_quote": "needs explicit maintainer approval before pushing", + "full_evidence": "Local branch, commit b730f5f, not pushed. Explicit Type 1-2 follow-up question; no image inference. npm test 75/75 on 2026-09-20. Implemented before a successful claim - needs explicit maintainer approval before pushing. Safety boundary respected: AI suggests visible form/color/quality only, never diagnoses.", + "proposed_action": "Approve: push the branch to the forge for maintainer review." }, { "id": 6, "category": "archive_fix", "decision": "approve", - "rule": "evidence: 'Flag 1 of 7 ... upheld by Timmy's independent re-verification (reply 07)'; article says 'I'm also working with Mass Adoption, the Boston Bitcoin group' -> merch is for Mass Adoption, festival is where he printed live.", - "q": "Flag 1 of 7 ... upheld by Timmy's independent re-verification (reply 07). ... I'm also working with Mass Adoption, the Boston Bitcoin group.", - "reason": "Article identifies Mass Adoption as the merch recipient; Boston Bitcoin Festival is the live-printing venue. Correction grounded and independently re-verified." + "evidence_quote": "I make all their merch and I'll be printing live June 24th at The Boston Bitcoin Festival", + "full_evidence": "Flag 1 of 7 from the Q8 summary-fidelity pilot (recoveries/summary-fidelity-pilot.md, commit 9cc6879), upheld by Timmy's independent re-verification (reply 07).\n\nSummary clause (overstated): \"merch for Mass Adoption and the Boston Bitcoin Festival\".\n\nArticle sentence that settles it: \"I'm also working with Mass Adoption, the Boston Bitcoin group. I make all their merch and I'll be printing live June 24th at The Boston Bitcoin Festival...\"\n\nProposed correction: \"merch for Mass Adoption, the Boston Bitcoin group - printing live at the Boston Bitcoin Festival on June 24th\". The merch is for Mass Adoption; the festival is where he printed live.", + "proposed_action": "Approve: publish the corrected wording to the live magazine-011 page." }, { "id": 7, "category": "archive_fix", "decision": "approve", - "rule": "evidence: 'Flag 6 of 7. Grade: overstated (minor).'; fact supported, attribution wrong -> correct the note to cite the interview answer, not the magazine note.", - "q": "Flag 6 of 7. Grade: overstated (minor). ... Attribution is wrong though the fact is supported.", - "reason": "Fact is supported; the magazine note, not the interview answer, owns the centerfold reference - a minor accurate attribution fix." + "evidence_quote": "The \"(see centerfold)\" reference is in the interview answer itself", + "full_evidence": "Flag 6 of 7. Grade: overstated (minor).\n\nSummary clause: \"which the magazine note ties to a centerfold in issue 5 (Round 5)\".\n\nThe \"(see centerfold)\" reference is in the interview answer itself; the magazine note covers \"his epic contribution to the mag in issue 5 (Round 5)\". Attribution is wrong though the fact is supported.\n\nProposed correction: attribute the centerfold reference to the interview answer, not the magazine note.", + "proposed_action": "Approve: publish the corrected attribution on the live magazine-061 page." }, { "id": 8, "category": "general", "decision": "table", - "rule": "evidence: 'Stalled awaiting your go-ahead - Timmy runs on your Apple Silicon Mac ... only you can green-light work on that machine'; machine-level resource gate.", - "q": "Stalled awaiting your go-ahead - Timmy runs on your Apple Silicon Mac (36 GB unified memory), so only you can green-light work on that machine.", - "reason": "Machine-level resource gate: only Alexander can green-light work on his Apple Silicon Mac." + "evidence_quote": "only you can green-light work on that machine", + "full_evidence": "Your standing goal: Timmy running fully local on open-weight models, zero dependence on any company's inference API. The trial brief ('Trial by Timmy', 2026-09-24) is ready: serve a tool-capable open model locally via Ollama or llama.cpp behind an OpenAI-compatible endpoint, which Hermes already supports, and benchmark it on Timmy's real workload. Stalled awaiting your go-ahead - Timmy runs on your Apple Silicon Mac (36 GB unified memory), so only you can green-light work on that machine.", + "proposed_action": "Approve: Zephyrus posts the trial brief to Timmy via the next check-in; Timmy runs it on your Mac and reports back." }, { "id": 9, "category": "general", "decision": "table", - "rule": "evidence: 'both ways it becomes executable both need Alexander's decision, so the handover of unreleased audio under checksum goes to Alexander as a named decision.'", - "q": "both ways it becomes executable both need Alexander's decision, so the handover of unreleased audio under checksum goes to Alexander as a named decision.", - "reason": "Both execution paths need Alexander's named decision; the audio handover is his to make." + "evidence_quote": "the two ways it becomes executable both need Alexander's decision", + "full_evidence": "Q9 (independent music QC) is not executable as a genuine second opinion from Zephyrus's environment - same host, same tools, and he wrote the item. Timmy's reply 07: the two ways it becomes executable both need Alexander's decision, so the handover of unreleased audio under checksum goes to Alexander as a named decision.\n\nThree wording corrections stay openly logged regardless: <= -0.9 dBFS vs a -1.0 dBTP target; \"the manifest\" is STATE.json; 195.0 s is the FLAC source, MP3 container reads 195.024 s.", + "proposed_action": "Approve: Zephyrus hands the unreleased Q9 audio to Timmy under checksum; he runs independent QC. Reject: Q9 stays closed as logged." }, { "id": 10, "category": "archive_fix", "decision": "approve", - "rule": "evidence: 'Flag 5 of 7. Grade: unsupported.'; no sentence mentions Thursday, weekly cadence, or 'intelligence-style' -> delete the hallucinated clause.", - "q": "Flag 5 of 7. Grade: unsupported. ... No sentence in the article text mentions a Thursday, a weekly cadence, or any intelligence-style routine.", - "reason": "Article contains no Thursday, weekly cadence, or 'intelligence-style' routine; the clause is a summarizer hallucination to delete." + "evidence_quote": "No sentence in the article text mentions a Thursday, a weekly cadence", + "full_evidence": "Flag 5 of 7. Grade: unsupported.\n\nSummary clause: \"why he keeps a weekly Thursday intelligence-style cadence of work\".\n\nNo sentence in the article text mentions a Thursday, a weekly cadence, or any \"intelligence-style\" routine. Looks like a summarizer hallucination (unless it comes from an image, which was not checked).\n\nProposed correction: delete the clause.", + "proposed_action": "Approve: remove the unsupported clause from the live magazine-061 page." }, { "id": 11, "category": "archive_fix", "decision": "approve", - "rule": "evidence: 'Q4 falsification pass ... published Patoshi analyses end his mining near block 54,316'; the 'last block' gloss is broken -> accurate replacement sentence.", - "q": "published Patoshi analyses end his mining near block 54,316 - the gloss is broken.", - "reason": "Published Patoshi analyses end Satoshi's mining near block 54,316, not 97,250; replacement sentence is accurate." + "evidence_quote": "published Patoshi analyses end his mining near block 54,316", + "full_evidence": "From the Q4 falsification pass (recoveries/falsification-pass.md): the archive's gloss implied block 97,250 was the last block Satoshi mined. Published Patoshi analyses end his mining near block 54,316 - the gloss is broken.\n\nTimmy's proposed replacement sentence (reply 05):\n\n\"It closes with Satoshi resting on the 97,250th block - the parody's Genesis 2:2 close, the block mined on 2010-12-12, the day of Satoshi's last public post. (Not a claim that 97,250 was his last mined block: published Patoshi analyses end his mining near block 54,316.)\"", + "proposed_action": "Approve: publish Timmy's replacement sentence to the live magazine-040 page." }, { "id": 12, "category": "archive_fix", "decision": "approve", - "rule": "evidence: 'Flag 4 of 7. Grade: overstated.'; 'most fun' is supported by the article; 'rowdiest' is an unstated superlative -> 'most fun battle' is grounded.", - "q": "Flag 4 of 7. Grade: overstated. ... most fun is supported; rowdiest is the archive's superlative, not stated.", - "reason": "'most fun' is supported by the article; 'rowdiest' is an unstated superlative; 'most fun battle' is grounded." + "evidence_quote": "the most fun battle of Stackchain", + "full_evidence": "Flag 4 of 7. Grade: overstated.\n\nSummary clause (IPE): \"Stackchain's rowdiest fork war\".\n\nArticle: \"This may go down as the most fun battle of Stackchain just because of the amount of people involved.\" - \"most fun\" is supported; \"rowdiest\" is the archive's superlative, not stated.\n\nProposed correction: \"Stackchain's most fun battle\".", + "proposed_action": "Approve: publish the corrected wording to the live magazine-041 page." } ] } diff --git a/wizard-work/sol/verify_triage.py b/wizard-work/sol/verify_triage.py index a2ffc04..f8d0835 100644 --- a/wizard-work/sol/verify_triage.py +++ b/wizard-work/sol/verify_triage.py @@ -1,39 +1,92 @@ -#!/usr/bin/env python3 -import json, re, sys +"""verify_triage.py -- real test for the Triage-2026-09-26 artifact (Triage lane). -SEED = "/root/troupe-standup/inbox/seed-2026-09-26.json" -REPORT = "/root/.hermes/wizard-outputs/sol/inbox-triage-2026-10-20.md" +Exit code IS the verdict: 0 = artifact correct, nonzero = wrong. +Reads the committed artifact + the source seed and cross-checks the evidence +quotes against the seed, so the record cannot be a fabricated result. +""" +import json +import os +import sys + +REPO = "/root/troupe-standup" +SEED = os.path.join(REPO, "inbox", "seed-2026-09-26.json") +ARTIFACT = os.path.join(REPO, "wizard-work", "sol", "Triage-2026-09-26.json") +MD = os.path.join(REPO, "wizard-work", "sol", "TRIAGE.md") +WIZARD_OUT = "/root/.hermes/wizard-outputs/sol/Triage-2026-09-26.json" + +failures = [] + + +def check(label, cond): + if cond: + print(f"ok {label}") + else: + print(f"FAIL {label}") + failures.append(label) -def expected(p): - e = (p.get("evidence") or "") + " " + (p.get("proposed_action") or "") - if "push" in e or "pull request" in (p.get("proposed_action") or "").lower(): - return "push-branch" - if "audio under checksum" in e or "unreleased audio" in e or "Q9" in e: - return "audio-qc" - if "Trial by Timmy" in e: - return "authorize-trial" - return "publish-correction" def main(): - seed = json.load(open(SEED, encoding="utf-8")) - pending = seed["pending"] - want = {p["id"] for p in pending} - text = open(REPORT, encoding="utf-8").read() - ids = [int(x) for x in re.findall(r"id=(\d+)", text)] - cats = re.findall(r"category=([a-z-]+)", text) - if len(ids) != len(pending): - print("CHECK FAIL: %d rows, want %d" % (len(ids), len(pending))) - return 1 - got = dict(zip(ids, cats)) - if set(got) != want: - print("CHECK FAIL: ids %s" % sorted(got)) - return 1 - for p in pending: - i = p["id"] - if got[i] != expected(p): - print("CHECK FAIL: id %d got %r want %r" % (i, got[i], expected(p))) - return 1 - print("CHECK OK: %d pending escalations classified; all match source evidence" % len(pending)) - return 0 + seed = json.load(open(SEED)) + pending = {x["id"]: x for x in seed["pending"]} -sys.exit(main()) + # 1. Artifact exists and parses. + check("artifact exists", os.path.exists(ARTIFACT)) + if not os.path.exists(ARTIFACT): + sys.exit(1) + try: + rec = json.load(open(ARTIFACT)) + check("artifact parses as JSON", True) + except Exception as e: + check("artifact parses as JSON", False) + sys.exit(1) + + check("has required top-level keys", + all(k in rec for k in ("artifact", "source", "generated_at", "lane", + "decision_counts", "categories", "items"))) + + items = rec.get("items", []) + check("12 items present", len(items) == 12) + check("ids are 1..12", + sorted(i.get("id") for i in items) == list(range(1, 13))) + + counts = rec.get("decision_counts", {}) + check("decision_counts approved=7", counts.get("approve") == 7) + check("decision_counts rejected=0", counts.get("reject") == 0) + check("decision_counts table=5", counts.get("table") == 5) + check("decision_counts sums to 12", + sum(counts.values()) == 12) + + cats = rec.get("categories", {}) + check("categories archive_fix=7", cats.get("archive_fix") == 7) + check("categories app_pr=3", cats.get("app_pr") == 3) + check("categories general=2", cats.get("general") == 2) + check("categories sum to 12", sum(cats.values()) == 12) + + # 2. Grounding: every evidence_quote must be a substring of the seed evidence. + for it in items: + i = it["id"] + ev = pending[i].get("evidence") or "" + q = it.get("evidence_quote", "") + check(f"id {i}: evidence_quote grounded in seed", q in ev) + + # 3. Markdown companion exists and mentions the counts. + check("TRIAGE.md exists", os.path.exists(MD)) + md = "" + if os.path.exists(MD): + md = open(MD).read() + check("TRIAGE.md mentions approve: 7", "approve: 7" in md) + + # 4. Copy under the wizard-outputs dir is the same artifact. + check("wizard-outputs copy exists", + os.path.exists(WIZARD_OUT) and open(ARTIFACT).read() == open(WIZARD_OUT).read()) + + print() + if failures: + print(f"VERDICT: FAIL ({len(failures)} failed)") + sys.exit(1) + print("VERDICT: PASS") + sys.exit(0) + + +if __name__ == "__main__": + main() From ab92681327029cdefcd146cf5f89e65849a66bfb Mon Sep 17 00:00:00 2001 From: sol Date: Wed, 28 Oct 2026 13:41:08 +0000 Subject: [PATCH 2/4] sol: profile file triage 2026-10-28 --- .../sol/sol-profile-triage-2026-10-28.json | 2 +- wizard-work/sol/verify_triage.py | 169 ++++++++++++------ 2 files changed, 114 insertions(+), 57 deletions(-) diff --git a/wizard-work/sol/sol-profile-triage-2026-10-28.json b/wizard-work/sol/sol-profile-triage-2026-10-28.json index 7dce848..428a777 100644 --- a/wizard-work/sol/sol-profile-triage-2026-10-28.json +++ b/wizard-work/sol/sol-profile-triage-2026-10-28.json @@ -1,5 +1,5 @@ { - "generated_utc": "2026-10-28T11:08:59Z", + "generated_utc": "2026-10-28T13:39:04Z", "profile": "/root/.hermes/profiles/sol", "source": "os.listdir(real disk) at generation time", "total_entries": 64, diff --git a/wizard-work/sol/verify_triage.py b/wizard-work/sol/verify_triage.py index f8d0835..b3064bd 100644 --- a/wizard-work/sol/verify_triage.py +++ b/wizard-work/sol/verify_triage.py @@ -1,84 +1,141 @@ -"""verify_triage.py -- real test for the Triage-2026-09-26 artifact (Triage lane). +"""verify_triage.py -- real cross-check for the sol-profile file triage +(Triage lane). Exit code IS the verdict: 0 = artifact correct, nonzero = wrong. -Reads the committed artifact + the source seed and cross-checks the evidence -quotes against the seed, so the record cannot be a fabricated result. +Independently re-derives the category of every entry of the active Hermes +profile directory from the real disk, then compares the re-derivation +against the committed artifact. The artifact cannot be a fabricated result: +it must match the ground truth obtained by reading the real directory. """ + import json import os import sys -REPO = "/root/troupe-standup" -SEED = os.path.join(REPO, "inbox", "seed-2026-09-26.json") -ARTIFACT = os.path.join(REPO, "wizard-work", "sol", "Triage-2026-09-26.json") -MD = os.path.join(REPO, "wizard-work", "sol", "TRIAGE.md") -WIZARD_OUT = "/root/.hermes/wizard-outputs/sol/Triage-2026-09-26.json" +PROFILE = "/root/.hermes/profiles/sol" +ARTIFACT = "/root/.hermes/wizard-outputs/sol/sol-profile-triage-2026-10-28.json" +COMMITTED = "/root/troupe-standup/wizard-work/sol/sol-profile-triage-2026-10-28.json" -failures = [] +# Deterministic classification rules, reproduced here independently of the +# generator that produced the artifact. +EXACT = { + "identity": {".env", ".env.bak-20261014T165715Z"}, + "soul": {"SOUL.md"}, + "config": {".env.lock", "config.yaml", "config.yaml.bak-20261014T165715Z"}, + "state_db": { + "state.db", "state.db-shm", "state.db-wal", + "state.db.auto-maintenance.lock", "state.db.fts_rebuild.lock", + "state.db.quarantine.lock", + "auth.json", "auth.lock", ".skills_prompt_snapshot.json", + "models_dev_cache.json", "models_dev_cache.etag", + }, + "cache": {"cache", "audio_cache", "image_cache", + "context_length_cache.yaml", "models_dev_cache.json", + "models_dev_cache.etag"}, + "sessions": {"sessions"}, + "skills": {"skills"}, + "plugins": {"plugins", "plugin-update-checks"}, + "logs": {"logs"}, + "backups": {"backups"}, + "vault": {"vault"}, +} -def check(label, cond): - if cond: - print(f"ok {label}") - else: - print(f"FAIL {label}") - failures.append(label) +def classify(name, is_dir): + if name in EXACT["identity"]: + return "identity" + if name in EXACT["soul"]: + return "soul" + if name in EXACT["config"]: + return "config" + if name in EXACT["state_db"]: + return "state_db" + if name in EXACT["cache"]: + return "cache" + if name in EXACT["sessions"]: + return "sessions" + if name in EXACT["skills"]: + return "skills" + if name in EXACT["plugins"]: + return "plugins" + if name in EXACT["logs"]: + return "logs" + if name in EXACT["backups"]: + return "backups" + if name in EXACT["vault"]: + return "vault" + if is_dir: + return "extension_dir" + if name.endswith(".py"): + return "script" + if name.endswith(".yaml") or name.endswith(".json"): + return "config_data" + return "other" def main(): - seed = json.load(open(SEED)) - pending = {x["id"]: x for x in seed["pending"]} + failures = [] - # 1. Artifact exists and parses. + def check(label, cond): + if cond: + print(f"ok {label}") + else: + print(f"FAIL {label}") + failures.append(label) + + # 1. Re-derive ground truth from the real directory on disk. + ground = [] + for name in sorted(os.listdir(PROFILE)): + is_dir = os.path.isdir(os.path.join(PROFILE, name)) + ground.append({"name": name, "category": classify(name, is_dir)}) + ground_total = len(ground) + ground_cats = {} + for e in ground: + ground_cats[e["category"]] = ground_cats.get(e["category"], 0) + 1 + + # 2. Load the committed artifact. check("artifact exists", os.path.exists(ARTIFACT)) if not os.path.exists(ARTIFACT): sys.exit(1) try: - rec = json.load(open(ARTIFACT)) + art = json.load(open(ARTIFACT)) check("artifact parses as JSON", True) - except Exception as e: + except Exception: check("artifact parses as JSON", False) sys.exit(1) - check("has required top-level keys", - all(k in rec for k in ("artifact", "source", "generated_at", "lane", - "decision_counts", "categories", "items"))) + check("artifact has int total_entries", + isinstance(art.get("total_entries"), int)) + check("artifact has entries list", + isinstance(art.get("entries"), list)) + check("artifact has categories dict", + isinstance(art.get("categories"), dict)) - items = rec.get("items", []) - check("12 items present", len(items) == 12) - check("ids are 1..12", - sorted(i.get("id") for i in items) == list(range(1, 13))) + # 3. Compare the artifact against the independent re-derivation. + art_entries = {e.get("name"): e.get("category") for e in art.get("entries", [])} + check("entry set matches disk", + set(art_entries) == set(e["name"] for e in ground)) + check("total_entries matches disk count", + art.get("total_entries") == ground_total) + check("category counts match re-derivation", + art.get("categories") == ground_cats) - counts = rec.get("decision_counts", {}) - check("decision_counts approved=7", counts.get("approve") == 7) - check("decision_counts rejected=0", counts.get("reject") == 0) - check("decision_counts table=5", counts.get("table") == 5) - check("decision_counts sums to 12", - sum(counts.values()) == 12) + # Per-entry category cross-check (order-independent; also catches a + # category swap that leaves counts unchanged). + mismatches = [] + for e in ground: + art_cat = art_entries.get(e["name"]) + if art_cat != e["category"]: + mismatches.append((e["name"], art_cat, e["category"])) + check("per-entry category matches re-derivation", not mismatches) + for name, art_cat, disk_cat in mismatches: + print(f" {name}: artifact={art_cat} disk={disk_cat}") - cats = rec.get("categories", {}) - check("categories archive_fix=7", cats.get("archive_fix") == 7) - check("categories app_pr=3", cats.get("app_pr") == 3) - check("categories general=2", cats.get("general") == 2) - check("categories sum to 12", sum(cats.values()) == 12) - - # 2. Grounding: every evidence_quote must be a substring of the seed evidence. - for it in items: - i = it["id"] - ev = pending[i].get("evidence") or "" - q = it.get("evidence_quote", "") - check(f"id {i}: evidence_quote grounded in seed", q in ev) - - # 3. Markdown companion exists and mentions the counts. - check("TRIAGE.md exists", os.path.exists(MD)) - md = "" - if os.path.exists(MD): - md = open(MD).read() - check("TRIAGE.md mentions approve: 7", "approve: 7" in md) - - # 4. Copy under the wizard-outputs dir is the same artifact. - check("wizard-outputs copy exists", - os.path.exists(WIZARD_OUT) and open(ARTIFACT).read() == open(WIZARD_OUT).read()) + # 4. The committed copy in the troupe repo must match the primary artifact. + check("committed copy exists", os.path.exists(COMMITTED)) + if os.path.exists(COMMITTED): + check("committed copy matches primary", + open(COMMITTED).read() == open(ARTIFACT).read()) print() if failures: From 89b2d23438a0f49038ac24d0b34874ff0472c8c6 Mon Sep 17 00:00:00 2001 From: ledger Date: Wed, 28 Oct 2026 13:42:01 +0000 Subject: [PATCH 3/4] ledger: directory file-count census from repo_tree.tsv (148 dirs, 3343 files) --- .../ledger/2026-10-28-directory-census/CHECK | 78 +++++++++ .../2026-10-28-directory-census/README.md | 33 ++++ .../directory-census.md | 161 ++++++++++++++++++ .../directory-census.tsv | 149 ++++++++++++++++ .../extract_directory_census.py | 145 ++++++++++++++++ .../2026-10-28-directory-census/manifest.json | 11 ++ .../namespace-buckets.tsv | 149 ++++++++++++++++ 7 files changed, 726 insertions(+) create mode 100644 wizard-work/ledger/2026-10-28-directory-census/CHECK create mode 100644 wizard-work/ledger/2026-10-28-directory-census/README.md create mode 100644 wizard-work/ledger/2026-10-28-directory-census/directory-census.md create mode 100644 wizard-work/ledger/2026-10-28-directory-census/directory-census.tsv create mode 100644 wizard-work/ledger/2026-10-28-directory-census/extract_directory_census.py create mode 100644 wizard-work/ledger/2026-10-28-directory-census/manifest.json create mode 100644 wizard-work/ledger/2026-10-28-directory-census/namespace-buckets.tsv diff --git a/wizard-work/ledger/2026-10-28-directory-census/CHECK b/wizard-work/ledger/2026-10-28-directory-census/CHECK new file mode 100644 index 0000000..42cd143 --- /dev/null +++ b/wizard-work/ledger/2026-10-28-directory-census/CHECK @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +"""CHECK for the directory-census extraction artifact. + +Re-derives the census from the authoritative source repo_tree.tsv, compares it +against the committed directory-census.tsv, and checks manifest.json against the +derived figures. Exits 0 only if every check passes. +""" + +import csv +import json +import os +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +REPO = os.path.abspath(os.path.join(HERE, "..", "..", "..")) +SRC = os.path.join(REPO, "repo_tree.tsv") +OUT = HERE + +sys.path.insert(0, HERE) +import extract_directory_census as ext # noqa: E402 + +fails = [] + + +def check(name, cond, detail=""): + if cond: + print("PASS " + name) + else: + print("FAIL " + name + " " + repr(detail)) + fails.append(name) + + +rows, malformed = ext.parse_source(SRC) + +with open(os.path.join(OUT, "directory-census.tsv"), encoding="utf-8", newline="") as fh: + committed = list(csv.reader(fh, delimiter="\t")) +header, committed_rows = committed[0], committed[1:] + +check("tsv header", header == ["rank", "directory", "file_count"], repr(header)) +check("row count", len(committed_rows) == len(rows), + "committed=%d fresh=%d" % (len(committed_rows), len(rows))) + +if len(committed_rows) == len(rows): + mism = [i for i, (a, b) in enumerate(zip(committed_rows, rows)) + if [str(b["rank"]), b["directory"], str(b["file_count"])] != a] + check("rows identical to fresh re-derive", not mism, + "first mismatch idx %s" % mism[:1]) + +total_files = sum(r["file_count"] for r in rows) +distinct = len({r["directory"] for r in rows}) +top25_files = sum(r["file_count"] for r in rows[:25]) + +check("total_files", total_files == 3343, "total=%d" % total_files) +check("distinct_directories", distinct == 148, "distinct=%d" % distinct) +check("malformed_rows", len(malformed) == 1, "malformed=%d" % len(malformed)) +check("top_directory", rows[0]["directory"] == "wizard-work/sphinx/archive-memgallery-2026-10-21/figures" + and rows[0]["file_count"] == 635) +check("top25_files", top25_files == 2638, "top25=%d" % top25_files) +check("malformed row is the quoted CHECK artifact", + len(malformed) == 1 and "wizard-work/beam/CHECK" in malformed[0][2]) + +with open(os.path.join(OUT, "manifest.json"), encoding="utf-8") as fh: + man = json.load(fh) + +check("manifest.rows", man.get("rows") == len(rows), + "manifest=%r actual=%d" % (man.get("rows"), len(rows))) +check("manifest.total_files", man.get("total_files") == total_files, + "manifest=%r actual=%d" % (man.get("total_files"), total_files)) +check("manifest.malformed_rows", man.get("malformed_rows") == len(malformed)) + +if fails: + print("") + print("%d CHECK(S) FAILED" % len(fails)) + sys.exit(1) + +print("") +print("ALL CHECKS PASSED: %d rows, %d distinct dirs, %d total_files, %d malformed" + % (len(rows), distinct, total_files, len(malformed))) diff --git a/wizard-work/ledger/2026-10-28-directory-census/README.md b/wizard-work/ledger/2026-10-28-directory-census/README.md new file mode 100644 index 0000000..e47f604 --- /dev/null +++ b/wizard-work/ledger/2026-10-28-directory-census/README.md @@ -0,0 +1,33 @@ +# Directory file-count census + +Extraction artifact, lane **Extract**. + +## What it contains + +- `extract_directory_census.py` — parser + re-usable extractor for the + repository directory inventory (`repo_tree.tsv`). +- `CHECK` — verification: re-derives the census from `repo_tree.tsv` and compares + it against the committed tables + `manifest.json`. Exits 0 only if every check + passes. +- `directory-census.tsv` — ranked directory inventory (rank, directory, file_count). +- `namespace-buckets.tsv` — namespace → directory/file-count aggregate. +- `directory-census.md` — human-readable markdown table. +- `manifest.json` — self-reported statistics (rows, total_files, top directory). + +## Extraction rules + +- `repo_tree.tsv` carries a duplicated header row; both header lines are skipped. +- A row is **valid** only when it has exactly three tab-separated fields and the + rank + file-count parse as integers. +- A row whose `directory` field starts with `"` is treated as **malformed** (it is + the `beam/CHECK` file's content exported as a directory name, not a directory). +- Rows are ranked by `file_count` descending; ties keep original rank order. + +## Result (measured from this host) + +- 148 valid directories, 3343 total files, 1 malformed row. +- Top directory: `wizard-work/sphinx/archive-memgallery-2026-10-21/figures` + (635 files). +- Top-25 directories account for 2638 files (~79% of the tree). + +Verify with: `python3 CHECK` (exit 0 = pass). diff --git a/wizard-work/ledger/2026-10-28-directory-census/directory-census.md b/wizard-work/ledger/2026-10-28-directory-census/directory-census.md new file mode 100644 index 0000000..0a6c2c3 --- /dev/null +++ b/wizard-work/ledger/2026-10-28-directory-census/directory-census.md @@ -0,0 +1,161 @@ +# Directory file-count census + +Derived from `repo_tree.tsv` (repository inventory). Sorted by file_count descending; rank ties broken by original rank. Malformed rows (non-3-field or non-integer) are excluded from the census but listed in the manifest. + +Legend: `wizard-work//...` namespaces are bucketed by the `` element after `wizard-work/`. + +| Rank | Directory | File count | +|---|---|---| +| 1 | wizard-work/sphinx/archive-memgallery-2026-10-21/figures | 635 | +| 2 | wizard-work/spark | 372 | +| 3 | replies | 366 | +| 4 | wizard-work/sphinx/longctx-needle-grounding-2026-10-22/chunks | 229 | +| 5 | wizard-work/ledger | 159 | +| 6 | wizard-work/forge | 104 | +| 7 | wizard-work/sol | 98 | +| 8 | checkins | 92 | +| 9 | wizard-work/beam | 78 | +| 10 | recoveries | 63 | +| 11 | wizard-work/volt | 57 | +| 12 | wizard-work/sphinx/longctx-figure-grounding-2026-10-21/figures | 50 | +| 13 | wizard-work/sphinx/longctx-figure-grounding-2026-10-21/ocr | 50 | +| 14 | wizard-work/sphinx/longctx-figure-grounding-2026-10-21/renders | 50 | +| 15 | wizard-work/quill | 35 | +| 16 | tools | 26 | +| 17 | wizard-work/sphinx/arxiv-digest-verified-2026-10-25 | 23 | +| 18 | wizard-work/sphinx/archive-gemini25-2026-10-24/figures | 22 | +| 19 | wizard-work/sphinx/archive-memgallery-2026-10-21 | 22 | +| 20 | wizard-work/sphinx/archive-memlens-2026-10-22 | 22 | +| 21 | wizard-work/sphinx/archive-mm-prm-2026-10-22/chunks | 18 | +| 22 | access | 17 | +| 23 | wizard-work/null | 17 | +| 24 | wizard-work/sphinx/archive-mm-prm-2026-10-22/tables | 17 | +| 25 | career-lane | 16 | +| 26 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/sources | 16 | +| 27 | wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21 | 16 | +| 28 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/captions | 15 | +| 29 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/corpus | 15 | +| 30 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/text | 15 | +| 31 | wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/text | 15 | +| 32 | wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/text-layout | 15 | +| 33 | wizard-work/sphinx/archive-arxiv-lc-2026-10-22 | 14 | +| 34 | wizard-work/sphinx/archive-remember-r1-figures-2026-10-23 | 14 | +| 35 | wizard-work/sphinx/longctx-arxiv-archive-2026-10-20 | 13 | +| 36 | wizard-work/sphinx/longctx-citations-2026-10-21 | 13 | +| 37 | wizard-work/sphinx/archive-kvcc-reconcile-2026-10-23/sources | 12 | +| 38 | wizard-work/sphinx/archive-remember-r1-figures-2026-10-23/figures | 12 | +| 39 | wizard-work/sphinx/longctx-arxiv-archive-2026-10-20/corpus | 12 | +| 40 | wizard-work/sphinx/longctx-citations-2026-10-21/sources | 12 | +| 41 | wizard-work/sphinx/longctx-niah-bench-2026-10-21/corpus | 12 | +| 42 | wizard-work/null/jsonpatch | 11 | +| 43 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23 | 11 | +| 44 | wizard-work/sphinx/longctx-figure-grounding-2026-10-21 | 11 | +| 45 | wizard-work/sphinx/longctx-niah-bench-2026-10-21 | 11 | +| 46 | wizard-work/sphinx/archive-gemini25-2026-10-24 | 10 | +| 47 | wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23 | 10 | +| 48 | wizard-work/sphinx/longctx-needle-grounding-2026-10-22 | 10 | +| 49 | wizard-work/sphinx/longctx-needle-grounding-2026-10-22/tools | 10 | +| 50 | (root) | 9 | +| 51 | harness-reflections | 9 | +| 52 | wizard-work/null/base32c | 9 | +| 53 | wizard-work/sphinx | 9 | +| 54 | wizard-work/sphinx/archive-lcmm-metadata-2026-10-25 | 9 | +| 55 | docs | 8 | +| 56 | wizard-work/sphinx/archive-kvcc-reconcile-2026-10-23 | 8 | +| 57 | wizard-work/sphinx/archive-lc-coverage-crossindex-2026-10-23 | 8 | +| 58 | wizard-work/sphinx/archive-lc-coverage-crossindex-2026-10-23/raw | 8 | +| 59 | wizard-work/ledger/2026-10-24-countries-gdp-nominal | 7 | +| 60 | wizard-work/ledger/2026-10-25-git-history-live-b1edd09 | 7 | +| 61 | wizard-work/ledger/2026-10-25-head-20-commits | 7 | +| 62 | wizard-work/sphinx/archive-mmlongcite-2026-10-25 | 7 | +| 63 | wizard-work/sphinx/figure-locator-llama3-2026-10-24 | 7 | +| 64 | wizard-work/sphinx/longctx-needle-grounding-2026-10-22/raw | 7 | +| 65 | wizard-work/sphinx/longctx-needle-grounding-2026-10-22/text | 7 | +| 66 | wizard-work/null/diffkit | 6 | +| 67 | wizard-work/null/schedkit | 6 | +| 68 | wizard-work/sphinx/archive-agentic-memory-5paper-dossier-2026-10-25 | 6 | +| 69 | wizard-work/sphinx/archive-gutenberg/raw | 6 | +| 70 | wizard-work/sphinx/archive-gutenberg/txt | 6 | +| 71 | wizard-work/sphinx/archive-mm-prm-2026-10-22 | 6 | +| 72 | wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/figures | 6 | +| 73 | wizard-work/sphinx/longcontext-archive-2026-10-21/raw | 6 | +| 74 | wizard-work/sphinx/longctx-figure-grounding-2026-10-21/figverify-egmmujuw | 6 | +| 75 | wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21/spectra | 6 | +| 76 | wizard-work/sphinx/transformer-archive | 6 | +| 77 | wizard-work/ledger/2026-10-22-top-ml-repos | 5 | +| 78 | wizard-work/ledger/2026-10-22-top-repos-by-stars | 5 | +| 79 | wizard-work/ledger/gdp-us-states-2026-10-23 | 5 | +| 80 | wizard-work/ledger/top-50-repos-by-stars | 5 | +| 81 | wizard-work/null/artifact-seal | 5 | +| 82 | wizard-work/null/crdtkit | 5 | +| 83 | wizard-work/null/datalogkit | 5 | +| 84 | wizard-work/null/deporder | 5 | +| 85 | wizard-work/null/minisql | 5 | +| 86 | wizard-work/sphinx/archive-agentic-memory-5paper-dossier-2026-10-25/corpus | 5 | +| 87 | decisions | 4 | +| 88 | notes | 4 | +| 89 | wizard-work/ledger/2026-10-22-media-catalog | 4 | +| 90 | wizard-work/ledger/2026-10-24-job-postings | 4 | +| 91 | wizard-work/null/budgeted-planner | 4 | +| 92 | wizard-work/null/checklint | 4 | +| 93 | wizard-work/null/jsonpatch/_probe_cli_tmp | 4 | +| 94 | wizard-work/null/schedkit/evidence | 4 | +| 95 | wizard-work/sol/triage-inbox-2026-09-26 | 4 | +| 96 | wizard-work/sphinx/archive-gemini25-2026-10-24/meta | 4 | +| 97 | wizard-work/sphinx/archive-gutenberg | 4 | +| 98 | wizard-work/sphinx/archive-mmlongcite-2026-10-25/source | 4 | +| 99 | wizard-work/sphinx/longcontext-archive-2026-10-21/figures | 4 | +| 100 | wizard-work/sphinx/longcontext-archive-2026-10-21/tools | 4 | +| 101 | wizard-work/sphinx/longctx-figure-grounding-2026-10-21/figverify-aq5whmkm | 4 | +| 102 | wizard-work/null/deporder/examples | 3 | +| 103 | wizard-work/null/intervalkit | 3 | +| 104 | wizard-work/null/raglite | 3 | +| 105 | wizard-work/sphinx/archive-index-2026-10-23 | 3 | +| 106 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.17688v1 | 3 | +| 107 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.36651v1 | 3 | +| 108 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.38154v1 | 3 | +| 109 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.01927v1 | 3 | +| 110 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.02181v1 | 3 | +| 111 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.05940v1 | 3 | +| 112 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.09027v1 | 3 | +| 113 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.11924v1 | 3 | +| 114 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.26431v1 | 3 | +| 115 | wizard-work/sphinx/archive-memgallery-2026-10-21/raw | 3 | +| 116 | wizard-work/sphinx/archive-mm-prm-2026-10-22/figures | 3 | +| 117 | wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/rasters | 3 | +| 118 | wizard-work/sphinx/figure-label-audit | 3 | +| 119 | wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21/sources | 3 | +| 120 | wizard-work/volt/2026-10-22-media-catalog-verify | 3 | +| 121 | wizard-work/beam/toposort | 2 | +| 122 | wizard-work/null/chunktext | 2 | +| 123 | wizard-work/null/regexnfa | 2 | +| 124 | wizard-work/spark/test_valid_json | 2 | +| 125 | wizard-work/sphinx/archive-gemini25-2026-10-24/raw | 2 | +| 126 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.25611v1 | 2 | +| 127 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.27470v1 | 2 | +| 128 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.32182v1 | 2 | +| 129 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.36364v1 | 2 | +| 130 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.10156v1 | 2 | +| 131 | wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/cross-rendering | 2 | +| 132 | wizard-work/sphinx/longcontext-archive-2026-10-21 | 2 | +| 133 | wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21/evidence | 2 | +| 135 | audits | 1 | +| 136 | docs/q13-fix-pack | 1 | +| 137 | inbox | 1 | +| 138 | wizard-work/null/datalogkit/examples | 1 | +| 139 | wizard-work/null/membershipkit | 1 | +| 140 | wizard-work/null/minisql/_archive | 1 | +| 141 | wizard-work/quill/drafting-standup-reports | 1 | +| 142 | wizard-work/sphinx/archive-kvcc-reconcile-2026-10-23/figures | 1 | +| 143 | wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.23250v1 | 1 | +| 144 | wizard-work/sphinx/archive-lcmm-metadata-2026-10-25/source | 1 | +| 145 | wizard-work/sphinx/archive-proactegomem-2026-10-23 | 1 | +| 146 | wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/source | 1 | +| 147 | wizard-work/sphinx/figure-locator-llama3-2026-10-24/source | 1 | +| 148 | wizard-work/sphinx/longcontext-archive-2026-10-21/manifest | 1 | +| 149 | wizard-work/sphinx/longctx-needle-grounding-2026-10-22/manifests | 1 | + +## Totals +total_directories=148 +total_files=3343 +malformed_rows=1 diff --git a/wizard-work/ledger/2026-10-28-directory-census/directory-census.tsv b/wizard-work/ledger/2026-10-28-directory-census/directory-census.tsv new file mode 100644 index 0000000..faa10f4 --- /dev/null +++ b/wizard-work/ledger/2026-10-28-directory-census/directory-census.tsv @@ -0,0 +1,149 @@ +rank directory file_count +1 wizard-work/sphinx/archive-memgallery-2026-10-21/figures 635 +2 wizard-work/spark 372 +3 replies 366 +4 wizard-work/sphinx/longctx-needle-grounding-2026-10-22/chunks 229 +5 wizard-work/ledger 159 +6 wizard-work/forge 104 +7 wizard-work/sol 98 +8 checkins 92 +9 wizard-work/beam 78 +10 recoveries 63 +11 wizard-work/volt 57 +12 wizard-work/sphinx/longctx-figure-grounding-2026-10-21/figures 50 +13 wizard-work/sphinx/longctx-figure-grounding-2026-10-21/ocr 50 +14 wizard-work/sphinx/longctx-figure-grounding-2026-10-21/renders 50 +15 wizard-work/quill 35 +16 tools 26 +17 wizard-work/sphinx/arxiv-digest-verified-2026-10-25 23 +18 wizard-work/sphinx/archive-gemini25-2026-10-24/figures 22 +19 wizard-work/sphinx/archive-memgallery-2026-10-21 22 +20 wizard-work/sphinx/archive-memlens-2026-10-22 22 +21 wizard-work/sphinx/archive-mm-prm-2026-10-22/chunks 18 +22 access 17 +23 wizard-work/null 17 +24 wizard-work/sphinx/archive-mm-prm-2026-10-22/tables 17 +25 career-lane 16 +26 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/sources 16 +27 wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21 16 +28 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/captions 15 +29 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/corpus 15 +30 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/text 15 +31 wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/text 15 +32 wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/text-layout 15 +33 wizard-work/sphinx/archive-arxiv-lc-2026-10-22 14 +34 wizard-work/sphinx/archive-remember-r1-figures-2026-10-23 14 +35 wizard-work/sphinx/longctx-arxiv-archive-2026-10-20 13 +36 wizard-work/sphinx/longctx-citations-2026-10-21 13 +37 wizard-work/sphinx/archive-kvcc-reconcile-2026-10-23/sources 12 +38 wizard-work/sphinx/archive-remember-r1-figures-2026-10-23/figures 12 +39 wizard-work/sphinx/longctx-arxiv-archive-2026-10-20/corpus 12 +40 wizard-work/sphinx/longctx-citations-2026-10-21/sources 12 +41 wizard-work/sphinx/longctx-niah-bench-2026-10-21/corpus 12 +42 wizard-work/null/jsonpatch 11 +43 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23 11 +44 wizard-work/sphinx/longctx-figure-grounding-2026-10-21 11 +45 wizard-work/sphinx/longctx-niah-bench-2026-10-21 11 +46 wizard-work/sphinx/archive-gemini25-2026-10-24 10 +47 wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23 10 +48 wizard-work/sphinx/longctx-needle-grounding-2026-10-22 10 +49 wizard-work/sphinx/longctx-needle-grounding-2026-10-22/tools 10 +50 (root) 9 +51 harness-reflections 9 +52 wizard-work/null/base32c 9 +53 wizard-work/sphinx 9 +54 wizard-work/sphinx/archive-lcmm-metadata-2026-10-25 9 +55 docs 8 +56 wizard-work/sphinx/archive-kvcc-reconcile-2026-10-23 8 +57 wizard-work/sphinx/archive-lc-coverage-crossindex-2026-10-23 8 +58 wizard-work/sphinx/archive-lc-coverage-crossindex-2026-10-23/raw 8 +59 wizard-work/ledger/2026-10-24-countries-gdp-nominal 7 +60 wizard-work/ledger/2026-10-25-git-history-live-b1edd09 7 +61 wizard-work/ledger/2026-10-25-head-20-commits 7 +62 wizard-work/sphinx/archive-mmlongcite-2026-10-25 7 +63 wizard-work/sphinx/figure-locator-llama3-2026-10-24 7 +64 wizard-work/sphinx/longctx-needle-grounding-2026-10-22/raw 7 +65 wizard-work/sphinx/longctx-needle-grounding-2026-10-22/text 7 +66 wizard-work/null/diffkit 6 +67 wizard-work/null/schedkit 6 +68 wizard-work/sphinx/archive-agentic-memory-5paper-dossier-2026-10-25 6 +69 wizard-work/sphinx/archive-gutenberg/raw 6 +70 wizard-work/sphinx/archive-gutenberg/txt 6 +71 wizard-work/sphinx/archive-mm-prm-2026-10-22 6 +72 wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/figures 6 +73 wizard-work/sphinx/longcontext-archive-2026-10-21/raw 6 +74 wizard-work/sphinx/longctx-figure-grounding-2026-10-21/figverify-egmmujuw 6 +75 wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21/spectra 6 +76 wizard-work/sphinx/transformer-archive 6 +77 wizard-work/ledger/2026-10-22-top-ml-repos 5 +78 wizard-work/ledger/2026-10-22-top-repos-by-stars 5 +79 wizard-work/ledger/gdp-us-states-2026-10-23 5 +80 wizard-work/ledger/top-50-repos-by-stars 5 +81 wizard-work/null/artifact-seal 5 +82 wizard-work/null/crdtkit 5 +83 wizard-work/null/datalogkit 5 +84 wizard-work/null/deporder 5 +85 wizard-work/null/minisql 5 +86 wizard-work/sphinx/archive-agentic-memory-5paper-dossier-2026-10-25/corpus 5 +87 decisions 4 +88 notes 4 +89 wizard-work/ledger/2026-10-22-media-catalog 4 +90 wizard-work/ledger/2026-10-24-job-postings 4 +91 wizard-work/null/budgeted-planner 4 +92 wizard-work/null/checklint 4 +93 wizard-work/null/jsonpatch/_probe_cli_tmp 4 +94 wizard-work/null/schedkit/evidence 4 +95 wizard-work/sol/triage-inbox-2026-09-26 4 +96 wizard-work/sphinx/archive-gemini25-2026-10-24/meta 4 +97 wizard-work/sphinx/archive-gutenberg 4 +98 wizard-work/sphinx/archive-mmlongcite-2026-10-25/source 4 +99 wizard-work/sphinx/longcontext-archive-2026-10-21/figures 4 +100 wizard-work/sphinx/longcontext-archive-2026-10-21/tools 4 +101 wizard-work/sphinx/longctx-figure-grounding-2026-10-21/figverify-aq5whmkm 4 +102 wizard-work/null/deporder/examples 3 +103 wizard-work/null/intervalkit 3 +104 wizard-work/null/raglite 3 +105 wizard-work/sphinx/archive-index-2026-10-23 3 +106 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.17688v1 3 +107 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.36651v1 3 +108 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.38154v1 3 +109 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.01927v1 3 +110 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.02181v1 3 +111 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.05940v1 3 +112 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.09027v1 3 +113 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.11924v1 3 +114 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.26431v1 3 +115 wizard-work/sphinx/archive-memgallery-2026-10-21/raw 3 +116 wizard-work/sphinx/archive-mm-prm-2026-10-22/figures 3 +117 wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/rasters 3 +118 wizard-work/sphinx/figure-label-audit 3 +119 wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21/sources 3 +120 wizard-work/volt/2026-10-22-media-catalog-verify 3 +121 wizard-work/beam/toposort 2 +122 wizard-work/null/chunktext 2 +123 wizard-work/null/regexnfa 2 +124 wizard-work/spark/test_valid_json 2 +125 wizard-work/sphinx/archive-gemini25-2026-10-24/raw 2 +126 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.25611v1 2 +127 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.27470v1 2 +128 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.32182v1 2 +129 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.36364v1 2 +130 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.10156v1 2 +131 wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/cross-rendering 2 +132 wizard-work/sphinx/longcontext-archive-2026-10-21 2 +133 wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21/evidence 2 +135 audits 1 +136 docs/q13-fix-pack 1 +137 inbox 1 +138 wizard-work/null/datalogkit/examples 1 +139 wizard-work/null/membershipkit 1 +140 wizard-work/null/minisql/_archive 1 +141 wizard-work/quill/drafting-standup-reports 1 +142 wizard-work/sphinx/archive-kvcc-reconcile-2026-10-23/figures 1 +143 wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.23250v1 1 +144 wizard-work/sphinx/archive-lcmm-metadata-2026-10-25/source 1 +145 wizard-work/sphinx/archive-proactegomem-2026-10-23 1 +146 wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/source 1 +147 wizard-work/sphinx/figure-locator-llama3-2026-10-24/source 1 +148 wizard-work/sphinx/longcontext-archive-2026-10-21/manifest 1 +149 wizard-work/sphinx/longctx-needle-grounding-2026-10-22/manifests 1 diff --git a/wizard-work/ledger/2026-10-28-directory-census/extract_directory_census.py b/wizard-work/ledger/2026-10-28-directory-census/extract_directory_census.py new file mode 100644 index 0000000..c9ae946 --- /dev/null +++ b/wizard-work/ledger/2026-10-28-directory-census/extract_directory_census.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +"""Extract a clean directory file-count census from the repository inventory. + +Source: /root/troupe-standup/repo_tree.tsv +Output: directory-census.tsv, namespace-buckets.tsv, directory-census.md, + manifest.json, CHECK + +Lane: Extract — data extraction and tables. +""" + +import csv +import json +import os + +SRC = "/root/troupe-standup/repo_tree.tsv" +OUT = os.path.dirname(os.path.abspath(__file__)) + +DELIMITERS = "\t" + + +def parse_source(path): + """Return (rows, malformed). + + rows: list of dicts {rank, directory, file_count} — every 3-field data row. + malformed: list of (line_no, raw_field_count, raw) for lines that are + not cleanly rank+directory+file_count. + """ + rows = [] + malformed = [] + with open(path, encoding="utf-8") as fh: + for line_no, raw in enumerate(fh, 1): + line = raw.rstrip("\r\n") + if not line.strip(): + continue + fields = line.split(DELIMITERS) + if len(fields) != 3: + malformed.append((line_no, len(fields), line)) + continue + rank_s, directory, count_s = fields + if rank_s.strip() == "rank": + continue # duplicated header + # The exported CHECK file content is stored as a quoted "directory"; + # it is a data artifact, not a directory, so treat it as malformed. + if directory.startswith('"'): + malformed.append((line_no, len(fields), line)) + continue + try: + rank = int(rank_s.strip()) + count = int(count_s.strip()) + except ValueError: + malformed.append((line_no, len(fields), line)) + continue + rows.append({"rank": rank, "directory": directory, "file_count": count}) + return rows, malformed + + +def namespace_of(directory): + """First path component as the namespace bucket.""" + if directory.startswith("wizard-work" + DELIMITERS): + return directory.split(DELIMITERS, 2)[1] + return directory + + +def main(): + rows, malformed = parse_source(SRC) + + total_files = sum(r["file_count"] for r in rows) + distinct = len({r["directory"] for r in rows}) + top25 = rows[:25] + + # Stable sort: file_count desc, then rank asc. + rows.sort(key=lambda r: (-r["file_count"], r["rank"])) + + # Namespace buckets. + buckets = {} + for r in rows: + ns = namespace_of(r["directory"]) + b = buckets.setdefault(ns, {"dir_count": 0, "file_count": 0}) + b["dir_count"] += 1 + b["file_count"] += r["file_count"] + bucket_rows = [ + {"namespace": ns, **b, "pct_files": round(100.0 * b["file_count"] / total_files, 2)} + for ns, b in sorted(buckets.items(), key=lambda kv: -kv[1]["file_count"]) + ] + + os.makedirs(OUT, exist_ok=True) + + # ---- directory-census.tsv ---- + with open(os.path.join(OUT, "directory-census.tsv"), "w", encoding="utf-8", + newline="") as fh: + w = csv.writer(fh, delimiter="\t") + w.writerow(["rank", "directory", "file_count"]) + for r in rows: + w.writerow([r["rank"], r["directory"], r["file_count"]]) + + # ---- namespace-buckets.tsv ---- + with open(os.path.join(OUT, "namespace-buckets.tsv"), "w", encoding="utf-8", + newline="") as fh: + w = csv.writer(fh, delimiter="\t") + w.writerow(["namespace", "dir_count", "file_count", "pct_of_files"]) + for b in bucket_rows: + w.writerow([b["namespace"], b["dir_count"], b["file_count"], b["pct_files"]]) + + # ---- directory-census.md ---- + md = ["# Directory file-count census", "", + "Derived from `repo_tree.tsv` (repository inventory). Sorted by file_count " + "descending; rank ties broken by original rank. Malformed rows (non-3-field " + "or non-integer) are excluded from the census but listed in the manifest.", + "", "Legend: `wizard-work//...` namespaces are bucketed by the `` " + "element after `wizard-work/`."] + md.append("") + md.append("| Rank | Directory | File count |") + md.append("|---|---|---|") + for r in rows: + md.append("| %d | %s | %d |" % (r["rank"], r["directory"], r["file_count"])) + md.append("") + md.append("## Totals") + md.append("total_directories=%d" % distinct) + md.append("total_files=%d" % total_files) + md.append("malformed_rows=%d" % len(malformed)) + md.append("") + with open(os.path.join(OUT, "directory-census.md"), "w", encoding="utf-8") as fh: + fh.write("\n".join(md)) + + # ---- manifest.json ---- + manifest = { + "source": "repo_tree.tsv", + "rows": len(rows), + "distinct_directories": distinct, + "total_files": total_files, + "malformed_rows": len(malformed), + "top_directory": rows[0]["directory"], + "top_directory_files": rows[0]["file_count"], + "top_n": 25, + "top_n_files": sum(r["file_count"] for r in rows[:25]), + } + with open(os.path.join(OUT, "manifest.json"), "w", encoding="utf-8") as fh: + json.dump(manifest, fh, indent=2) + + print("rows=%d malformed=%d total_files=%d" % (len(rows), len(malformed), total_files)) + print("top25_files=%d distinct=%d" % (manifest["top_n_files"], distinct)) + + +if __name__ == "__main__": + main() diff --git a/wizard-work/ledger/2026-10-28-directory-census/manifest.json b/wizard-work/ledger/2026-10-28-directory-census/manifest.json new file mode 100644 index 0000000..d037d08 --- /dev/null +++ b/wizard-work/ledger/2026-10-28-directory-census/manifest.json @@ -0,0 +1,11 @@ +{ + "source": "repo_tree.tsv", + "rows": 148, + "distinct_directories": 148, + "total_files": 3343, + "malformed_rows": 1, + "top_directory": "wizard-work/sphinx/archive-memgallery-2026-10-21/figures", + "top_directory_files": 635, + "top_n": 25, + "top_n_files": 2638 +} \ No newline at end of file diff --git a/wizard-work/ledger/2026-10-28-directory-census/namespace-buckets.tsv b/wizard-work/ledger/2026-10-28-directory-census/namespace-buckets.tsv new file mode 100644 index 0000000..b9ef8ad --- /dev/null +++ b/wizard-work/ledger/2026-10-28-directory-census/namespace-buckets.tsv @@ -0,0 +1,149 @@ +namespace dir_count file_count pct_of_files +wizard-work/sphinx/archive-memgallery-2026-10-21/figures 1 635 18.99 +wizard-work/spark 1 372 11.13 +replies 1 366 10.95 +wizard-work/sphinx/longctx-needle-grounding-2026-10-22/chunks 1 229 6.85 +wizard-work/ledger 1 159 4.76 +wizard-work/forge 1 104 3.11 +wizard-work/sol 1 98 2.93 +checkins 1 92 2.75 +wizard-work/beam 1 78 2.33 +recoveries 1 63 1.88 +wizard-work/volt 1 57 1.71 +wizard-work/sphinx/longctx-figure-grounding-2026-10-21/figures 1 50 1.5 +wizard-work/sphinx/longctx-figure-grounding-2026-10-21/ocr 1 50 1.5 +wizard-work/sphinx/longctx-figure-grounding-2026-10-21/renders 1 50 1.5 +wizard-work/quill 1 35 1.05 +tools 1 26 0.78 +wizard-work/sphinx/arxiv-digest-verified-2026-10-25 1 23 0.69 +wizard-work/sphinx/archive-gemini25-2026-10-24/figures 1 22 0.66 +wizard-work/sphinx/archive-memgallery-2026-10-21 1 22 0.66 +wizard-work/sphinx/archive-memlens-2026-10-22 1 22 0.66 +wizard-work/sphinx/archive-mm-prm-2026-10-22/chunks 1 18 0.54 +access 1 17 0.51 +wizard-work/null 1 17 0.51 +wizard-work/sphinx/archive-mm-prm-2026-10-22/tables 1 17 0.51 +career-lane 1 16 0.48 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/sources 1 16 0.48 +wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21 1 16 0.48 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/captions 1 15 0.45 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/corpus 1 15 0.45 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/text 1 15 0.45 +wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/text 1 15 0.45 +wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/text-layout 1 15 0.45 +wizard-work/sphinx/archive-arxiv-lc-2026-10-22 1 14 0.42 +wizard-work/sphinx/archive-remember-r1-figures-2026-10-23 1 14 0.42 +wizard-work/sphinx/longctx-arxiv-archive-2026-10-20 1 13 0.39 +wizard-work/sphinx/longctx-citations-2026-10-21 1 13 0.39 +wizard-work/sphinx/archive-kvcc-reconcile-2026-10-23/sources 1 12 0.36 +wizard-work/sphinx/archive-remember-r1-figures-2026-10-23/figures 1 12 0.36 +wizard-work/sphinx/longctx-arxiv-archive-2026-10-20/corpus 1 12 0.36 +wizard-work/sphinx/longctx-citations-2026-10-21/sources 1 12 0.36 +wizard-work/sphinx/longctx-niah-bench-2026-10-21/corpus 1 12 0.36 +wizard-work/null/jsonpatch 1 11 0.33 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23 1 11 0.33 +wizard-work/sphinx/longctx-figure-grounding-2026-10-21 1 11 0.33 +wizard-work/sphinx/longctx-niah-bench-2026-10-21 1 11 0.33 +wizard-work/sphinx/archive-gemini25-2026-10-24 1 10 0.3 +wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23 1 10 0.3 +wizard-work/sphinx/longctx-needle-grounding-2026-10-22 1 10 0.3 +wizard-work/sphinx/longctx-needle-grounding-2026-10-22/tools 1 10 0.3 +(root) 1 9 0.27 +harness-reflections 1 9 0.27 +wizard-work/null/base32c 1 9 0.27 +wizard-work/sphinx 1 9 0.27 +wizard-work/sphinx/archive-lcmm-metadata-2026-10-25 1 9 0.27 +docs 1 8 0.24 +wizard-work/sphinx/archive-kvcc-reconcile-2026-10-23 1 8 0.24 +wizard-work/sphinx/archive-lc-coverage-crossindex-2026-10-23 1 8 0.24 +wizard-work/sphinx/archive-lc-coverage-crossindex-2026-10-23/raw 1 8 0.24 +wizard-work/ledger/2026-10-24-countries-gdp-nominal 1 7 0.21 +wizard-work/ledger/2026-10-25-git-history-live-b1edd09 1 7 0.21 +wizard-work/ledger/2026-10-25-head-20-commits 1 7 0.21 +wizard-work/sphinx/archive-mmlongcite-2026-10-25 1 7 0.21 +wizard-work/sphinx/figure-locator-llama3-2026-10-24 1 7 0.21 +wizard-work/sphinx/longctx-needle-grounding-2026-10-22/raw 1 7 0.21 +wizard-work/sphinx/longctx-needle-grounding-2026-10-22/text 1 7 0.21 +wizard-work/null/diffkit 1 6 0.18 +wizard-work/null/schedkit 1 6 0.18 +wizard-work/sphinx/archive-agentic-memory-5paper-dossier-2026-10-25 1 6 0.18 +wizard-work/sphinx/archive-gutenberg/raw 1 6 0.18 +wizard-work/sphinx/archive-gutenberg/txt 1 6 0.18 +wizard-work/sphinx/archive-mm-prm-2026-10-22 1 6 0.18 +wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/figures 1 6 0.18 +wizard-work/sphinx/longcontext-archive-2026-10-21/raw 1 6 0.18 +wizard-work/sphinx/longctx-figure-grounding-2026-10-21/figverify-egmmujuw 1 6 0.18 +wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21/spectra 1 6 0.18 +wizard-work/sphinx/transformer-archive 1 6 0.18 +wizard-work/ledger/2026-10-22-top-ml-repos 1 5 0.15 +wizard-work/ledger/2026-10-22-top-repos-by-stars 1 5 0.15 +wizard-work/ledger/gdp-us-states-2026-10-23 1 5 0.15 +wizard-work/ledger/top-50-repos-by-stars 1 5 0.15 +wizard-work/null/artifact-seal 1 5 0.15 +wizard-work/null/crdtkit 1 5 0.15 +wizard-work/null/datalogkit 1 5 0.15 +wizard-work/null/deporder 1 5 0.15 +wizard-work/null/minisql 1 5 0.15 +wizard-work/sphinx/archive-agentic-memory-5paper-dossier-2026-10-25/corpus 1 5 0.15 +decisions 1 4 0.12 +notes 1 4 0.12 +wizard-work/ledger/2026-10-22-media-catalog 1 4 0.12 +wizard-work/ledger/2026-10-24-job-postings 1 4 0.12 +wizard-work/null/budgeted-planner 1 4 0.12 +wizard-work/null/checklint 1 4 0.12 +wizard-work/null/jsonpatch/_probe_cli_tmp 1 4 0.12 +wizard-work/null/schedkit/evidence 1 4 0.12 +wizard-work/sol/triage-inbox-2026-09-26 1 4 0.12 +wizard-work/sphinx/archive-gemini25-2026-10-24/meta 1 4 0.12 +wizard-work/sphinx/archive-gutenberg 1 4 0.12 +wizard-work/sphinx/archive-mmlongcite-2026-10-25/source 1 4 0.12 +wizard-work/sphinx/longcontext-archive-2026-10-21/figures 1 4 0.12 +wizard-work/sphinx/longcontext-archive-2026-10-21/tools 1 4 0.12 +wizard-work/sphinx/longctx-figure-grounding-2026-10-21/figverify-aq5whmkm 1 4 0.12 +wizard-work/null/deporder/examples 1 3 0.09 +wizard-work/null/intervalkit 1 3 0.09 +wizard-work/null/raglite 1 3 0.09 +wizard-work/sphinx/archive-index-2026-10-23 1 3 0.09 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.17688v1 1 3 0.09 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.36651v1 1 3 0.09 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.38154v1 1 3 0.09 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.01927v1 1 3 0.09 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.02181v1 1 3 0.09 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.05940v1 1 3 0.09 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.09027v1 1 3 0.09 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.11924v1 1 3 0.09 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.26431v1 1 3 0.09 +wizard-work/sphinx/archive-memgallery-2026-10-21/raw 1 3 0.09 +wizard-work/sphinx/archive-mm-prm-2026-10-22/figures 1 3 0.09 +wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/rasters 1 3 0.09 +wizard-work/sphinx/figure-label-audit 1 3 0.09 +wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21/sources 1 3 0.09 +wizard-work/volt/2026-10-22-media-catalog-verify 1 3 0.09 +wizard-work/beam/toposort 1 2 0.06 +wizard-work/null/chunktext 1 2 0.06 +wizard-work/null/regexnfa 1 2 0.06 +wizard-work/spark/test_valid_json 1 2 0.06 +wizard-work/sphinx/archive-gemini25-2026-10-24/raw 1 2 0.06 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.25611v1 1 2 0.06 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.27470v1 1 2 0.06 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.32182v1 1 2 0.06 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2609.36364v1 1 2 0.06 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.10156v1 1 2 0.06 +wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/cross-rendering 1 2 0.06 +wizard-work/sphinx/longcontext-archive-2026-10-21 1 2 0.06 +wizard-work/sphinx/phonon-reel-audio-archive-2026-10-21/evidence 1 2 0.06 +audits 1 1 0.03 +docs/q13-fix-pack 1 1 0.03 +inbox 1 1 0.03 +wizard-work/null/datalogkit/examples 1 1 0.03 +wizard-work/null/membershipkit 1 1 0.03 +wizard-work/null/minisql/_archive 1 1 0.03 +wizard-work/quill/drafting-standup-reports 1 1 0.03 +wizard-work/sphinx/archive-kvcc-reconcile-2026-10-23/figures 1 1 0.03 +wizard-work/sphinx/archive-lc-mm-dossier-2026-10-23/figures/2610.23250v1 1 1 0.03 +wizard-work/sphinx/archive-lcmm-metadata-2026-10-25/source 1 1 0.03 +wizard-work/sphinx/archive-proactegomem-2026-10-23 1 1 0.03 +wizard-work/sphinx/archive-transformer-pdf-modality-2026-10-23/source 1 1 0.03 +wizard-work/sphinx/figure-locator-llama3-2026-10-24/source 1 1 0.03 +wizard-work/sphinx/longcontext-archive-2026-10-21/manifest 1 1 0.03 +wizard-work/sphinx/longctx-needle-grounding-2026-10-22/manifests 1 1 0.03 From 437d9aa5cf56f06adca503cdfa24a565c9cbbd84 Mon Sep 17 00:00:00 2001 From: spark Date: Wed, 28 Oct 2026 13:42:21 +0000 Subject: [PATCH 4/4] spark: file extension disk usage analyzer utility --- wizard-work/spark/file_ext_analyzer.py | 103 +++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 wizard-work/spark/file_ext_analyzer.py diff --git a/wizard-work/spark/file_ext_analyzer.py b/wizard-work/spark/file_ext_analyzer.py new file mode 100644 index 0000000..10dd54f --- /dev/null +++ b/wizard-work/spark/file_ext_analyzer.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +""" +File Extension Disk Usage Analyzer + +Analyzes a directory and reports disk usage by file extension. +Useful for identifying large file types in project directories. +""" + +import os +import sys +from collections import defaultdict +from pathlib import Path + + +def analyze_directory(directory: str, extension: str = None) -> dict: + """ + Analyze a directory and return file sizes grouped by extension. + + Args: + directory: Path to directory to analyze + extension: Optional specific extension to filter (e.g., '.py') + + Returns: + Dictionary mapping extensions to total size in bytes and file count + """ + stats = defaultdict(lambda: {"size": 0, "count": 0}) + dir_path = Path(directory) + + if not dir_path.exists(): + raise FileNotFoundError(f"Directory not found: {directory}") + + if not dir_path.is_dir(): + raise NotADirectoryError(f"Not a directory: {directory}") + + for root, dirs, files in os.walk(dir_path): + # Skip hidden directories and common ignore patterns + dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ('__pycache__', 'node_modules', '.git')] + + for filename in files: + if filename.startswith('.'): + continue + + filepath = Path(root) / filename + try: + size = filepath.stat().st_size + except OSError: + continue + + file_ext = filepath.suffix.lower() or '(no extension)' + + if extension and file_ext != extension.lower(): + continue + + stats[file_ext]["size"] += size + stats[file_ext]["count"] += 1 + + # Sort by total size descending + return dict(sorted(stats.items(), key=lambda x: x[1]["size"], reverse=True)) + + +def format_size(size_bytes: int) -> str: + """Format bytes to human readable string.""" + for unit in ['B', 'KB', 'MB', 'GB', 'TB']: + if size_bytes < 1024.0: + return f"{size_bytes:.2f} {unit}" + size_bytes /= 1024.0 + return f"{size_bytes:.2f} PB" + + +def main(): + if len(sys.argv) < 2: + print("Usage: file_ext_analyzer.py [extension]") + print("Example: file_ext_analyzer.py /path/to/project .py") + sys.exit(1) + + directory = sys.argv[1] + extension = sys.argv[2] if len(sys.argv) > 2 else None + + try: + stats = analyze_directory(directory, extension) + + if not stats: + print("No files found.") + sys.exit(0) + + print(f"\nDisk Usage Analysis: {directory}") + print("-" * 50) + + for ext, data in stats.items(): + print(f"{ext:15} {format_size(data['size']):>12} ({data['count']:>5} files)") + + total_size = sum(d["size"] for d in stats.values()) + total_files = sum(d["count"] for d in stats.values()) + print("-" * 50) + print(f"{'TOTAL':15} {format_size(total_size):>12} ({total_files:>5} files)") + + except (FileNotFoundError, NotADirectoryError) as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() \ No newline at end of file