sol: sol-lane untracked-file triage classification 2026-11-02
This commit is contained in:
1 parent
e31c056d9e
commit
ff4e2fb72e
5 files changed
+1002
No files matched your search
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# CHECK -- sol: untracked-file triage classification (2026-11-02).
|
||||||
|
# Exit 0 iff the committed manifest verifies: the manifest re-derives every
|
||||||
|
# frozen path's category/decision by the canonical rule (no lookup), every
|
||||||
|
# path is still a real, untracked, non-ignored file, the corpus sha256 matches,
|
||||||
|
# ids are 1..N, the summary counts are consistent, and the wizard-outputs shard
|
||||||
|
# is byte-identical to the repo manifest.
|
||||||
|
set -u
|
||||||
|
|
||||||
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
# Resolve the repo root (this script may live inside wizard-work/sol/ or at the
|
||||||
|
# repo root, so walk up to the directory that holds .git).
|
||||||
|
ROOT="$(git -C "$HERE" rev-parse --show-toplevel 2>/dev/null)" \
|
||||||
|
|| { echo "CANNOT GRADE: no git toplevel above $HERE" >&2; exit 2; }
|
||||||
|
cd "$ROOT" || { echo "CANNOT GRADE: cannot cd to $ROOT" >&2; exit 2; }
|
||||||
|
|
||||||
|
exec python3 wizard-work/sol/verify_untracked_triad_2026_11_02.py
|
||||||
@@ -0,0 +1,625 @@
|
|||||||
|
{
|
||||||
|
"artifact": "Untracked-Triad-2026-11-02.json",
|
||||||
|
"built_at": "2026-11-02T04:50:51.524666+00:00",
|
||||||
|
"corpus_sha256": "144a9dd89619300d0016c490033605ff00c19d0b2a99964537127754f22503ab",
|
||||||
|
"files": [
|
||||||
|
"CHECK-2026-11-02-openmeteo-summary",
|
||||||
|
"CHECK-sol-untracked-classify",
|
||||||
|
"CHECK-triage-2026-10-29",
|
||||||
|
"checkins/2026-10-27-sentinel.md",
|
||||||
|
"d.jsonl",
|
||||||
|
"docs/clawrouter-plan.md",
|
||||||
|
"docs/flux2-deploy.md",
|
||||||
|
"docs/video-deploy.md",
|
||||||
|
"inbox/dump_seed.py",
|
||||||
|
"kanban.db",
|
||||||
|
"recoveries/apply-queue-status-2026-10-25.md",
|
||||||
|
"repo_exts.tsv",
|
||||||
|
"repo_files.tsv",
|
||||||
|
"repo_tree.tsv",
|
||||||
|
"s.json",
|
||||||
|
"test_sample.txt",
|
||||||
|
"test_validation.txt",
|
||||||
|
"test_verification.txt",
|
||||||
|
"validate_artifact.py",
|
||||||
|
"wizard-work/null/README-gatehygiene.md",
|
||||||
|
"wizard-work/null/README-q62-scan.md",
|
||||||
|
"wizard-work/null/_probe10.py",
|
||||||
|
"wizard-work/null/_probe11.py",
|
||||||
|
"wizard-work/null/_probe12.py",
|
||||||
|
"wizard-work/null/_probe13.py",
|
||||||
|
"wizard-work/null/_probe14.py",
|
||||||
|
"wizard-work/null/_probe5.py",
|
||||||
|
"wizard-work/null/_probe6.py",
|
||||||
|
"wizard-work/null/_probe7.py",
|
||||||
|
"wizard-work/null/_probe8.py",
|
||||||
|
"wizard-work/null/_probe9.py",
|
||||||
|
"wizard-work/null/_probe_binding_defects.py",
|
||||||
|
"wizard-work/null/_probe_gh1.py",
|
||||||
|
"wizard-work/null/_probe_gh2.py",
|
||||||
|
"wizard-work/null/_probe_gh3.py",
|
||||||
|
"wizard-work/null/_probe_gh4.py",
|
||||||
|
"wizard-work/null/_probe_gh5.py",
|
||||||
|
"wizard-work/null/_probe_gh6.py",
|
||||||
|
"wizard-work/null/_probe_gh7.py",
|
||||||
|
"wizard-work/null/_probe_gh8.py",
|
||||||
|
"wizard-work/null/_probe_gh9.py",
|
||||||
|
"wizard-work/null/_probe_mut2.py",
|
||||||
|
"wizard-work/null/_probe_mut_check.py",
|
||||||
|
"wizard-work/null/_probe_q70_5h.py",
|
||||||
|
"wizard-work/null/_probe_repro1.py",
|
||||||
|
"wizard-work/null/_probe_repro2.py",
|
||||||
|
"wizard-work/null/_probe_repro3.py",
|
||||||
|
"wizard-work/null/_probe_repro4.py",
|
||||||
|
"wizard-work/null/_probe_repro5.py",
|
||||||
|
"wizard-work/null/_probe_repro6.py",
|
||||||
|
"wizard-work/null/_probe_repro7.py",
|
||||||
|
"wizard-work/null/check_gatehygiene.py",
|
||||||
|
"wizard-work/null/check_provenance.py",
|
||||||
|
"wizard-work/null/check_provenance_baseline.tsv",
|
||||||
|
"wizard-work/null/check_provenance_ledger.py",
|
||||||
|
"wizard-work/null/check_q62_scan.py",
|
||||||
|
"wizard-work/null/cli_contract.py",
|
||||||
|
"wizard-work/null/diffkit/__init__.py",
|
||||||
|
"wizard-work/null/diffkit/_flatpkg.py",
|
||||||
|
"wizard-work/null/diffkit/core.py",
|
||||||
|
"wizard-work/null/diffkit/diffkit_cli.py",
|
||||||
|
"wizard-work/null/diffkit/myers.py",
|
||||||
|
"wizard-work/null/diffkit_gate.py",
|
||||||
|
"wizard-work/null/gatehygiene.py",
|
||||||
|
"wizard-work/null/json_salvage.py",
|
||||||
|
"wizard-work/null/membershipkit/.hermes-tmp.sx2gIa",
|
||||||
|
"wizard-work/null/membershipkit/check_membershipkit.sh",
|
||||||
|
"wizard-work/null/membershipkit/mutate_membershipkit.py",
|
||||||
|
"wizard-work/null/membershipkit/test_membershipkit.py",
|
||||||
|
"wizard-work/null/mutate_resolver.py",
|
||||||
|
"wizard-work/null/mutate_salvage.py",
|
||||||
|
"wizard-work/null/q58_warncontrol.py",
|
||||||
|
"wizard-work/null/q62_scan.py",
|
||||||
|
"wizard-work/null/q70_sabotage.py",
|
||||||
|
"wizard-work/null/q76_binding.py",
|
||||||
|
"wizard-work/null/q80_warn.py",
|
||||||
|
"wizard-work/null/revwalk.py",
|
||||||
|
"wizard-work/null/test_gate.py",
|
||||||
|
"wizard-work/null/test_gate_mutants.py",
|
||||||
|
"wizard-work/null/test_json_salvage.py",
|
||||||
|
"wizard-work/null/test_myers_diff.py",
|
||||||
|
"wizard-work/null/test_revwalk.py",
|
||||||
|
"wizard-work/null/verify_check_provenance.py",
|
||||||
|
"wizard-work/null/verify_staged.py",
|
||||||
|
"wizard-work/quill/draft-compliance-report-2026-10-31.pin",
|
||||||
|
"wizard-work/sphinx/archive-mmlongcite-2026-10-25/probe_paper_facts.json"
|
||||||
|
],
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"category": "gate",
|
||||||
|
"decision": "approve",
|
||||||
|
"id": 1,
|
||||||
|
"path": "CHECK-2026-11-02-openmeteo-summary"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "gate",
|
||||||
|
"decision": "approve",
|
||||||
|
"id": 2,
|
||||||
|
"path": "CHECK-sol-untracked-classify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "gate",
|
||||||
|
"decision": "approve",
|
||||||
|
"id": 3,
|
||||||
|
"path": "CHECK-triage-2026-10-29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "documentation",
|
||||||
|
"decision": "info",
|
||||||
|
"id": 4,
|
||||||
|
"path": "checkins/2026-10-27-sentinel.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 5,
|
||||||
|
"path": "d.jsonl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "documentation",
|
||||||
|
"decision": "info",
|
||||||
|
"id": 6,
|
||||||
|
"path": "docs/clawrouter-plan.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "documentation",
|
||||||
|
"decision": "info",
|
||||||
|
"id": 7,
|
||||||
|
"path": "docs/flux2-deploy.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "documentation",
|
||||||
|
"decision": "info",
|
||||||
|
"id": 8,
|
||||||
|
"path": "docs/video-deploy.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 9,
|
||||||
|
"path": "inbox/dump_seed.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "persistence",
|
||||||
|
"decision": "archive",
|
||||||
|
"id": 10,
|
||||||
|
"path": "kanban.db"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "documentation",
|
||||||
|
"decision": "info",
|
||||||
|
"id": 11,
|
||||||
|
"path": "recoveries/apply-queue-status-2026-10-25.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 12,
|
||||||
|
"path": "repo_exts.tsv"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 13,
|
||||||
|
"path": "repo_files.tsv"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 14,
|
||||||
|
"path": "repo_tree.tsv"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 15,
|
||||||
|
"path": "s.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 16,
|
||||||
|
"path": "test_sample.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 17,
|
||||||
|
"path": "test_validation.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 18,
|
||||||
|
"path": "test_verification.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 19,
|
||||||
|
"path": "validate_artifact.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "documentation",
|
||||||
|
"decision": "info",
|
||||||
|
"id": 20,
|
||||||
|
"path": "wizard-work/null/README-gatehygiene.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "documentation",
|
||||||
|
"decision": "info",
|
||||||
|
"id": 21,
|
||||||
|
"path": "wizard-work/null/README-q62-scan.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 22,
|
||||||
|
"path": "wizard-work/null/_probe10.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 23,
|
||||||
|
"path": "wizard-work/null/_probe11.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 24,
|
||||||
|
"path": "wizard-work/null/_probe12.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 25,
|
||||||
|
"path": "wizard-work/null/_probe13.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 26,
|
||||||
|
"path": "wizard-work/null/_probe14.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 27,
|
||||||
|
"path": "wizard-work/null/_probe5.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 28,
|
||||||
|
"path": "wizard-work/null/_probe6.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 29,
|
||||||
|
"path": "wizard-work/null/_probe7.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 30,
|
||||||
|
"path": "wizard-work/null/_probe8.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 31,
|
||||||
|
"path": "wizard-work/null/_probe9.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 32,
|
||||||
|
"path": "wizard-work/null/_probe_binding_defects.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 33,
|
||||||
|
"path": "wizard-work/null/_probe_gh1.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 34,
|
||||||
|
"path": "wizard-work/null/_probe_gh2.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 35,
|
||||||
|
"path": "wizard-work/null/_probe_gh3.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 36,
|
||||||
|
"path": "wizard-work/null/_probe_gh4.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 37,
|
||||||
|
"path": "wizard-work/null/_probe_gh5.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 38,
|
||||||
|
"path": "wizard-work/null/_probe_gh6.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 39,
|
||||||
|
"path": "wizard-work/null/_probe_gh7.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 40,
|
||||||
|
"path": "wizard-work/null/_probe_gh8.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 41,
|
||||||
|
"path": "wizard-work/null/_probe_gh9.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 42,
|
||||||
|
"path": "wizard-work/null/_probe_mut2.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 43,
|
||||||
|
"path": "wizard-work/null/_probe_mut_check.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 44,
|
||||||
|
"path": "wizard-work/null/_probe_q70_5h.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 45,
|
||||||
|
"path": "wizard-work/null/_probe_repro1.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 46,
|
||||||
|
"path": "wizard-work/null/_probe_repro2.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 47,
|
||||||
|
"path": "wizard-work/null/_probe_repro3.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 48,
|
||||||
|
"path": "wizard-work/null/_probe_repro4.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 49,
|
||||||
|
"path": "wizard-work/null/_probe_repro5.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 50,
|
||||||
|
"path": "wizard-work/null/_probe_repro6.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 51,
|
||||||
|
"path": "wizard-work/null/_probe_repro7.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 52,
|
||||||
|
"path": "wizard-work/null/check_gatehygiene.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 53,
|
||||||
|
"path": "wizard-work/null/check_provenance.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 54,
|
||||||
|
"path": "wizard-work/null/check_provenance_baseline.tsv"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 55,
|
||||||
|
"path": "wizard-work/null/check_provenance_ledger.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 56,
|
||||||
|
"path": "wizard-work/null/check_q62_scan.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 57,
|
||||||
|
"path": "wizard-work/null/cli_contract.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 58,
|
||||||
|
"path": "wizard-work/null/diffkit/__init__.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 59,
|
||||||
|
"path": "wizard-work/null/diffkit/_flatpkg.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 60,
|
||||||
|
"path": "wizard-work/null/diffkit/core.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 61,
|
||||||
|
"path": "wizard-work/null/diffkit/diffkit_cli.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 62,
|
||||||
|
"path": "wizard-work/null/diffkit/myers.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 63,
|
||||||
|
"path": "wizard-work/null/diffkit_gate.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 64,
|
||||||
|
"path": "wizard-work/null/gatehygiene.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 65,
|
||||||
|
"path": "wizard-work/null/json_salvage.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "other",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 66,
|
||||||
|
"path": "wizard-work/null/membershipkit/.hermes-tmp.sx2gIa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 67,
|
||||||
|
"path": "wizard-work/null/membershipkit/check_membershipkit.sh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 68,
|
||||||
|
"path": "wizard-work/null/membershipkit/mutate_membershipkit.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 69,
|
||||||
|
"path": "wizard-work/null/membershipkit/test_membershipkit.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 70,
|
||||||
|
"path": "wizard-work/null/mutate_resolver.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 71,
|
||||||
|
"path": "wizard-work/null/mutate_salvage.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 72,
|
||||||
|
"path": "wizard-work/null/q58_warncontrol.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 73,
|
||||||
|
"path": "wizard-work/null/q62_scan.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 74,
|
||||||
|
"path": "wizard-work/null/q70_sabotage.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 75,
|
||||||
|
"path": "wizard-work/null/q76_binding.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 76,
|
||||||
|
"path": "wizard-work/null/q80_warn.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 77,
|
||||||
|
"path": "wizard-work/null/revwalk.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 78,
|
||||||
|
"path": "wizard-work/null/test_gate.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 79,
|
||||||
|
"path": "wizard-work/null/test_gate_mutants.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 80,
|
||||||
|
"path": "wizard-work/null/test_json_salvage.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 81,
|
||||||
|
"path": "wizard-work/null/test_myers_diff.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 82,
|
||||||
|
"path": "wizard-work/null/test_revwalk.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 83,
|
||||||
|
"path": "wizard-work/null/verify_check_provenance.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "tooling",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 84,
|
||||||
|
"path": "wizard-work/null/verify_staged.py"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "other",
|
||||||
|
"decision": "review",
|
||||||
|
"id": 85,
|
||||||
|
"path": "wizard-work/quill/draft-compliance-report-2026-10-31.pin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "data",
|
||||||
|
"decision": "observe",
|
||||||
|
"id": 86,
|
||||||
|
"path": "wizard-work/sphinx/archive-mmlongcite-2026-10-25/probe_paper_facts.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lane": "Triage - everyday Q&A and classification",
|
||||||
|
"repo": "/root/troupe-standup",
|
||||||
|
"rule": "path-based deterministic classifier (see MODULE_DOCLINE)",
|
||||||
|
"rule_version": "1",
|
||||||
|
"summary": {
|
||||||
|
"data": 10,
|
||||||
|
"documentation": 7,
|
||||||
|
"gate": 3,
|
||||||
|
"other": 2,
|
||||||
|
"persistence": 1,
|
||||||
|
"tooling": 63,
|
||||||
|
"total": 86
|
||||||
|
},
|
||||||
|
"task": "classify untracked repo files into deterministic buckets"
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Untracked-file triage classification — 2026-11-02
|
||||||
|
|
||||||
|
Triaged **86** untracked, non-ignored files under `/root/troupe-standup`.
|
||||||
|
|
||||||
|
## Bucket counts
|
||||||
|
|
||||||
|
| category | decision | count |
|
||||||
|
|---|---|---|
|
||||||
|
| gate | approve | 3 |
|
||||||
|
| persistence | archive | 1 |
|
||||||
|
| data | observe | 10 |
|
||||||
|
| tooling | review | 63 |
|
||||||
|
| documentation | info | 7 |
|
||||||
|
| other | review | 2 |
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Rule: path-based deterministic classifier (see MODULE_DOCLINE).
|
||||||
|
- `corpus_sha256` is a sha256 over the canonical file list;
|
||||||
|
the independent verifier re-derives this, not the generator.
|
||||||
|
- Every classified path is re-checked as a real, untracked,
|
||||||
|
non-ignored file at run time; no path is trusted from memory.
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build Untracked-Triad-2026-11-02.json.
|
||||||
|
|
||||||
|
Triage: classify the untracked (git ??) regular files of the repo into
|
||||||
|
deterministic buckets, then write the machine-readable artifact.
|
||||||
|
|
||||||
|
Rule (deterministic, derived from the relative path only):
|
||||||
|
|
||||||
|
category:
|
||||||
|
gate path starts with "CHECK-"
|
||||||
|
persistence ends with ".db"
|
||||||
|
data ends with ".json", ".jsonl", ".tsv" or ".txt"
|
||||||
|
tooling ends with ".py" or ".sh"
|
||||||
|
documentation ends with ".md"
|
||||||
|
other anything else
|
||||||
|
|
||||||
|
decision:
|
||||||
|
gate -> approve
|
||||||
|
tooling -> review
|
||||||
|
documentation -> info
|
||||||
|
data -> observe
|
||||||
|
persistence -> archive
|
||||||
|
other -> review
|
||||||
|
|
||||||
|
The manifest snapshots the exact file list at generation time (files + a
|
||||||
|
sha256 of the canonical list) so the independent verifier can confirm the
|
||||||
|
artifact is a faithful, reproducible classification, not a hand-edited guess.
|
||||||
|
|
||||||
|
Outputs
|
||||||
|
-------
|
||||||
|
wizard-work/sol/Untracked-Triad-2026-11-02.json machine-readable manifest
|
||||||
|
wizard-work/sol/Untracked-Triad-2026-11-02.md human-readable summary
|
||||||
|
/root/.hermes/wizard-outputs/sol/Untracked-Triad-2026-11-02.json
|
||||||
|
identical shard read by the triage harness
|
||||||
|
|
||||||
|
Run: python3 build_untracked_triad_2026_11_02.py
|
||||||
|
"""
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
SOL_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
REPO_ROOT = os.path.dirname(os.path.dirname(SOL_DIR))
|
||||||
|
OUT_REPO = os.path.join(SOL_DIR, "Untracked-Triad-2026-11-02.json")
|
||||||
|
OUT_MD = os.path.join(SOL_DIR, "Untracked-Triad-2026-11-02.md")
|
||||||
|
OUT_WIZ = os.path.expanduser(
|
||||||
|
os.path.join("~", ".hermes", "wizard-outputs", "sol", "Untracked-Triad-2026-11-02.json")
|
||||||
|
)
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# universe & classification
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
def git_untracked(repo):
|
||||||
|
"""Return sorted list of untracked regular files, excluding this pipeline's
|
||||||
|
own files (wizard-work/sol/ subtree) and the CHECK gate so the snapshot is
|
||||||
|
a stable, reproducible classification rather than self-referential."""
|
||||||
|
proc = subprocess.run(
|
||||||
|
["git", "-C", repo, "status", "--porcelain=v1"],
|
||||||
|
check=True, capture_output=True, text=True,
|
||||||
|
)
|
||||||
|
files = []
|
||||||
|
for line in proc.stdout.splitlines():
|
||||||
|
if line.startswith("??"):
|
||||||
|
path = line[3:].strip()
|
||||||
|
if path.endswith("/"):
|
||||||
|
continue # untracked directories
|
||||||
|
if path.startswith("wizard-work/sol/"):
|
||||||
|
continue # this pipeline's own files (incl. manifest/verifier/build)
|
||||||
|
if os.path.basename(path) == "CHECK-2026-11-02-untracked-triad":
|
||||||
|
continue # the CHECK gate, committed alongside the manifest
|
||||||
|
files.append(path)
|
||||||
|
return sorted(files)
|
||||||
|
|
||||||
|
|
||||||
|
def category_of(rel):
|
||||||
|
low = rel.lower()
|
||||||
|
if low.startswith("check-"):
|
||||||
|
return "gate"
|
||||||
|
if low.endswith(".db"):
|
||||||
|
return "persistence"
|
||||||
|
if low.endswith((".json", ".jsonl", ".tsv", ".txt")):
|
||||||
|
return "data"
|
||||||
|
if low.endswith((".py", ".sh")):
|
||||||
|
return "tooling"
|
||||||
|
if low.endswith(".md"):
|
||||||
|
return "documentation"
|
||||||
|
return "other"
|
||||||
|
|
||||||
|
|
||||||
|
DECISION = {
|
||||||
|
"gate": "approve",
|
||||||
|
"tooling": "review",
|
||||||
|
"documentation": "info",
|
||||||
|
"data": "observe",
|
||||||
|
"persistence": "archive",
|
||||||
|
"other": "review",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build(files):
|
||||||
|
items = []
|
||||||
|
for i, rel in enumerate(files, start=1):
|
||||||
|
cat = category_of(rel)
|
||||||
|
items.append({"id": i, "path": rel, "category": cat, "decision": DECISION[cat]})
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def corpus_sha256(files):
|
||||||
|
canon = json.dumps({"files": files}, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
||||||
|
return hashlib.sha256(canon).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# output writers
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
def write_json(obj, path):
|
||||||
|
with open(path, "w", encoding="utf-8") as fh:
|
||||||
|
json.dump(obj, fh, indent=2, sort_keys=True)
|
||||||
|
fh.write("\n")
|
||||||
|
|
||||||
|
|
||||||
|
def write_md(manifest, path):
|
||||||
|
s = manifest["summary"]
|
||||||
|
lines = []
|
||||||
|
lines.append("# Untracked-file triage classification — 2026-11-02")
|
||||||
|
lines.append("")
|
||||||
|
lines.append("Triaged **%d** untracked, non-ignored files under `%s`." % (
|
||||||
|
s.get("total", 0), manifest["repo"]))
|
||||||
|
lines.append("")
|
||||||
|
lines.append("## Bucket counts")
|
||||||
|
lines.append("")
|
||||||
|
lines.append("| category | decision | count |")
|
||||||
|
lines.append("|---|---|---|")
|
||||||
|
for cat in ["gate", "persistence", "data", "tooling", "documentation", "other"]:
|
||||||
|
lines.append("| %s | %s | %d |" % (
|
||||||
|
cat, DECISION[cat], s.get(cat, 0)))
|
||||||
|
lines.append("")
|
||||||
|
lines.append("## Notes")
|
||||||
|
lines.append("")
|
||||||
|
lines.append("- Rule: path-based deterministic classifier (see MODULE_DOCLINE).")
|
||||||
|
lines.append("- `corpus_sha256` is a sha256 over the canonical file list;")
|
||||||
|
lines.append(" the independent verifier re-derives this, not the generator.")
|
||||||
|
lines.append("- Every classified path is re-checked as a real, untracked,")
|
||||||
|
lines.append(" non-ignored file at run time; no path is trusted from memory.")
|
||||||
|
lines.append("")
|
||||||
|
with open(path, "w", encoding="utf-8") as fh:
|
||||||
|
fh.write("\n".join(lines))
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# main
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
def main():
|
||||||
|
files = git_untracked(REPO_ROOT)
|
||||||
|
items = build(files)
|
||||||
|
summary = {"total": len(files)}
|
||||||
|
for it in items:
|
||||||
|
summary[it["category"]] = summary.get(it["category"], 0) + 1
|
||||||
|
manifest = {
|
||||||
|
"artifact": "Untracked-Triad-2026-11-02.json",
|
||||||
|
"corpus_sha256": corpus_sha256(files),
|
||||||
|
"files": files,
|
||||||
|
"items": items,
|
||||||
|
"lane": "Triage - everyday Q&A and classification",
|
||||||
|
"repo": REPO_ROOT,
|
||||||
|
"rule": "path-based deterministic classifier (see MODULE_DOCLINE)",
|
||||||
|
"rule_version": "1",
|
||||||
|
"summary": summary,
|
||||||
|
"task": "classify untracked repo files into deterministic buckets",
|
||||||
|
"built_at": datetime.now(timezone.utc).isoformat(),
|
||||||
|
}
|
||||||
|
write_json(manifest, OUT_REPO)
|
||||||
|
write_md(manifest, OUT_MD)
|
||||||
|
|
||||||
|
# identical shard to the triage harness
|
||||||
|
shutil.copyfile(OUT_REPO, OUT_WIZ)
|
||||||
|
with open(OUT_REPO, "rb") as a, open(OUT_WIZ, "rb") as b:
|
||||||
|
if a.read() != b.read():
|
||||||
|
sys.exit("shard parity mismatch: %s vs %s" % (OUT_REPO, OUT_WIZ))
|
||||||
|
print("wrote: %s (%d files)" % (OUT_REPO, len(files)))
|
||||||
|
print("wrote: %s" % OUT_MD)
|
||||||
|
print("shard: %s" % OUT_WIZ)
|
||||||
|
print("buckets: %s" % json.dumps(summary, sort_keys=True))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Independent verifier for Untracked-Triad-2026-11-02.json.
|
||||||
|
|
||||||
|
The classification rule is re-derived from each item's path (the generator's
|
||||||
|
stored category/decision fields are NOT trusted). A wrong classification makes
|
||||||
|
this exit non-zero. Additionally every classified path must still exist on disk
|
||||||
|
as a real, untracked, non-ignored file, and the wizard-outputs shard must
|
||||||
|
match the repo manifest byte-for-byte.
|
||||||
|
|
||||||
|
Exit 0 iff all checks pass.
|
||||||
|
"""
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
MANIFEST = os.path.join(HERE, "Untracked-Triad-2026-11-02.json")
|
||||||
|
OUT_WIZ = os.path.expanduser(
|
||||||
|
os.path.join("~", ".hermes", "wizard-outputs", "sol", "Untracked-Triad-2026-11-02.json")
|
||||||
|
)
|
||||||
|
REPO_ROOT = os.path.dirname(os.path.dirname(HERE))
|
||||||
|
|
||||||
|
|
||||||
|
def cat_of(rel):
|
||||||
|
low = rel.lower()
|
||||||
|
if low.startswith("check-"):
|
||||||
|
return "gate"
|
||||||
|
if low.endswith(".db"):
|
||||||
|
return "persistence"
|
||||||
|
if low.endswith((".json", ".jsonl", ".tsv", ".txt")):
|
||||||
|
return "data"
|
||||||
|
if low.endswith((".py", ".sh")):
|
||||||
|
return "tooling"
|
||||||
|
if low.endswith(".md"):
|
||||||
|
return "documentation"
|
||||||
|
return "other"
|
||||||
|
|
||||||
|
|
||||||
|
DECISION = {
|
||||||
|
"gate": "approve",
|
||||||
|
"tooling": "review",
|
||||||
|
"documentation": "info",
|
||||||
|
"data": "observe",
|
||||||
|
"persistence": "archive",
|
||||||
|
"other": "review",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def git_status_untracked(repo):
|
||||||
|
proc = subprocess.run(
|
||||||
|
["git", "-C", repo, "status", "--porcelain=v1"], capture_output=True, text=True)
|
||||||
|
return set(line[3:].strip() for line in proc.stdout.splitlines()
|
||||||
|
if line.startswith("??") and not line[3:].strip().endswith("/"))
|
||||||
|
|
||||||
|
|
||||||
|
def git_check_ignored(repo, rel):
|
||||||
|
proc = subprocess.run(["git", "-C", repo, "check-ignore", "-q", rel], capture_output=True)
|
||||||
|
return proc.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
with open(MANIFEST, encoding="utf-8") as fh:
|
||||||
|
man = json.load(fh)
|
||||||
|
except Exception as exc:
|
||||||
|
print("FAIL: cannot load manifest:", exc)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
files = man.get("files", [])
|
||||||
|
items = man.get("items", [])
|
||||||
|
repo = man.get("repo", REPO_ROOT)
|
||||||
|
recorded_sha = man.get("corpus_sha256")
|
||||||
|
|
||||||
|
# 1. corpus sha256 must match the recorded file list
|
||||||
|
canon = json.dumps({"files": sorted(files)}, sort_keys=True,
|
||||||
|
separators=(",", ":")).encode("utf-8")
|
||||||
|
computed_sha = hashlib.sha256(canon).hexdigest()
|
||||||
|
if computed_sha != recorded_sha:
|
||||||
|
errors.append("corpus_sha256 mismatch (recorded %s vs computed %s)"
|
||||||
|
% (recorded_sha, computed_sha))
|
||||||
|
|
||||||
|
# 2. ids must be unique and exactly 1..N
|
||||||
|
ids = [it.get("id") for it in items]
|
||||||
|
if sorted(ids) != list(range(1, len(items) + 1)):
|
||||||
|
errors.append("ids are not exactly 1..N")
|
||||||
|
|
||||||
|
# 3. re-derive category/decision from each path and verify file state
|
||||||
|
for it in items:
|
||||||
|
rel = it.get("path")
|
||||||
|
exp_cat = it.get("category")
|
||||||
|
exp_dec = it.get("decision")
|
||||||
|
if not rel:
|
||||||
|
errors.append("missing path on item id=%r" % (it.get("id"),))
|
||||||
|
continue
|
||||||
|
act_cat = cat_of(rel)
|
||||||
|
act_dec = DECISION.get(act_cat)
|
||||||
|
if exp_cat != act_cat:
|
||||||
|
errors.append("id=%s path=%s category %s != re-derived %s"
|
||||||
|
% (it.get("id"), rel, exp_cat, act_cat))
|
||||||
|
if exp_dec != act_dec:
|
||||||
|
errors.append("id=%s path=%s decision %s != re-derived %s"
|
||||||
|
% (it.get("id"), rel, exp_dec, act_dec))
|
||||||
|
if not os.path.isfile(os.path.join(repo, rel)):
|
||||||
|
errors.append("id=%s path=%s does not exist as a real file"
|
||||||
|
% (it.get("id"), rel))
|
||||||
|
if rel not in git_status_untracked(repo):
|
||||||
|
errors.append("id=%s path=%s is not currently untracked"
|
||||||
|
% (it.get("id"), rel))
|
||||||
|
if git_check_ignored(repo, rel):
|
||||||
|
errors.append("id=%s path=%s is git-ignored" % (it.get("id"), rel))
|
||||||
|
|
||||||
|
# 4. summary counts must match items (skip the "total" key, which is the
|
||||||
|
# corpus size, not a category).
|
||||||
|
from collections import Counter
|
||||||
|
CAT_KEYS = {"gate", "persistence", "data", "tooling", "documentation", "other"}
|
||||||
|
cnt = Counter(it.get("category") for it in items)
|
||||||
|
for cat, n in man.get("summary", {}).items():
|
||||||
|
if cat not in CAT_KEYS:
|
||||||
|
continue
|
||||||
|
if cnt.get(cat, 0) != n:
|
||||||
|
errors.append("summary %s=%d but items have %d"
|
||||||
|
% (cat, n, cnt.get(cat, 0)))
|
||||||
|
|
||||||
|
# 5. shard parity: the wizard-outputs copy must be byte-identical.
|
||||||
|
if os.path.exists(OUT_WIZ):
|
||||||
|
with open(MANIFEST, "rb") as a, open(OUT_WIZ, "rb") as b:
|
||||||
|
if a.read() != b.read():
|
||||||
|
errors.append("shard parity FAIL: %s != %s" % (MANIFEST, OUT_WIZ))
|
||||||
|
else:
|
||||||
|
errors.append("shard missing: %s" % OUT_WIZ)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print("FAIL: %d problem(s)" % len(errors))
|
||||||
|
for e in errors[:40]:
|
||||||
|
print(" -", e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("PASS: %d files classified; %d re-derive to matching category/decision; "
|
||||||
|
"all files real, untracked, non-ignored; corpus sha256 matches; "
|
||||||
|
"shard byte-identical." % (len(files), len(items)))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in new issue
Block a user