Reported by kuhy: "I run run.sh and I have no idea where the actual program is
and how to run it". In EPFU that was one `gcc -Wall -Wextra -pedantic main.c`
line and nothing else -- the makefile has no -o, so the binary is an a.out that
nothing mentions, and it was never executed.
Two separate failures, both fixed.
Building is not running. make, cxx, maven and dotnet built and stopped; make,
maven and dotnet did not even print where the output went, while cxx and tex
did. They all execute what they produced now. `make` is the awkward one,
because a makefile need not say what it writes: the runner snapshots the
executables either side of the build and runs whatever is new.
A course is not always one program. Twelve of them are not -- EPFU a game and
a lab, EOOP six binaries, EARIN eight labs, MOM three reports. With no target
named, an interactive run prints a numbered menu and asks; `run <dir> 2`, a
path substring, or `all` skips the prompt. Enumeration deliberately scans the
course root rather than --entry, because EPFU pinning --entry to penguins/src
is precisely why labs/krudnic3_lab1.c had never been compiled. --entry is the
default now, not the only.
Interactive by default: EPFU's penguins and ECOAR's puzzle both read stdin,
and you typed `run`, so you are at the keyboard. --batch (and any
non-terminal stdin) means no prompt, stdin from /dev/null and a 60s cap per
program, so an unattended run cannot wedge. --probe never reaches any of this
and does not even enumerate targets: all 44 probes produce a byte-identical
gates/runnability-local.tsv, and `status` is still seconds long.
Running things immediately found two bugs that could not have surfaced before,
both recorded in TODO-refactor-remaining.md rather than fixed here, since both
mean touching a submitted .c:
- EPFU/labs/krudnic3_lab1.c dies with SIGFPE, integer division by zero.
- ECOAR's puzzle.out writes dest.bmp beside its source, so the tree guard
fails the run. That guard is doing exactly its job.
Verified: EPFU both targets, EOOP under a pty answering the prompt, EADS,
ECOAR, MOM. Full gate green, shellcheck clean on all 44 runners.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0172dj34FDpao6wsix8ZuCzE
kuhy chose the strict branch: no per-file-ignores at all, not even the S101
block that ruff's own docs and the rest of this fleet carry for test code. So
125 test assertions were rewritten to raise instead of assert.
Rather than 125 copies of `if x != y: raise AssertionError(...)`, each course
grows a small expect module -- expect_equal / expect_in / expect_true /
expect_false. That is also strictly better output than a bare assert here:
pytest's assertion rewriting does not reach into a helper, so the helper has
to print both values, and it does. The rewrite itself went through ast, not a
regex, because seven of ECOTE's asserts were wrapped over several lines.
Everything else in the two courses is gone as well:
- 66 argument and 37 return annotations on the translator, worked out from
what each function actually returns rather than stamped on as Any --
`list[str] | str` where a function returns "Error!" or the parsed columns.
- 16 prints became logger.error with %-style arguments. The messages still
reach stderr with no basicConfig, via logging's last-resort handler, so the
translator behaves exactly as before.
- Two `open()` calls became Path.open / Path.write_text, six RET504
assign-then-return pairs collapsed, one 380-character expected-HTML literal
split into implicitly concatenated pieces (it cannot be wrapped any other
way, which is what ISC001 being off is for), and one block of commented-out
code deleted.
- ECRYPT_PROJECT/__init__.py removed. It made the COURSE directory a package,
which nothing imports, and it was the sole cause of `N999 Invalid module
name: 'ECRYPT_PROJECT'`; with it gone, sieve is the top-level package and
its name is fine.
Verified by running both, not by reading: ECOTE 26 tests pass and
`python -m translator.main --filename examples/complicated/table1.tex` still
writes the same HTML with the same three column-count warnings on stderr;
ECRYPT_PROJECT 99 tests pass.
Repo-wide: 3,686 findings -> 3,159.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0172dj34FDpao6wsix8ZuCzE
kuhy overruled the "do not fix coursework to be better than it was submitted"
rule: git history is the archive, so the working tree can be clean. This lands
the config and the mechanical half of the cleanup -- 9,281 ruff findings under
the fleet config down to 3,686, with no per-file-ignores anywhere.
What is in here:
- pyproject.toml, the first one in this repo. select = ["ALL"], mypy strict,
and the vendored list mirrored into ruff exclude and coverage omit. Five
rules are off and each says why; CPY001 is the only judgement call, because
stamping a copyright header onto 137 university assignments would assert a
licence that was never claimed. No hook is wired up yet -- a gate lands only
once its subject is clean.
- ruff format + the safe fixes, then a second pass over the docstring rules
ruff marks unsafe (they only edit docstring text). 108 files.
- TRAK/sightpy is vendored, not coursework: it is rafael-fuente/Python-Raytracer
(BSD 3-Clause). Verified against a fresh upstream clone with line endings
normalised -- 30 of 32 files byte-identical, ray.py and scene.py carrying a
12- and 13-line local patch that counts rays for the report. 35 files that
should never have been linted, now excluded and restored.
- WDWR, SPD, MOM and ECRYPT are fully clean, by hand and verified by running
them: WDWR's three plot scripts print the same statistics as before, MOM's
PuLP model solves to the same cost. WDWR's graph.py had a 342-character CSV
header embedded as a string literal, which cannot be wrapped -- the data
moved to data/pareto_front.csv. Two 0-byte .py stubs are deleted; an empty
file is not a deliverable and git still has it.
Three harness bugs found by actually running things:
- `run` now forces MPLBACKEND=Agg. TRAK finished its ray trace in 37 seconds
and then sat for 45 minutes: plt.show() had opened an image viewer and was
waiting for someone to close the window.
- TRAK's main.py only pops that viewer with --show now, and its runner writes
to a gitignored build/ via the new --entry-args. The default output path is
outputs/output.png, which is TRACKED -- a plain run overwrote a submitted
deliverable.
- course_lib.sh was 357 lines, over this repo's own cap. Split into
course_probe.sh and course_run.sh.
Verified: ECOTE 26 tests pass, ECRYPT_PROJECT 99 pass, TRAK renders
cornell_box in 37s and exits 0, every module compiles, and every import ruff
removed was checked to be genuinely unused.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0172dj34FDpao6wsix8ZuCzE
Running the courses made this machine stutter during a game. That was me:
PORR's suite solves systems up to 10000x10000 and takes every core it is
given, and the pip installs are not cheap either.
A promise to be careful is not a fix, so `run` now executes inside a transient
systemd scope -- MemoryMax=2G, MemorySwapMax=0 (OOM-kill rather than thrash
swap), CPUQuota=200%, nice -n 19, ionice -c 3. Same mechanism the pre-push
hook in testsAndMisc uses. Verified from inside the scope: memory.max reads
2147483648 and cpu.max reads "200000 100000", so the kernel is enforcing it
rather than the script hoping.
RUN_MEMORY_MAX and RUN_CPU_QUOTA override it for a single deliberate run.
Recorded the two courses that still fail: PORR, which will now be OOM-killed
under the cap and needs a smaller default parameter set, and ZPOB, where
latexmk exits 12 from bibtex despite producing the PDF.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0172dj34FDpao6wsix8ZuCzE
Five files were outside README / CLAUDE* / DOCS* / TODO*, and two were over
the 250-line cap. Both gates now pass repo-wide.
Renames: the two lowercase readme.md files, and three documents into DOCS-*.
The AIS requirements doc split at its own boundary into functional (101) and
non-functional (174). The WDWR report split into six numbered sections behind
an index that keeps the original filename, 38-235 lines each; 753 lines of
body plus the 18-line header account for all 771 original lines, so nothing
was dropped.
That WDWR file needed checking before splitting: it sits next to main.tex and
main.pdf and looked like a conversion of them. It is not -- main.tex is
project 25406 and the markdown is project 18402, a different document. So it
is authored content and the split is real work, not churn on a build artifact.
Filled the three empty READMEs and replaced ECOTE's, which was a stale copy of
the root README still claiming the group projects were excluded -- they were
merged in by subtree some time ago.
EOPSY/lab1 turned out not to be the code-free directory the survey suggested:
it has modify.sh and modify_examples.sh. The oddly-named empty files beside
them are the exercise's OUTPUT, committed so the before/after state is
visible, and its README now says so rather than leaving them looking like junk.
CLAUDE.md follows the testsAndMisc structure. Writing it caught a nice one:
the md-naming marker is a biconditional, so quoting the literal removal string
in a non-TODO file fails the gate. The gate was right; the text is rephrased.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0172dj34FDpao6wsix8ZuCzE