# Strip comments from a polyglot repo for a public mirror

> Remove every comment from a Java, shell, Python, YAML, XML and Go tree for a public mirror, and prove each stripped file means what its source meant.

Published 2026-10-16. HTML version: https://guides.tsvinc.dev/strip-comments-public-mirror/


This strips every comment from an exported code tree (Java, shell with embedded awk, Python, YAML, XML, Go, JS, properties, Dockerfiles), keeps only what a machine or a licence needs, and proves each changed file equivalent to its source with a per-language oracle, plus control tests that show each oracle can fail.

> **Scope** — Verified on: Fedora Linux 44, kernel 7.2.10-200.fc44.x86_64; bash 5.3.9, Python 3.14.8, PyYAML 6.0.3, gawk 5.3.2, Go 1.26.0, Node v22.22.0, Temurin 25.0.4 with Maven 3.9.11 (2026-10-16), on 18 branches of one Java benchmark repo.
> **Needs:** a git repo you will export from; the scripts attached to this page ([`oss-strip-comments.py`](oss-strip-comments.py), [`test-oss-strip-comments.py`](test-oss-strip-comments.py), [`blind-oracle.py`](blind-oracle.py), [`naive.py`](naive.py), [`residual.py`](residual.py), [`strip-all.sh`](strip-all.sh)); the tools above on `PATH`; Maven able to resolve the build offline (`-o`) or online.
> **Time:** 30 min. **Risk:** none to the source repo: every step works on a `git archive` copy. The stripper rewrites files in place, so run it only on that copy. Publishing (force-pushing to the mirror) is outside this manual.

## Before you start

- **Placeholders.** `<SRC_REPO>`: path to the repo you export from. `<BRANCH>`: one branch to try first (mine was `micronaut/imperative-synth-more-io`). All commands run from one empty working directory that holds the six attached scripts.
- **Policy the script implements.** Kept: the ASF Maven wrapper files untouched (`mvnw`, `mvnw.bat`, `mvnw.cmd`, `maven-wrapper.properties`; Apache-2.0 §4(c) requires keeping their attribution notices), a shebang on line 1, Dockerfile parser directives (`# syntax=`, `# escape=`, `# check=`) at the top, Go `//go:` and `// +build` lines. Removed: Java/JS/Go comments and Javadoc, XML comments, YAML and shell comments (whole-line and trailing), Python comments and docstrings, comments inside embedded awk programs (including programs spliced with `'"$var"'`), whole-line `#`, `!` and `//` lines in `.properties` and `.conf`, whole-line `#` comments in `.gitignore` and `.dockerignore`.
- **Files the stripper never opens.** `.html`, `.txt`, `.json`, `.cmd`, `.md` and any suffix not in its map. A vendored licence header in an HTML report (my reports inline Plotly with its MIT header and a `/*! For license information please see plotly.min.js.LICENSE.txt */` pointer) survives for that reason, not because of an exception rule. If you ship a vendored `.js` bundle, its header *would* be stripped: add it to `LICENCE_EXEMPT` first.
- **Oracles per file type.**

  | Type | Oracle | Strength |
  |---|---|---|
  | `.sh`, `.bash` | `bash --pretty-print` of source and result, blank lines dropped, must be equal | full parse |
  | awk inside shell | `gawk -o-` (pretty-print) of each program before and after, comments dropped, must be equal | full parse, per program |
  | `.py` | `ast.dump` of source with docstrings removed equals `ast.dump` of result | full AST |
  | `.yml`, `.yaml` | `yaml.safe_load_all` of both equal | data equality |
  | `.xml` | `ElementTree.canonicalize(with_comments=False, strip_text=True)` of both equal | canonical form |
  | `.go` | token stream from `go/scanner` (comments skipped) of both equal | token stream |
  | `.js` | `node --check` of the result | syntax only |
  | `.java`, `.properties`, `.conf`, `.mod`, Dockerfile | none | covered by Step 8 for Java; the other four only by the unchanged-line net |

  Every stripper first blanks comments in place, so line numbers stay aligned for the safety checks; a post-pass then drops the lines that held only a comment, so the final file is shorter (Step 6's hunk header shows the shift). A second net aborts if any line the stripper did not touch is missing from the output.
- **Check the tools.** `bash --pretty-print` is listed by `bash --help` but not documented in `man bash`; check that your build has it.
  ```console
  $ bash --version | head -1; python3 -c 'import sys, yaml; print("Python", sys.version.split()[0], "PyYAML", yaml.__version__)'; gawk --version | head -1; go version; node --version; bash --help | command grep -- --pretty-print
  GNU bash, version 5.3.9(1)-release (x86_64-redhat-linux-gnu)
  Python 3.14.8 PyYAML 6.0.3
  GNU Awk 5.3.2, API 4.0, PMA Avon 8-g1, (GNU MPFR 4.2.2, GNU MP 6.3.0)
  go version go1.26.0 linux/amd64
  v22.22.0
  	--pretty-print
  ```
  Expected: all six lines. A missing `go`, `node` or `gawk` does not fail the run: the affected files are stripped unchecked and reported as `WARN: no oracle could check …` (see Failure modes).
- **Backup.** Nothing in the source repo is written. Step 3 keeps a `pristine/` copy of the export next to the stripped `tree/`.

## Steps

1. **Put the scripts in one directory.** `test-oss-strip-comments.py` loads `oss-strip-comments.py` from its own directory, so the two must sit side by side.

2. **Run the trap and control tests.**
   ```console
   $ python3 -I test-oss-strip-comments.py -v
   test_awk (__main__.Controls.test_awk) ... ok
   test_go (__main__.Controls.test_go) ... ok
   test_py (__main__.Controls.test_py) ... ok
   test_sh (__main__.Controls.test_sh) ... ok
   test_xml (__main__.Controls.test_xml) ... ok
   test_yaml (__main__.Controls.test_yaml) ... ok
   test_awk_including_spliced (__main__.Traps.test_awk_including_spliced) ... ok
   test_dockerfile (__main__.Traps.test_dockerfile) ... ok
   test_go (__main__.Traps.test_go) ... ok
   test_java (__main__.Traps.test_java) ... ok
   test_licence_exempt (__main__.Traps.test_licence_exempt) ... ok
   test_properties (__main__.Traps.test_properties) ... ok
   test_python (__main__.Traps.test_python) ... ok
   test_sh (__main__.Traps.test_sh) ... ok
   test_xml (__main__.Traps.test_xml) ... ok
   test_yaml (__main__.Traps.test_yaml) ... ok

   ----------------------------------------------------------------------
   Ran 16 tests in 1.062s

   OK
   ```
   Expected: `OK`, 16 tests. The `Traps` tests feed inputs where a comment marker is not a comment (`${x#y}`, `$#`, heredoc bodies, `"http://x"`, Java text blocks, YAML block scalars, `<![CDATA[`, Go raw strings, `/*` in a Dockerfile `rm -rf …/lists/*`). Each `Controls` test swaps in a deliberately wrong stripper (renames `echo`, swaps an import, edits a quoted YAML value, empties a Go raw string, renames an XML element, changes `4 / 2` to `4 / 3` inside awk) and asserts that the oracle stops the run.

3. **Prove the controls can fail.** A control that passes no matter what proves nothing. `blind-oracle.py` replaces one oracle with one that always answers "same" and re-runs the controls:
   ```python
   #!/usr/bin/env python3
   """Control of the controls: blind one oracle (always says "same") and run the
   control tests. The control for that language must now FAIL.
   Usage: blind-oracle.py <test-oss-strip-comments.py> <ext>"""
   import importlib.util, sys, unittest
   spec = importlib.util.spec_from_file_location("t", sys.argv[1])
   t = importlib.util.module_from_spec(spec); spec.loader.exec_module(t)
   ext = sys.argv[2]
   t.s.STRIPPERS[ext] = (t.s.STRIPPERS[ext][0], lambda src, new: True)
   suite = unittest.defaultTestLoader.loadTestsFromTestCase(t.Controls)
   sys.exit(not unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful())
   ```
   ```console
   $ python3 -I blind-oracle.py test-oss-strip-comments.py .sh
   test_awk (t.Controls.test_awk) ... ok
   test_go (t.Controls.test_go) ... ok
   test_py (t.Controls.test_py) ... ok
   test_sh (t.Controls.test_sh) ... FAIL
   test_xml (t.Controls.test_xml) ... ok
   test_yaml (t.Controls.test_yaml) ... ok

   ======================================================================
   FAIL: test_sh (t.Controls.test_sh)
   ----------------------------------------------------------------------
   Traceback (most recent call last):
   …
   AssertionError: SystemExit not raised

   ----------------------------------------------------------------------
   Ran 6 tests in 0.181s

   FAILED (failures=1)
   ```
   Expected: exit status 1; exactly the control for the blinded language fails, the other five pass. Repeat with `.py`, `.yml`, `.go`, `.xml`; each fails only its own control. `test_awk` stays `ok` when `.sh` is blinded because awk programs have their own oracle.

4. **Export one branch into a throwaway tree and keep a pristine copy.**
   ```console
   $ mkdir tree
   $ git -C <SRC_REPO> archive origin/<BRANCH> | tar -x -C tree
   $ cp -a tree pristine
   $ find tree -type f | wc -l
   144
   ```
   Expected: a file count, no errors. The source repo is only read.

5. **Strip.**
   ```console
   $ time python3 -I oss-strip-comments.py tree
     comments stripped from 55 file(s)

   real	0m0.363s
   user	0m0.313s
   sys	0m0.135s
   ```
   Expected: one `comments stripped from N file(s)` line and no `WARN:` or `FATAL:` line. A `FATAL:` line means an oracle or the unchanged-line net found a change in meaning. The run stops at that file; files before it are already rewritten, so export again before retrying (Failure modes, row 1).

6. **Read what changed.** The awk program inside `lib.sh` lost its column notes; only comments went:
   ```console
   $ diff -u pristine/scripts/bench/lib.sh tree/scripts/bench/lib.sh
   --- pristine/scripts/bench/lib.sh	2026-10-16 18:41:24.000000000 +0300
   +++ tree/scripts/bench/lib.sh	2026-10-16 22:26:50.626119877 +0300
   …
   @@ -132,11 +108,6 @@
      log "Analyzing prometheus CSV..."
      awk -F',' '
      BEGIN {
   -    # columns: 1:ts 2:rss 3:heap_used 4:heap_committed 5:heap_max
   -    # 6:nonheap_used 7:nonheap_committed 8:buf_mem 9:buf_count
   -    # 10:gc_count 11:gc_total 12:cpu_usage 13:cpu_seconds 14:uptime
   -    # 15:threads 16:threads_daemon 17:pool_active 18:pool_idle
   -    # 19:pool_pending 20:pool_total 21:http_count 22:http_dur
      }
      NR>1 {
        n++
   …
   ```
   On this branch the 55 changed files were 31 `.java`, 13 `.sh`, 3 `.properties`, 3 `.yml`, 2 Dockerfiles, 1 `.go`, 1 `.xml`, 1 `.js`. All 31 shebangs stayed on line 1. The branch has no Go directives and no Dockerfile parser directives, so those two keep-rules are exercised only by the Step 2 trap tests.

7. **Run a naive stripper through the same oracle.** This is the control on real files: a plain regex stripper for shell comments, judged by the real `bash --pretty-print` oracle.
   ```python
   #!/usr/bin/env python3
   """Control: replace one language's stripper with a naive regex and let the
   real oracle judge each file. Usage: naive.py <oss-strip-comments.py> <ext> <regex> <file>..."""
   import importlib.util, pathlib, re, sys
   spec = importlib.util.spec_from_file_location("strip", sys.argv[1])
   s = importlib.util.module_from_spec(spec); spec.loader.exec_module(s)
   ext, rx = sys.argv[2], re.compile(sys.argv[3], re.M)
   s.STRIPPERS[ext] = (lambda t: rx.sub("", t), s.STRIPPERS[ext][1])
   caught = 0
   for f in map(pathlib.Path, sys.argv[4:]):
       try:
           s.strip_text(f, f.read_text())
           print(f"passed  {f}")
       except SystemExit as e:
           caught += 1
           print(e)
   print(f"{caught} of {len(sys.argv) - 4} caught")
   ```
   ```console
   $ python3 -I naive.py oss-strip-comments.py .sh '[ \t]#.*$|^[ \t]*#(?!!).*$' $(/usr/bin/find pristine -name '*.sh' | sort) | sed '/^passed/d'
   FATAL: pristine/scripts/bench/lib.sh changed meaning after stripping
   FATAL: pristine/scripts/prom-scraper.sh changed meaning after stripping
   FATAL: pristine/scripts/report-detailed.sh changed meaning after stripping
   FATAL: pristine/scripts/report-summary.sh changed meaning after stripping
   4 of 30 caught
   ```
   Expected: at least one `FATAL`. In `report-detailed.sh` and `report-summary.sh` the regex cut CSS colours out of an HTML template (`background: #0d1117; color: #c9d1d9; }` became `background:`). Those two are real breaks, and both still pass `bash -n`, so a syntax check alone would have shipped them. In `lib.sh` and `prom-scraper.sh` the regex removed only comments: `#` lines inside single-quoted awk programs (plus one trailing shell comment in `lib.sh`). The shell oracle sees the awk program as part of a shell string, so it flags any edit there; those two are cautious catches of comment-only changes, which the real stripper handles with its own gawk oracle.

8. **Compile what has no oracle.** Java has no equivalence oracle here; a full test-compile of the stripped tree is the check. Build the Go module too.
   ```console
   $ cp -a tree build
   $ (cd build && mvn -q -o -DskipTests test-compile > ../mvn.log 2>&1; echo "mvn exit=$?")
   mvn exit=0
   $ (cd build/mock-server && go build -o /dev/null . ; echo "go exit=$?")
   go exit=0
   ```
   Expected: both `exit=0`. `test-compile` covers test sources too, which plain `compile` skips. The copy keeps `target/` out of `tree/`.

9. **Repeat for every branch you will publish.** `strip-all.sh` exports, strips, test-compiles and builds each branch:
   ```bash
   #!/usr/bin/env bash
   # usage: strip-all.sh <SRC_REPO> <OUT_DIR> <STRIPPER> <BRANCH>...
   set -u
   src=$1 out=$2 stripper=$3; shift 3
   rc=0
   for b in "$@"; do
     d="$out/${b//\//_}"
     rm -rf "$d"; mkdir -p "$d"
     git -C "$src" archive "origin/$b" | tar -x -C "$d"
     s=$(python3 -I "$stripper" "$d" 2>&1) || { echo "$b STRIP FAILED: $s"; rc=1; continue; }
     ( cd "$d" && mvn -q -o -DskipTests test-compile > "$d.mvn.log" 2>&1 ) && m=OK || { m=FAIL; rc=1; }
     ( cd "$d/mock-server" && go build -o /dev/null . > "$d.go.log" 2>&1 ) && g=OK || { g=FAIL; rc=1; }
     echo "$b |${s#  comments} | mvn=$m go=$g"
   done
   exit $rc
   ```
   ```console
   $ time bash strip-all.sh <SRC_REPO> "$PWD/all" oss-strip-comments.py $(git -C <SRC_REPO> for-each-ref --format='%(refname:lstrip=3)' 'refs/remotes/origin/*/*synth*')
   micronaut/imperative-jdbc-synth | stripped from 55 file(s) | mvn=OK go=OK
   micronaut/imperative-synth | stripped from 52 file(s) | mvn=OK go=OK
   micronaut/imperative-synth-more-io | stripped from 55 file(s) | mvn=OK go=OK
   …
   springboot/reactive-r2dbc-synth | stripped from 49 file(s) | mvn=OK go=OK
   springboot/reactive-synth | stripped from 44 file(s) | mvn=OK go=OK
   springboot/reactive-synth-more-io | stripped from 46 file(s) | mvn=OK go=OK

   real	1m51.490s
   user	8m36.538s
   sys	0m27.609s
   ```
   Expected: one line per branch, every one `mvn=OK go=OK`, no `STRIP FAILED`, exit status 0. The `mock-server` path and the branch pattern are specific to my repo; change them for yours.

## Verify

Every changed file that has an oracle passed it (Step 5), the Java compiled (Steps 8 and 9), the licence files are byte-identical, and no comment-shaped line is left in the types the scan can judge without a parser:

```console
$ for f in mvnw mvnw.cmd .mvn/wrapper/maven-wrapper.properties; do cmp pristine/$f tree/$f && echo "unchanged: $f"; done
unchanged: mvnw
unchanged: mvnw.cmd
unchanged: .mvn/wrapper/maven-wrapper.properties
$ python3 -I residual.py pristine | tail -1
93 files scanned, 513 comment-shaped lines
$ python3 -I residual.py tree
93 files scanned, 0 comment-shaped lines
$ python3 -I residual.py all
all/micronaut_imperative-synth/src/main/java/dev/tsvinc/space/service/ServiceConstants.java:41: * Math.sin(dLon / 2) * Math.sin(dLon / 2);
all/micronaut_reactive-synth/src/main/java/dev/tsvinc/space/service/ServiceConstants.java:41: * Math.sin(dLon / 2) * Math.sin(dLon / 2);
all/quarkus_imperative-synth/src/main/java/dev/tsvinc/space/service/ServiceConstants.java:41: * Math.sin(dLon / 2) * Math.sin(dLon / 2);
all/quarkus_reactive-synth/src/main/java/dev/tsvinc/space/service/ServiceConstants.java:41: * Math.sin(dLon / 2) * Math.sin(dLon / 2);
all/springboot_imperative-synth/src/main/java/dev/tsvinc/space/service/ServiceConstants.java:41: * Math.sin(dLon / 2) * Math.sin(dLon / 2);
all/springboot_reactive-synth/src/main/java/dev/tsvinc/space/service/ServiceConstants.java:41: * Math.sin(dLon / 2) * Math.sin(dLon / 2);
1451 files scanned, 6 comment-shaped lines
```

The six hits across all 18 branches are one line of code: the continuation of a multiplication (`+ Math.cos(…) * Math.cos(…)` on the line above, `* Math.sin(dLon / 2) …` on this one). `residual.py` only flags line starts (`#`, `//`, `/*`, `*`, `<!--`) in `.java`, `.xml`, `.yml`, `.yaml`, `.properties`, `.go`, `.js`, `.py`; shell is left out because `case` patterns (`*)`) and `.gitignore` globs match the same shapes.

## Undo / rollback

- **Local tree:** delete `tree/` and export again, or copy `pristine/` back. Verified: a second `git archive` of the same branch into `tree2/` gave no output from `diff -r pristine tree2`.
- **Keep-everything export:** my export wrapper takes `STRIP_COMMENTS=0` and skips the stripper. On 2026-10-16 that path also stopped on the comment-validator error (`FATAL: 1 comment(s) do not stand alone`, Failure modes), so it was not a working rollback that day.
- **Published mirror:** re-push the previous commit of each branch (the export prints `updated <old> -> <new>` per branch). `[UNVERIFIED: rollback not exercised]`

## Failure modes

| Symptom (exact message) | Cause | Fix |
|---|---|---|
| `FATAL: <path> changed meaning after stripping` | The oracle for that file type saw a difference: a real stripper bug, or a deliberately wrong stripper in a control. | Diff the oracle's view of both versions (for shell: `bash --pretty-print` of each) and fix the stripper; never bypass the oracle. |
| `FATAL: … changed meaning after stripping` on a shell file whose only change is a removed comment block | `bash --pretty-print` renders a removed mid-file comment block as a blank line, so a strict comparison differs by one empty line. | Compare with blank lines dropped; the current `_oracle_sh` does this. |
| `WARN: no oracle could check <path>: spliced awk program at line <N>` | An awk program built as `'…'"$var"'…'` does not parse standalone, so gawk cannot check it. | The current stripper joins the pieces with placeholder identifiers and checks the whole program; the WARN means an older stripper. |
| `UNUSABLE COMMENT pom.xml:21 cites a plan wave: <!-- Wave 2: …` then `FATAL: 1 comment(s) do not stand alone` | My export runs a comment validator (meant for the keep-comments mode) before the stripper, so a comment the stripper would delete still fails the run. | Run the stripper before the validation pass. I made that reorder first in a private clone, where the same 19-branch dry run finished with exit 0. It is now committed (`4fc38fe1`, 2026-10-16): with the default strip, the stripper runs first. `STRIP_COMMENTS=0` still validates and still rejects such a comment, which is intended, because in that mode the comment ships. |

## Field notes

- **2026-10-16 18:40–19:02 (Steps 4–9 and Verify re-run and saved 22:26–22:29; Steps 2, 3 and 7 pasted from the 18:42–19:02 runs), workstation (Fedora 44, kernel 7.2.10; bash 5.3.9, Python 3.14.8, PyYAML 6.0.3, gawk 5.3.2, Go 1.26.0, Node v22.22.0, Temurin 25.0.4, Maven 3.9.11):**
  - Scripts from the repo's `main` at 9e3a2f6. Test suite: 16 tests, OK.
  - Blinded each oracle in turn (`.sh`, `.py`, `.yml`, `.go`, `.xml`, and awk by making the gawk normaliser return a constant). Every time, only the matching control failed.
  - The JS oracle is weaker than the rest. A syntax break (`1 - 2` to `1 - ;`) is caught, but a meaning change (`1 - 2` to `1 + 2`) passes. There is no JS control test, and none would make sense against `node --check`.
  - One branch (144 files, at 9acf917c) stripped 55 files in under a second. Wrapper files were byte-identical afterwards. It test-compiled offline in 11.5 s.
  - The naive shell regex was caught on 4 of 30 scripts. Two were real breaks (CSS colours cut from HTML templates) that `bash -n` accepts; the other two were comment-only edits inside awk programs, flagged cautiously because the shell oracle compares the awk text as a shell string.
  - The full dry-run export, as committed, stopped on the second branch: a `<!-- Wave 2: … -->` comment in that branch's `pom.xml` failed the keep-comments validator, which runs before the stripper. `STRIP_COMMENTS=0` stopped on the same comment. The reorder below went into the export later that evening as `4fc38fe1`.
  - In a private clone I moved the repairs/validation block after the strip block. The dry run then passed all 19 branches in 29.5 s. `main` came out with the same tree as the published commit, and the other 18 came out as updates.
  - Test-compile plus Go build of all 18 stripped branches: 18 of 18 OK, from both the dry-run mirror and `strip-all.sh`.
  - Across the 18 branches the wrapper files were byte-identical: 54 of 54.
  - Stripping `main`'s own `scripts/` stripped the stripper. Its stripped test suite still passed against the stripped stripper.
  - The public mirror, cloned read-only, had 19 branches. `main` still carried the Plotly 2.35.2 MIT header, the `/*! For license information … */` pointer and `plotly.min.js.LICENSE.txt`. That file is byte-identical to `plotly.js@2.35.2/dist/plotly.min.js.LICENSE.txt` on jsDelivr; `plotly.js-dist-min@2.35.2` ships no such file.
  - `residual.py` over all 19 mirror branches (1452 files) reported 10 comment-shaped lines and no comments: 6 are the Java continuation line, 4 are lines inside Python string literals in the report generator (`*{box-sizing:border-box;}` and three `##` Markdown headings). It skips line-1 shebangs.
- **2026-10-16 (earlier the same day), same workstation, JDK 25.0.2 GraalVM CE for the compile check:**
  - The first strip-mode dry runs stopped twice.
    - First a shell false positive on a bench scenario script: the pretty-printer had turned a removed comment block into one blank line. The oracle now drops blank lines.
    - Then a Go FATAL on the mock server's `main.go`. The saved before/after pair passes the 16 October oracle, and the output of the 16 October stripper matches the saved "after" file. What the earlier check compared was not kept.
  - Another dry run carried 36 `WARN` lines, two spliced awk programs on each of the 18 branches. That stripper had no splice support yet.
  - After the fixes, dry runs were clean, and all 18 stripped branches test-compiled and built.
  - Pushed all 19 branches as orphan commits. A second push added the Plotly notice file to `main` and left the 18 others unchanged.
  - The mirror still has wrapper 3.1.1 (`mvnw.bat`). The source branches have since moved to wrapper 3.3.4: `only-script`, `mvnw.cmd`, and a `maven-wrapper.properties` with no licence header. A 3.3.4 export was not pushed by the time of this run.

## Notes

- The script's docstring records a break that the unchanged-line net alone missed: a Dockerfile named `Dockerfile.java` went to the Java scanner, and the `/*` in `rm -rf /var/lib/apt/lists/*` opened a block comment that blanked ten lines. Blanked lines count as changed, so the net did not fire. The fix is classifying by what the file is (`Dockerfile*` is checked before the suffix map). Dockerfiles still have no oracle.
- Why exempt the wrapper files by name: `mvnw` has no suffix and `.cmd` is not in the map, so neither would be touched anyway. `maven-wrapper.properties` *is* stripped as `.properties`, and in wrapper 3.1.1 it carries the ASF header. The name list covers all of them and does not depend on the map.
- Java equivalence beyond compiling (comparing `javac` token streams, say) is a possible stronger oracle. Not tried.
- The attached `oss-strip-comments.py` is byte-identical to the copy in my repo; its docstring mentions `export-oss-mirror.sh` and a plan row `D5.10`, both of which live in my private repo and are not published.
- `STRIP_COMMENTS=0` and the repair/validation pass belong to my export wrapper, which also deletes Markdown, adds `LICENSE`, and makes one orphan commit per branch. They are not part of the attached scripts.
- The public mirror these runs fed: https://gitlab.com/myrants-oss/micronaut-native-as-hell

## Sources

- Apache License 2.0, §4(c), on retaining attribution notices in redistributed source: https://www.apache.org/licenses/LICENSE-2.0.txt
- gawk options, `-o` / `--pretty-print`: https://www.gnu.org/software/gawk/manual/html_node/Options.html
- Go `go/scanner` (`Mode`; `ScanComments` unset skips comments): https://pkg.go.dev/go/scanner
- Python `ast`: https://docs.python.org/3/library/ast.html
- Python `xml.etree.ElementTree.canonicalize`: https://docs.python.org/3/library/xml.etree.elementtree.html
- Node.js CLI (`-c, --check`): https://nodejs.org/api/cli.html
- Maven Wrapper (default `only-script` type, `mvnw` / `mvnw.cmd`): https://maven.apache.org/tools/wrapper/
- Plotly 2.35.2 notice file: https://cdn.jsdelivr.net/npm/plotly.js@2.35.2/dist/plotly.min.js.LICENSE.txt

