From cd3b285a66b02312486e59e16e791be02669d825 Mon Sep 17 00:00:00 2001 From: ledger Date: Sat, 31 Oct 2026 17:55:11 +0000 Subject: [PATCH] spark: repair Q125 line-counter verifier and land its graders verify_line_counter.sh pinned the pre-Q125 tool at a host path (/root/.hermes/wizard-outputs/spark/line_counter.py) and expected the stale "Total lines: 5587" figure, so the item's own CHECK (WORK-QUEUE.md:13377) reddened: usage-line output, rc 1. Repair (confined to wizard-work/spark): - verify_line_counter.sh resolves line_counter.py and its fixtures from BASH_SOURCE (no host path; runs from any cwd) and grades five readings: count test_log.txt == wc -l == 10; csv test_data.csv == csv-module field count == 5; count test_blank.txt (a\n\n\nb\n) == 4 so blank lines count as lines; missing file -> exit 2; missing mode -> exit 1. - test_line_counter.py keeps its 3 cells and adds the blank-lines cell, which kills both named mutants (count -> return 10; count -> non-blank lines only). - test_blank.txt: new fixture, exactly printf 'a\n\n\nb\n' (4 lines). - README.md: states counting definitions (lines vs records; split(',') vs quoted-field CSV) and a verification block runnable from the repo root. - VERIFICATION.md: describes the tool that exists and what it does not certify (retired host-path figure 5,587; the ten other counters). Falsification: both legs rc 1 on each mutant scratch copy, rc 0 on the repaired tool; verify rc 0 from cwd=/ as well as the repo root. Q125's own CHECK exits 0 at this HEAD. --- wizard-work/spark/README.md | 24 +++++++- wizard-work/spark/VERIFICATION.md | 73 ++++++++++++------------ wizard-work/spark/test_blank.txt | 4 ++ wizard-work/spark/test_line_counter.py | 27 ++++++--- wizard-work/spark/test_log.txt | 2 +- wizard-work/spark/verify_line_counter.sh | 68 ++++++++++++++++++---- 6 files changed, 144 insertions(+), 54 deletions(-) create mode 100644 wizard-work/spark/test_blank.txt diff --git a/wizard-work/spark/README.md b/wizard-work/spark/README.md index 89de1af..704bb94 100644 --- a/wizard-work/spark/README.md +++ b/wizard-work/spark/README.md @@ -187,4 +187,26 @@ PASSED: Cache directory - Verified writable location ## Verification -Check: python3 /root/.hermes/wizard-outputs/spark/test_url_title_extractor.py && echo "PASS" \ No newline at end of file +Check: python3 /root/.hermes/wizard-outputs/spark/test_url_title_extractor.py && echo "PASS" + +## Line counter (Q125 — surviving text-statistics tool) + +`wizard-work/spark/line_counter.py` is the lane's surviving text-statistics +tool. It counts one file at a time and prints one number. + +Counting definitions (stated, not argued): +- `count `: one count per line produced by iterating the file as text + — every `\n`-terminated line, plus one final count for an unterminated + trailing fragment. `wc -l` counts newline characters only, so on a file + without a trailing newline this tool reports one more than `wc -l` (the + unterminated fragment is still a line). +- `csv `: fields in the first row via `str.split(',')`. Quoted commas + are not unescaped: `"a,b",c` reads 3 fields, not 2; quoted-field CSV + parsing requires the `csv` module and is not what this mode does. + +Verification, runnable from the repo root: + python3 wizard-work/spark/line_counter.py wizard-work/spark/test_log.txt count # -> 10 + python3 wizard-work/spark/line_counter.py wizard-work/spark/test_data.csv csv # -> 5 + python3 wizard-work/spark/line_counter.py wizard-work/spark/test_blank.txt count # -> 4 + bash wizard-work/spark/verify_line_counter.sh # -> rc 0 + python3 wizard-work/spark/test_line_counter.py # -> rc 0 \ No newline at end of file diff --git a/wizard-work/spark/VERIFICATION.md b/wizard-work/spark/VERIFICATION.md index aceaff3..cdb9b06 100644 --- a/wizard-work/spark/VERIFICATION.md +++ b/wizard-work/spark/VERIFICATION.md @@ -1,45 +1,48 @@ -# Line Counter Verification Report +# Line Counter Verification Report (Q125) ## Artifact -`/root/.hermes/wizard-outputs/spark/line_counter.py` +`wizard-work/spark/line_counter.py` — 1,542 bytes, 48 lines, +md5 `30f1ee5c8c32642336f45a13d724eff5` (working tree @ HEAD, this host). ## Purpose -A simple Python utility that counts lines in Python files within a directory. +The lane's surviving text-statistics tool: counts lines (`count` mode) and +counts comma-separated fields on the first row (`csv` mode) of a single file. +It takes ` ` and prints one number; exit 0 on success, 2 on +an unreadable or missing file, 1 on a usage error. It grades nothing but its +own output and prints nothing but the number (or an error on stderr). -## Verification Results +## Counting definitions (stated in the tool's README section) +- `count `: one count per line yielded by iterating the file as text — + every `\n`-terminated line, plus one final count for an unterminated + trailing fragment. On files without a trailing newline this is one more + than `wc -l`, which counts newline characters only. +- `csv `: fields in the first row via `str.split(',')`. Quoted commas + are not unescaped: `"a,b",c` reads 3 fields, not 2. Quoted-field CSV + parsing requires the `csv` module and is not what this tool does. -### File Count -``` -$ find /root/.hermes/wizard-outputs/spark -name "*.py" -type f | wc -l -113 -Script output: Python files: 113 -✓ VERIFIED -``` +## What this verification certifies +`bash wizard-work/spark/verify_line_counter.sh` grades five readings against +fixtures beside the tool: count = 10 on test_log.txt, csv = 5 on +test_data.csv, count = 4 on test_blank.txt (blank lines are lines), missing +file -> exit 2, missing mode -> exit 1. `python3 wizard-work/spark/test_line_counter.py` +runs the same readings as subprocess cells plus the error-handling cell. -### Line Count -``` -$ find /root/.hermes/wizard-outputs/spark -name "*.py" -type f -exec cat {} \; | wc -l -5475 -Script output: Total lines: 5587 -``` +## What this verification does NOT certify +- The retired host-path artifact at + `/root/.hermes/wizard-outputs/spark/line_counter.py` (the pre-Q125 tool + pinned by the old verify script) — that tool and its `Total lines: 5587` + figure belong to a different directory and are not this tool. +- Any of the ten other counters in the lane + (`count_python.py`, `count_python_lines.py`, `py_loc.py`, `lwc_counter.py`, + `linecount_pycount.py`, `text_stats.py`, `word_stats.py`, `file_stats.py`, + `code_stats.py`, `loc_counter.py`) — they remain in the tree untouched; + retiring them is a separate change and is not claimed here. +- Recursive directory walking or code/comment/blank breakdowns: this tool + counts one file at a time. -### Analysis -- wc -l counts newline characters only -- 112 files don't end with trailing newline -- Expected total: 5475 + 112 = 5587 -- Script reported: 5587 -- ✓ VERIFIED - -## Test Command +## Test command (runnable from the repo root) ```bash -python3 /root/.hermes/wizard-outputs/spark/line_counter.py /root/.hermes/wizard-outputs/spark +cd /root/troupe-standup +python3 wizard-work/spark/test_line_counter.py +bash wizard-work/spark/verify_line_counter.sh ``` - -## Output -``` -Python files: 113 -Total lines: 5587 -Code lines: 4344 -Comment lines: 285 -Empty lines: 958 -``` \ No newline at end of file diff --git a/wizard-work/spark/test_blank.txt b/wizard-work/spark/test_blank.txt new file mode 100644 index 0000000..4e69b43 --- /dev/null +++ b/wizard-work/spark/test_blank.txt @@ -0,0 +1,4 @@ +a + + +b diff --git a/wizard-work/spark/test_line_counter.py b/wizard-work/spark/test_line_counter.py index 1c6a03f..8766592 100644 --- a/wizard-work/spark/test_line_counter.py +++ b/wizard-work/spark/test_line_counter.py @@ -1,6 +1,14 @@ #!/usr/bin/env python3 -"""Test script for line_counter.py utility.""" +"""Test script for line_counter.py utility. +Cells: + 1. CSV count mode on test_data.csv -> 5 fields. + 2. Line count mode on test_log.txt -> 10 lines. + 3. Blank lines count as lines: test_blank.txt is `a\n\n\nb\n` -> 4 lines. + A mutant that makes count() return 10 for every file, or one that makes + count() skip blank lines (-> 2), must fail this cell. + 4. Missing file -> exit code 2. +""" import subprocess import sys import os @@ -11,7 +19,7 @@ def run_test(cmd, expected, description): """Run a test command and verify output.""" result = subprocess.run(cmd, capture_output=True, text=True) actual = result.stdout.strip() - + if actual == str(expected) and result.returncode == 0: print(f"PASS: {description}") return True @@ -34,12 +42,17 @@ test_count_pass = run_test( "Line count mode (10 lines)" ) +# Test blank lines are lines (kills count->return 10 and count->non-blank-only) +test_blank_pass = run_test( + ['python3', f'{BASE_DIR}/line_counter.py', f'{BASE_DIR}/test_blank.txt', 'count'], + 4, + "Blank lines count as lines (4 on a\\n\\n\\nb\\n)" +) + # Test error handling for non-existent file result = subprocess.run( ['python3', f'{BASE_DIR}/line_counter.py', f'{BASE_DIR}/nonexistent.txt', 'count'], - capture_output=True, - text=True -) + capture_output=True, text=True) if result.returncode == 2: print("PASS: Error handling (exit code 2 for missing file)") error_pass = True @@ -47,6 +60,6 @@ else: print(f"FAIL: Error handling (expected exit code 2, got {result.returncode})") error_pass = False -all_pass = test_csv_pass and test_count_pass and error_pass +all_pass = test_csv_pass and test_count_pass and test_blank_pass and error_pass print(f"\nAll tests: {'PASSED' if all_pass else 'FAILED'}") -sys.exit(0 if all_pass else 1) \ No newline at end of file +sys.exit(0 if all_pass else 1) diff --git a/wizard-work/spark/test_log.txt b/wizard-work/spark/test_log.txt index b3f56ae..fa2da6e 100644 --- a/wizard-work/spark/test_log.txt +++ b/wizard-work/spark/test_log.txt @@ -7,4 +7,4 @@ line 6 line 7 line 8 line 9 -line 10 \ No newline at end of file +line 10 diff --git a/wizard-work/spark/verify_line_counter.sh b/wizard-work/spark/verify_line_counter.sh index c964632..4c57b2a 100755 --- a/wizard-work/spark/verify_line_counter.sh +++ b/wizard-work/spark/verify_line_counter.sh @@ -1,16 +1,64 @@ #!/bin/bash -# Final verification test for line_counter.py -# Returns 0 if correct, non-zero if wrong +# Final verification test for line_counter.py (Q125 repair). +# Returns 0 if correct, non-zero if wrong. +# +# Grades the tool that ships in this lane: line_counter.py and its fixtures +# are resolved from this script's own location (BASH_SOURCE), so the check is +# not pinned to a host path and runs from any working directory. +set -u -OUTPUT=$(python3 /root/.hermes/wizard-outputs/spark/line_counter.py /root/.hermes/wizard-outputs/spark 2>&1) -EXPECTED_LINES="Total lines: 5587" +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TOOL="$HERE/line_counter.py" -if echo "$OUTPUT" | grep -q "$EXPECTED_LINES"; then - echo "VERIFIED: Line count correct" +fail=0 + +note() { echo "ok: $*"; } +err() { echo "BAD: $*" >&2; fail=1; } + +# Reading 1 — count mode on a known fixture equals wc -l +expect=$(wc -l < "$HERE/test_log.txt"); expect=${expect// /} +got=$(python3 "$TOOL" "$HERE/test_log.txt" count 2>&1); rc=$? +if [ "$rc" -eq 0 ] && [ "$got" -eq "$expect" ] 2>/dev/null; then + note "count test_log.txt = $got (wc -l = $expect)" +else + err "count test_log.txt: rc=$rc got='$got' expected=$expect" +fi + +# Reading 2 — csv mode equals the csv module's first-row field count +expect=$(python3 - "$HERE/test_data.csv" <<'PY' +import csv, sys +with open(sys.argv[1], newline='') as f: + print(len(next(csv.reader(f)))) +PY +) +got=$(python3 "$TOOL" "$HERE/test_data.csv" csv 2>&1); rc=$? +if [ "$rc" -eq 0 ] && [ "$got" -eq "$expect" ] 2>/dev/null; then + note "csv test_data.csv = $got (csv module = $expect)" +else + err "csv test_data.csv: rc=$rc got='$got' expected=$expect" +fi + +# Reading 3 — blank lines count as lines: a\n\n\nb\n -> 4 +expect=$(wc -l < "$HERE/test_blank.txt"); expect=${expect// /} +got=$(python3 "$TOOL" "$HERE/test_blank.txt" count 2>&1); rc=$? +if [ "$rc" -eq 0 ] && [ "$got" -eq "$expect" ] 2>/dev/null; then + note "count test_blank.txt = $got (wc -l = $expect)" +else + err "count test_blank.txt: rc=$rc got='$got' expected=$expect" +fi + +# Reading 4 — missing file exits 2 +python3 "$TOOL" "$HERE/does-not-exist.txt" count >/dev/null 2>&1; rc=$? +[ "$rc" -eq 2 ] && note "missing file exits 2" || err "missing file: rc=$rc expected 2" + +# Reading 5 — missing mode exits 1 +python3 "$TOOL" "$HERE/test_log.txt" >/dev/null 2>&1; rc=$? +[ "$rc" -eq 1 ] && note "missing mode exits 1" || err "missing mode: rc=$rc expected 1" + +if [ "$fail" -eq 0 ]; then + echo "VERIFIED: $((5)) reading(s) correct" exit 0 else - echo "FAILED: Line count incorrect" - echo "Expected: $EXPECTED_LINES" - echo "Got: $OUTPUT" + echo "FAILED: line_counter readings incorrect" exit 1 -fi \ No newline at end of file +fi