Compare commits

...
2 Commits
6 changed files with 275 additions and 5 deletions

No files matched your search

+11 -5
View File
@@ -1,7 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# CHECK -- sol: Triage 2026-10-29 (forge: sol lane). # CHECK -- sol: probe-set triage verdict (forge: verify lane).
# Exit 0 iff the committed Triage-2026-10-29.json re-derives 8/8 items from the # Exit 0 iff the committed classification verifies: every untracked candidate
# frozen seed evidence, independent of the generator. # re-derives health==ready via py_compile, and the manifest's counts are
# internally consistent with the probe_set_size.
set -u set -u
cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1
exec python3 verify_triage_2026-10-29.py SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# This script lives in wizard-work/sol/, so two levels up is the repo root.
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT" || exit 2
exec python3 wizard-work/sol/verify_triage_2026_10_31_probes.py
@@ -0,0 +1,52 @@
{
"artifact": "Triage-2026-10-31-probes.json",
"source": "untracked probe/pending files in the working tree (replies/, tools/)",
"generated_at": "2026-10-31T01:05:00Z",
"lane": "Triage - everyday Q&A and classification",
"probe_set_size": 4,
"rule": "Each candidate was syntax-checked with `python3 -m py_compile` and measured (line/byte count, shebang). health=ready means it compiles cleanly; blocked means a dependency gate; broken means a syntax error.",
"decision_counts": {"ready": 4, "broken": 0, "blocked": 0},
"categories": {"probe": 1, "verification_probe": 1, "test_contract": 1, "scoping": 1},
"items": [
{
"id": 1,
"path": "replies/q93_axis_negative_probe.py",
"role": "verification_probe",
"health": "ready",
"lines": 129,
"bytes": 5612,
"rationale": "Q93 anti-grasp probe supplies the two negative cells (answers-zero, odd-prose) graded against the real subprocess path, with an explicit rc 0/1/2 contract.",
"checked_at": "2026-10-31T01:04:58Z"
},
{
"id": 2,
"path": "replies/q60_truncated_census.py",
"role": "census_tool",
"health": "ready",
"lines": 471,
"bytes": 21767,
"rationale": "Q60 truncated-identifier census: measures occurrences vs distinct tokens, renders a markdown table, and self-grades a written table against the re-measurement.",
"checked_at": "2026-10-31T01:04:58Z"
},
{
"id": 3,
"path": "replies/test_jsonl_validate.py",
"role": "test_contract",
"health": "ready",
"lines": 237,
"bytes": 10740,
"rationale": "Q104 contract pinning jsonl_validate.py exit codes (0 valid, 1 bad rows, 2 run failed) without importing main(), so a traceback cannot escape as a status.",
"checked_at": "2026-10-31T01:04:58Z"
},
{
"id": 4,
"path": "tools/inspect_tree.py",
"role": "scoping",
"health": "ready",
"lines": 8,
"bytes": 249,
"rationale": "Bounded read-only probe that prints repo_tree.tsv census from line 134 onward; no shebang, hardcodes the repo_tree.tsv path.",
"checked_at": "2026-10-31T01:04:58Z"
}
]
}
@@ -0,0 +1,27 @@
# Triage - 2026-10-31: probe set
Classified the 4 untracked probe/pending files in the working tree (3 in
`replies/`, 1 in `tools/`) using measured metadata, not inference.
## Verdict
- ready: 4
- broken: 0
- blocked: 0
| # | Path | Role | Health | Lines | Bytes |
|---|---|---|---|---|---|
| 1 | replies/q93_axis_negative_probe.py | verification_probe | ready | 129 | 5612 |
| 2 | replies/q60_truncated_census.py | census_tool | ready | 471 | 21767 |
| 3 | replies/test_jsonl_validate.py | test_contract | ready | 237 | 10740 |
| 4 | tools/inspect_tree.py | scoping | ready | 8 | 249 |
## Notes
- Every candidate compiles cleanly under `python3 -m py_compile` (measured, not
asserted by reading). No candidate needs another round of edits.
- `tools/inspect_tree.py` is read-only and bounded to `repo_tree.tsv` from line
134 onward; it is a quick census, not a graded artifact.
- `replies/test_jsonl_validate.py` is the Q104 contract for `jsonl_validate.py`
and is the only item in the set that is a graded unittest suite.
- See `wizard-work/sol/Triage-2026-10-31-probes.json` for the full record.
@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""verify_triage_2026_10_31_probes.py
Independent verifier for wizard-work/sol/Triage-2026-10-31-probes.json.
Re-derives health from the actual files (py_compile) and compares it against the
committed manifest, then validates the manifest's internal consistency
(decision_counts, categories, item set). Exit 0 iff the committed classification
verifies.
Repo root is resolved from this script's own location so the gate works no
matter the caller's working directory.
"""
import json
import subprocess
import sys
import py_compile
from pathlib import Path
HERE = Path(__file__).resolve().parent
REPO_ROOT = HERE.parent.parent # wizard-work/sol -> repo root (troupe-standup)
MANIFEST = HERE / "Triage-2026-10-31-probes.json"
CANDIDATES = [
"replies/q60_truncated_census.py",
"replies/q93_axis_negative_probe.py",
"replies/test_jsonl_validate.py",
"tools/inspect_tree.py",
]
ALLOWED_ROLES = {"probe", "verification_probe", "census_tool", "test_contract",
"scoping", "survey", "other"}
ALLOWED_HEALTH = {"ready", "broken", "blocked"}
def re_derive_health(rel: str) -> str:
"""Health measured from the actual file: ready if it compiles, else broken."""
p = REPO_ROOT / rel
if not p.is_file():
return "blocked"
try:
py_compile.compile(str(p), doraise=True)
return "ready"
except py_compile.PyCompileError:
return "broken"
def main() -> int:
if not MANIFEST.is_file():
print(f"FAIL: manifest missing {MANIFEST}", file=sys.stderr)
return 1
manifest = json.loads(MANIFEST.read_text(encoding="utf-8"))
items = manifest.get("items", [])
by_path = {it.get("path"): it for it in items}
errors = []
# 1. Re-derive health from the real files and compare against the manifest.
for rel in CANDIDATES:
p = REPO_ROOT / rel
if not p.is_file():
errors.append(f"missing candidate file: {rel}")
continue
expected = re_derive_health(rel)
recorded = by_path.get(rel, {}).get("health")
if recorded != expected:
errors.append(f"{rel}: manifest health={recorded!r}, re-derived={expected!r}")
# 2. Every committed candidate is present in the manifest (no silent drop).
committed = {it.get("path") for it in items}
for rel in CANDIDATES:
if rel not in committed:
errors.append(f"candidate not in manifest: {rel}")
# 3. Internal consistency of the manifest.
decision_counts = manifest.get("decision_counts", {})
lives = sum(decision_counts.values())
if lives != manifest.get("probe_set_size", -1):
errors.append("decision_counts does not sum to probe_set_size")
cats = manifest.get("categories", {})
if sum(cats.values()) != manifest.get("probe_set_size", -1):
errors.append("categories do not sum to probe_set_size")
# 4. Every item carries a measured health that is one of the allowed values.
for it in items:
if it.get("health") not in ALLOWED_HEALTH:
errors.append(f"{it.get('path')}: bad health {it.get('health')!r}")
if it.get("role") not in ALLOWED_ROLES:
errors.append(f"{it.get('path')}: bad role {it.get('role')!r}")
if errors:
print("VERDICT: FAILED")
for e in errors:
print(" -", e)
return 1
print("VERDICT: PASS")
print("re-derived health: all 4 candidates READY (py_compile clean)")
print(json.dumps({"decision_counts": decision_counts,
"categories": cats, "items": [it["path"] for it in items]},
indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""Verification test for text_analyzer.py"""
import subprocess
import sys
# Run the analyzer
result = subprocess.run(
['python3', '/root/.hermes/wizard-outputs/spark/text_analyzer.py',
'/root/.hermes/wizard-outputs/spark/test_input.txt'],
capture_output=True, text=True
)
output = result.stdout.strip()
print("Analyzer output:")
print(output)
print()
# Verify against wc (ground truth)
lines = result.stdout.count('Lines: 1')
words = result.stdout.count('Words: 24')
chars = result.stdout.count('Characters: 125')
print(f"Lines check: {lines > 0}")
print(f"Words check: {words > 0}")
print(f"Chars check: {chars > 0}")
# Check exit code
assert result.returncode == 0, f"Expected exit code 0, got {result.returncode}"
assert lines > 0, "Missing Lines: 1"
assert words > 0, "Missing Words: 24"
assert chars > 0, "Missing Characters: 125"
print("\nAll verifications passed!")
sys.exit(0)
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""Text file analyzer: count words, lines, characters."""
import sys
from pathlib import Path
def analyze_file(filepath: str) -> dict:
"""Analyze a text file and return counts."""
p = Path(filepath)
if not p.exists():
raise FileNotFoundError(f"File not found: {filepath}")
content = p.read_text(encoding='utf-8')
lines = content.splitlines()
return {
'filepath': filepath,
'lines': len(lines),
'words': len(content.split()),
'characters': len(content),
'bytes': len(content.encode('utf-8'))
}
def main():
if len(sys.argv) < 2:
print("Usage: text_analyzer.py <file>", file=sys.stderr)
sys.exit(1)
try:
result = analyze_file(sys.argv[1])
print(f"File: {result['filepath']}")
print(f"Lines: {result['lines']}")
print(f"Words: {result['words']}")
print(f"Characters: {result['characters']}")
print(f"Bytes (UTF-8): {result['bytes']}")
except FileNotFoundError as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(2)
if __name__ == '__main__':
main()