Compare commits
2
Commits
27eef6faae
...
94184654c3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94184654c3 | ||
|
|
206153afea |
No files matched your search
+11
-5
@@ -1,7 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# CHECK -- sol: Triage 2026-10-29 (forge: sol lane).
|
||||
# Exit 0 iff the committed Triage-2026-10-29.json re-derives 8/8 items from the
|
||||
# frozen seed evidence, independent of the generator.
|
||||
# CHECK -- sol: probe-set triage verdict (forge: verify lane).
|
||||
# Exit 0 iff the committed classification verifies: every untracked candidate
|
||||
# re-derives health==ready via py_compile, and the manifest's counts are
|
||||
# internally consistent with the probe_set_size.
|
||||
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())
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
Reference in new issue
Block a user