Reject duplicate node IDs in graph clones

Merged
BA
1d ago
+260-4

Graph serializers discarded a second object carrying an already visited node ID, so an invalid clone could receive full marks. JavaScript, Python, C, C++, and Java now reject distinct objects sharing an ID while continuing to accept cycles and shared nodes in valid graphs. C neighbor ordering remains tracked separately by #360.

The regression suite executes the browser runners and compiled harnesses against a valid cyclic triangle, a duplicated root, and a duplicated non-root node in each language. Before the fix, all ten invalid-graph checks failed and all five valid-graph checks passed. Afterward, all 15 checks passed without skips on both Windows and Linux.

Validation: Prettier, ESLint, Clippy, and the Git hooks passed. The completed ./scripts/test.sh run reported 1,294 browser checks passing with no failures and six Java checks skipped; Java was then installed and the focused five-language suite passed without skips. The full gate failed at the existing CLI file-permission assertion (0777 instead of 0600 on the WSL Windows filesystem) and six mutation-planning checks caused by missing jq. After installing jq, all six mutation-planning checks passed. The full gate is not green locally; the CLI failure also prevented later Rust test targets from running. Additional broad reruns were stopped after severe local resource contention and do not establish a passing result.

The completed gate also skipped commentflow, ruff, shfmt, shellcheck, cargo-audit, and actionlint because their tools were unavailable. Credentialed live-interview checks, mutation testing, and cross-platform release builds were not run locally and remain for their appropriate CI or credentialed lanes.

The before and after screenshots show the same intentionally invalid JavaScript solution on the actual interview page, served from a local static test server: 5/5 before the fix and 2/5 afterward, with the three corrupted graph cases rejected. This was not a credentialed live interview.

graph-before graph-after

Closes #381


Summary by cubic

Fixes graph clone validation so returned graphs with distinct nodes sharing an ID are rejected instead of silently passing. Previously, serializers collapsed nodes by ID, letting an invalid clone earn full marks.

  • JavaScript, Python, C, C++, and Java runners now reject distinct objects sharing an ID while still accepting legitimate cycles and shared nodes.
  • C also rejects node IDs outside 1–1023 so out-of-range nodes can't disappear from serialized output.
  • A regression suite covers the valid cyclic triangle, duplicated root and non-root nodes, C out-of-range IDs, NULL neighbors, and nodes shared from the input.

Closes #381.