Skip to content

fix(cli): reject unknown options and extra positionals in render - #105

Closed
NgoQuocViet2001 wants to merge 3 commits into
tt-a1i:mainfrom
NgoQuocViet2001:fix-render-rejects-unknown-options
Closed

NgoQuocViet2001 wants to merge 3 commits into
tt-a1i:mainfrom
NgoQuocViet2001:fix-render-rejects-unknown-options

Conversation

@NgoQuocViet2001

Copy link
Copy Markdown
Contributor

The bug

render destructured its positionals with no validation, so a mistyped flag became the output path:

$ archify render architecture spec.json --json out.html
C:\...\scratchpad\rendertest\--json
$ ls
--json      652771 bytes      <- the diagram, under a nonsense name
spec.json
$ echo $?
0

out.html is never written, nothing warns, and the exit code is 0. An extra positional goes the same way:

$ archify render architecture spec.json out.html extra.html
# extra.html silently dropped

--json is a plausible typo here precisely because it is a real option on the neighbouring compare and deliver commands.

The fix

Once --quality and --repo-root are stripped, render takes no options of its own, so anything left starting with -- is a typo. This mirrors the guard deliver already has, twelve lines away:

const unknown = repoArgs.rest.filter((arg) => arg.startsWith('--'));
if (unknown.length) fail(`Unknown render option "${unknown[0]}".`);
const [type, input, output] = repoArgs.rest;
if (!type || !input || repoArgs.rest.length > 3) fail(usage());

render was the only artifact-producing subcommand without it — compare, deliver, preview, visual-check, guide and brands all validate already.

After

$ archify render architecture spec.json --json out.html
Unknown render option "--json".            (non-zero, nothing written)

$ archify render architecture spec.json out.html extra.html
Usage: ...                                 (non-zero, nothing written)

$ archify render architecture spec.json ok.html
.../ok.html                                (unchanged)

Tests

Two cases in archify/test/cli.test.mjs, both asserting the directory afterwards contains only spec.json — so they fail if the stray file comes back, not just if the message changes.

before   ℹ tests 35   ℹ pass 31   ℹ fail 1
after    ℹ tests 37   ℹ pass 33   ℹ fail 1

The one failure is the same in both: cli: preview runs from an installed skill without node_modules and exits cleanly, which spawns a browser and fails on this Windows box on unmodified main too. Not touched by this change.

archify.zip

Rebuilt, since bin/archify.mjs ships in the skill runtime. Verified with the same comparison zip-freshness runs — against the previously committed archive the only file that differs is bin/archify.mjs, so nothing unrelated drifted in.

(Building on Windows silently produces a CRLF archive that fails that job; I built from an LF export under Linux, as with #91.)

render destructured its positionals with no validation, so a mistyped
flag was taken as the output path:

    archify render architecture spec.json --json out.html

wrote a 650KB html file literally named `--json`, never wrote
out.html, and exited 0. An extra positional was silently dropped the
same way.

render takes no options of its own once --quality and --repo-root are
stripped, so anything left starting with -- is a typo. Every sibling
artifact-producing subcommand already guards this -- compare, deliver,
preview, visual-check, guide and brands all do; render was the gap.

archify.zip rebuilt: bin/archify.mjs ships in the skill runtime.
@NgoQuocViet2001

Copy link
Copy Markdown
Contributor Author

Merged current main in — the branch had gone to conflict, and the conflicting file was archify.zip, which main regenerates on every change. The two source files merged cleanly.

Since the archive is a gate, I rebuilt it rather than hand-resolved it, and validated the toolchain first: rebuilding main's own tree reproduced its committed archify.zip byte-for-byte, so the environment matches what zip-freshness uses (Linux, Node 22 — v22.21.1 here). Then rebuilt on this branch and confirmed the guard is inside the packaged bin/archify.mjs.

On the merged head:

scripts/build-zip.sh /tmp/fresh.zip && cmp -s /tmp/fresh.zip archify.zip
  -> PASS: archify.zip is fresh

node --test archify/test/cli.test.mjs
  -> tests 43   pass 43   fail 0

node --test test/release-package-gates.test.mjs
  -> tests 19   pass 18   fail 0   skipped 1

npm test across the whole suite is 1028 tests, 1000 pass, 27 skipped, 0 fail. Worth noting the "archive build is byte-for-byte reproducible across caller time zones without system zip" gate was the one thing red before the rebuild and is green now — the earlier run of that test was catching exactly the stale archive.

Diff is unchanged in scope at 3 files: archify/bin/archify.mjs, archify/test/cli.test.mjs, and the rebuilt archify.zip.

tt-a1i added a commit that referenced this pull request Sep 4, 2026
Carries forward the original contribution from @NgoQuocViet2001 in #105 onto the current main branch and rebuilds the canonical archive.

Co-authored-by: NgoQuocViet2001 <ngoquocviet2001@gmail.com>
@tt-a1i

tt-a1i commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Thank you, @NgoQuocViet2001, for identifying this failure mode and providing the focused fix and regression coverage.

Because this PR comes from a fork with maintainer edits disabled, we could not resolve the archify.zip conflict directly on this branch. We carried the source and tests forward onto the current main branch in #303, rebuilt the canonical archive with Node 22, and preserved your contribution through explicit co-author credit.

The replacement passed the full local suite (1002 passed, 27 skipped, 0 failed), deterministic ZIP verification, packaged-skill smoke testing, and all current GitHub CI checks. It has now been merged as 5769ace.

Closing this PR as superseded by #303. Thanks again for the clear reproduction and the contribution.

@tt-a1i tt-a1i closed this Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants