nes-pascal

Packaging, Distribution, and Clean-Installation Audit

English [Português (Brasil)] — PT-BR translation pending

Status: this audit was followed by chore/packaging-hardening, which resolved P2-1, P2-2, P2-3, P3-1, and P3-2 at package version 0.5.12. The original findings below are preserved as historical context; see the Resolution section for verification.

Summary

This is an independent packaging, distribution, and clean-installation audit of the NES Pascal compiler. Its goal is to verify that a user can obtain the project from the repository, build and install the Python package in a clean environment, invoke the CLI correctly, compile a valid NES Pascal program, and understand the external ca65/ld65 toolchain requirement.

The audit did not change compiler semantics, runtime behavior, packaging configuration, CI, package structure, or CLI behavior. Only mechanical documentation changes were made.

Result: the packaged compiler is functional. No P0 or P1 findings. Three P2 findings and several P3 findings are reported below. The P2 findings concern missing console-script entry point, incomplete installation documentation for installed-package usage, and absent CI packaging coverage. None of the findings block obtaining, installing, invoking, or using the compiler today.


1. Package metadata inventory

Source of truth: pyproject.toml.

Field Declared value
Package name nes-pascal
Version 0.5.8
Requires-Python >=3.11
Build backend setuptools.build_meta (setuptools>=68)
Description / Summary Prototype Pascal compiler specialized for the NES
Runtime dependencies none declared (Requires-Dist absent)
Optional / dev dependencies none declared
License metadata none declared (setuptools auto-detects the LICENSE file; wheel METADATA is Dynamic: license-file)
README metadata none declared (no readme key; METADATA has no Long Description)
Project URLs none declared
Console-script / CLI entry points none declared (no [project.scripts])
Package discovery [tool.setuptools.packages.find] include nes_pascal*

The installed-wheel METADATA reflects exactly this:

Metadata-Version: 2.4
Name: nes-pascal
Version: 0.5.8
Summary: Prototype Pascal compiler specialized for the NES
Requires-Python: >=3.11
License-File: LICENSE
Dynamic: license-file

The metadata is internally consistent (name, version, Python range, summary). The notable gaps are the missing console-script entry point, README/long description, license expression, and project URLs. The version 0.5.8 is a stale milestone-era value relative to implemented features; see Version consistency.

2. Clean virtual-environment installation

The system interpreter is /usr/bin/python3 (3.12.3) and has neither pip nor ensurepip (Debian/Ubuntu without the python3-venv package, no sudo available). Virtual environments were created with python3 -m venv --without-pip and pip was bootstrapped with the official get-pip.py into each venv. Each venv is fully isolated in /tmp/opencode with its own site-packages; no repository-local PYTHONPATH, no previously installed dependencies, and no working-tree files were involved.

Installation does not depend on repository-local PYTHONPATH, pre-installed dependencies, generated files in the working tree, or editable-install-only behavior.

3. Wheel build and installation

Built with the declared backend using the standards-based frontend (python -m build), installed into an isolated audit environment only (not a runtime dependency):

nes_pascal-0.5.8-py3-none-any.whl   (91,998 bytes)

4. Source distribution audit

nes_pascal-0.5.8.tar.gz   (161,048 bytes)

5. Installed CLI audit

From the clean wheel-installed environment (no repository context):

Invocation Result
python -m nes_pascal.cli --version nes-pascal 0.5.8, exit 0
python -m nes_pascal.cli -V nes-pascal 0.5.8, exit 0
python -m nes_pascal.cli --help usage + option help, exit 0
python -m nes_pascal.cli (no args) argparse usage error, exit 2
python -m nes_pascal.cli /nonexistent.nsp -o x.nes file-access diagnostic, exit 1
nes-pascal --version not available — no console script is installed

Version output matches package metadata. Diagnostics display normally on stderr with E-codes and exit code 1. Invalid invocation exits with code 2.

6. End-to-end compile from outside the repository

A temporary project directory outside the repository (/tmp/opencode/nes-proj-outside) was created containing a minimal valid .nsp program. Using only the wheel-installed package, with the repository not on the path and not the working directory:

source .nsp  ->  installed NES Pascal  ->  .asm/.cfg/.map  ->  ca65  ->  ld65  ->  .nes

Result: successful. Generated main.asm, main.cfg, main.map, main.o, and main.nes; the ROM is 40,976 bytes (16-byte header + 32 KiB PRG + 8 KiB CHR) with a valid NES\x1a header.

Missing-toolchain diagnostic: with PATH restricted so that neither ca65 nor ld65 is discoverable, the compiler stage still runs, writes the .asm/.cfg/.map files, and then exits 1 with:

E5001: missing toolchain component: ca65 and ld65. Install the cc65 package and try again.

This matches the documented E5001 behavior.

7. Asset path behavior after installation

Real bundled assets were copied into the temporary outside-repository project (chr_asset.chr, nametable_loading.nam, game.chr, player_idle.json), and project-relative paths were passed to the installed compiler:

User-supplied project files continue to resolve relative to the .nsp source after the compiler is installed elsewhere. Nothing needs to be shipped inside the Python package.

8. External dependency documentation

Documented in docs/getting-started/prerequisites-and-installation.md (EN and PT-BR) and docs/reference/diagnostics/code-generation.md (E5001/E5002, EN and PT-BR):

Documentation is accurate; no misleading setup instructions were found.

9. Package contents audit

Wheel contents (13 modules + dist-info):

nes_pascal/{__init__,assets,ast,backend_ca65,builtins,cli,codegen_analysis,
diagnostics,lexer,memory_layout,metasprite_assets,parser,semantic}.py
nes_pascal-0.5.8.dist-info/{licenses/LICENSE,METADATA,WHEEL,RECORD,top_level.txt}

No unexpected contents in the wheel: no tests/, no docs/, no examples/, no .pyc, no caches, no build/ artifacts, no generated Assembly/ROMs, no benchmark output. The LICENSE file is intentionally included.

sdist contents: the package, pyproject.toml, README.md, LICENSE, generated setup.cfg, nes_pascal.egg-info, and the top-level tests/*.py modules (conventional for sdists; fixtures/golden/mesen data and examples are not included and are not required at runtime).

No large or unexpected files were found in either artifact.

10. Version consistency

Source Value
pyproject.toml (authoritative) 0.5.8
nes_pascal/__init__.py fallback 0.5.8
CLI version output nes-pascal 0.5.8
Wheel METADATA / filename 0.5.8
sdist filename / PKG-INFO 0.5.8
README / docs version claims none

All values agree today. Findings:

Resolution: the package version is now 0.5.12 and the hard-coded fallback was removed (see Resolution).

11. Python-version compatibility

12. Reproducibility / dirty-tree dependence

The working tree contained build/ and __pycache__/ artifacts during the first build. A second build was run from the same tree, and a third from a pristine git archive checkout:

No dependence on stale generated files was found. (Note: build/, dist/, *.egg-info/, and __pycache__/ are already gitignored.)

13. Installation documentation cross-check

A new user following docs/getting-started/prerequisites-and-installation.md and docs/getting-started/first-program.md (EN and PT-BR mirror pages):

Gap: the documentation never covers using the package after a clean install outside the repository. This is finding P2-2.

Resolution: the installation documentation now covers installed-package usage (see Resolution).

14. CI packaging coverage

Current CI (.github/workflows/ci.yml) installs the project with pip install -e . from the repository checkout in both jobs (compiler-toolchain and mesen-runtime) and never builds or installs a release artifact. Gaps:

This is finding P2-3. Minimal recommended packaging smoke coverage for a future packaging-hardening branch (not implemented during this audit):

  1. build the wheel and sdist (python -m build);
  2. install the wheel into a fresh virtual environment;
  3. assert python -m nes_pascal.cli --version and, once an entry point exists, nes-pascal --version;
  4. compile a minimal .nsp from a directory outside the repository using the installed wheel (with and without the toolchain on PATH).

Resolution: the packaging-smoke CI job implements this coverage and is now required by ci-gate (see Resolution).


Findings classification

P0 — released/installed compiler is unusable or produces invalid output: none.

P1 — clean installation or packaged CLI materially broken: none. Installation succeeds from wheel, sdist, pip install ., and pip install -e .; the packaged CLI works; end-to-end ROM builds work from outside the repository.

P2 — important packaging/release regression gap or misleading install docs:

P3 — metadata, polish, optional CI hardening:

Resolution — packaging hardening (0.5.12)

Implemented by branch chore/packaging-hardening (follow-up to this audit). No compiler semantics or runtime behavior changed.

Clean-artifact verification (branch state): nes_pascal-0.5.12-py3-none-any.whl and nes_pascal-0.5.12.tar.gz built from a clean tree with python -m build; each installed into a fresh virtual environment; imports, version, console script, module invocation, and outside-repository full ROM build all verified. No Requires-Dist appears in the wheel METADATA.

Local validation

CI run

The audit branch is intended to be pushed and validated by the repository’s authoritative GitHub Actions gate (ci-gate). See the branch push/CI result for the final gate status.


Appendix: exact versions and commands