Today — a clean directory with two malformed templates:
$ printf 'ZZZZZ\nZZZZ\n' > templates/broken.art
$ printf '# name: Sixer\n000\n000\n000\n000\n000\n000\n' > templates/sixer.art
$ mossaic-art --list-templates --no-colour > lt.out 2> lt.err; echo "list exit=$?"
list exit=0
$ head -1 lt.out
4 templates:
$ wc -c < lt.err
0
$ grep -c 'broken\|sixer' lt.out
0
$ mossaic-art --template sixer --year 2027 --no-colour --plan /dev/null; echo "exit=$?"
mossaic-art: no template named "sixer" — there is dragon, invader, pulse, wave
exit=2
$ mossaic-art --matrix templates/sixer.art --year 2027 --no-colour --plan /dev/null; echo "exit=$?"
mossaic-art: templates/sixer.art: a canvas is exactly 7 rows, one per weekday; this has 6
exit=2
Same file, two commands: one says exactly what is wrong, the other says the template does not exist. The local directory really is read, so the silence is a deliberate skip and not a missing feature:
$ printf '# name: Goodun\n# author: @me\n0000\n0400\n0040\n0004\n0000\n0000\n0000\n' > templates/goodun.art
$ mossaic-art --list-templates --no-colour | head -1
5 templates:
And a broken local file that shares a built-in's name draws a different picture and reports success:
$ printf '000\n000\n000\n' > templates/dragon.art # 3 rows, does not parse
$ mossaic-art --template dragon --year 2027 --no-colour --plan /dev/null | head -1; echo "exit=$?"
Dragon · 2027 · 53 of 53 columns · 146 days · 442 commits
exit=0
$ printf '# name: Mine\n0400\n0000\n0000\n0000\n0000\n0000\n0000\n' > templates/dragon.art # same name, valid
$ mossaic-art --template dragon --year 2027 --no-colour --plan /dev/null | head -1; echo "exit=$?"
Mine · 2027 · 4 of 53 columns · 1 days · 4 commits
exit=0
Why it is worth fixing — src/templates.rs:94-97 states the policy and names the escape hatch: "A file that does not parse is skipped rather than fatal: one broken template in a directory must not take out --list-templates, which is the command you would reach for to find out which one is broken." That command does not name the file, count what it skipped, or write a byte to stderr.
This is the loop #57 — the project's own good-first-issue walkthrough — puts a first-time contributor in: its step 2 is mkdir -p templates && cp your-name.art templates/ && mossaic-art --list-templates, and templates/ ships inside every release archive, so this is the end-user path. (A contributor working inside the repo is fine: build.rs embeds art/templates/ and the suite checks it, so they get a failing test with a reason.) One wrong row and the answer is "no template named mine" — an error about a name, for a file sitting right there under that name — and the listing they were told to check shows four templates and no complaint. The natural conclusion is that the lookup is wrong rather than the file, so the search goes to the wrong place. The shadowing case is worse: the same command draws two different pictures depending on whether the user's file happens to parse, with nothing printed either way.
Fix — have read_dir return the parse errors alongside the templates it read, and have --list-templates print them under the listing: 2 files in templates/ were skipped: broken.art (line 1, column 1: 'Z' is not a shade), sixer.art (a canvas is exactly 7 rows; this has 6). That is what the doc comment already promises and it costs no change to the skip-rather-than-fail policy. Then make the --template NAME miss tell the two cases apart: if a file with that stem is in a local directory but did not parse, give the parse error rather than "no template named". read_dir/catalogue have three callers in the whole tree, so the change is contained. The listing half alone is the cheap version; doing both keeps the third option — refusing to let an unparsable file shadow a built-in — available later.
Done when — with a malformed file in ./templates/, mossaic-art --list-templates names it and says why it was skipped, and mossaic-art --template <its stem> reports the parse error rather than "no template named"; a clean directory's listing is unchanged and one broken file still does not make the listing fail; a broken local file that shadows a built-in name no longer silently draws the built-in; and a test plants a malformed template and asserts the file name appears in the listing output.
Today — a clean directory with two malformed templates:
Same file, two commands: one says exactly what is wrong, the other says the template does not exist. The local directory really is read, so the silence is a deliberate skip and not a missing feature:
And a broken local file that shares a built-in's name draws a different picture and reports success:
Why it is worth fixing — src/templates.rs:94-97 states the policy and names the escape hatch: "A file that does not parse is skipped rather than fatal: one broken template in a directory must not take out
--list-templates, which is the command you would reach for to find out which one is broken." That command does not name the file, count what it skipped, or write a byte to stderr.This is the loop #57 — the project's own good-first-issue walkthrough — puts a first-time contributor in: its step 2 is
mkdir -p templates && cp your-name.art templates/ && mossaic-art --list-templates, andtemplates/ships inside every release archive, so this is the end-user path. (A contributor working inside the repo is fine: build.rs embedsart/templates/and the suite checks it, so they get a failing test with a reason.) One wrong row and the answer is "no template named mine" — an error about a name, for a file sitting right there under that name — and the listing they were told to check shows four templates and no complaint. The natural conclusion is that the lookup is wrong rather than the file, so the search goes to the wrong place. The shadowing case is worse: the same command draws two different pictures depending on whether the user's file happens to parse, with nothing printed either way.Fix — have
read_dirreturn the parse errors alongside the templates it read, and have--list-templatesprint them under the listing:2 files in templates/ were skipped: broken.art (line 1, column 1: 'Z' is not a shade), sixer.art (a canvas is exactly 7 rows; this has 6). That is what the doc comment already promises and it costs no change to the skip-rather-than-fail policy. Then make the--template NAMEmiss tell the two cases apart: if a file with that stem is in a local directory but did not parse, give the parse error rather than "no template named".read_dir/cataloguehave three callers in the whole tree, so the change is contained. The listing half alone is the cheap version; doing both keeps the third option — refusing to let an unparsable file shadow a built-in — available later.Done when — with a malformed file in
./templates/,mossaic-art --list-templatesnames it and says why it was skipped, andmossaic-art --template <its stem>reports the parse error rather than "no template named"; a clean directory's listing is unchanged and one broken file still does not make the listing fail; a broken local file that shadows a built-in name no longer silently draws the built-in; and a test plants a malformed template and asserts the file name appears in the listing output.