Commit Graph

4 Commits

Author SHA1 Message Date
fab8e93a4b parity_venv.sh follows the app to 3.13; the abi3 tag stays at cp312
The wheel is cp312-abi3, so it loads on 3.13 unchanged — the pin that has to
move is the interpreter the parity venv is built with, since its whole point is
resembling what the image ships.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDYRXGB8tW4NE7b91g7Kdb
2026-08-11 07:24:08 +02:00
340315b6e9 parity_venv.sh: swap the environment it claims to swap
The script exported UV_PROJECT_ENVIRONMENT and then reached for `uv pip`, which
does not honour it — it discovers an environment the way pip does, so the
uninstall and install landed in the app's own .venv. The sanity check that
follows could not notice, because `uv run` *does* honour the variable and so
read the untouched parity venv. Net effect: the swap happened in the wrong
place and reported success. Inc 0's parity claim never exercised the parity
venv at all.

Two fixes, since the second only surfaced once the first was in:

- `uv pip` gets --python pointing at the parity venv.
- everything afterwards runs that venv's interpreter directly. `uv run` re-syncs
  the environment against the app's manifest before running, and the manifest
  still asks for cadquery-ocp-novtk, so it reinstalled the stock wheel on top of
  the swap. The usage note at the top said to drive the app's tests that way
  too; it now says to use the venv's python.

Also pins `uv sync --python 3.12`, so the parity venv keeps resembling what the
image ships instead of following whatever interpreter is newest on the box, and
turns the sanity print into an assertion on __occt_version__ — an attribute
only our wheel defines, which makes it a check that the swap landed.

Verified end to end against the published 7.9.3.1.dev2: installs anonymously
from the Gitea index, 31 modules, ocp suite 48 passed, and the app's main venv
is left on stock.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfriM8XUkn7uYf5Dwe2xo6
2026-08-10 19:59:18 +02:00
091a2ad0cf Housekeeping ahead of the Inc 1-4 coverage work
- inventory.py --methods: report the instance methods the app calls per class,
  plus chained calls that constrain a return type. --check says which classes
  to bind; this says what to bind on them, which is what writing ~38 module
  TUs needs.
- Drop StlAPI from the inventory: StlAPI_Writer has no app call site (the only
  use was a test fixture, now on the app's own STL writer). 138 symbols / 47
  modules.
- adding-symbols.md: scope the executing-constructor ban to the BRepAlgoAPI
  booleans, which are the only classes with a deferred Set*/Build form —
  BRepMesh_IncrementalMesh, GeomAPI_*, BRepCheck_Analyzer and friends compute
  in their constructor by design and bind as stock. Replace the per-increment
  app-test guidance: backend/tests/conftest.py imports n3xd.main, so no app
  test can collect until the last module is bound. Increments gate on
  stock-recorded fixtures here; the app suite is the Inc 4 gate.
- parity_venv.sh: run the ocp suite in the swapped venv (it imports only
  OCP/n3xd_ocp, so it works throughout).
- Fix a stale macro name in occt_handle.h (ocp_new, not OCP_TRANSIENT_NEW) and
  drop the unused ocp_transient_class helper.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfriM8XUkn7uYf5Dwe2xo6
2026-08-10 19:23:27 +02:00
6139852768 Phase 10A/10B Inc 0: build system, handle model, first module surface
Builds n3xd-ocp end to end and publishes 7.9.3.1.dev1 to the Gitea registry,
where it installs anonymously and passes its suite.

- occt/Dockerfile: OCCT 7.9.3 compiled once into a manylinux_2_28 builder
  image (base digest + tarball sha256 pinned), Draw/VTK/Tk/Xlib/OpenGL off,
  FreeType on, -O2 without fast-math or march=native. A final layer asserts
  TKService/TKV3d exist with no libGL/libX11 DT_NEEDED, which is what lets the
  app image drop libgl1/libx11-6. Mounted into, never built FROM.
- scikit-build-core + nanobind STABLE_ABI -> one cp312-abi3 extension that
  registers every OCP.* submodule via PyImport_AddModule, so `import
  OCP.TopoDS` needs no shim and cls.__module__ is right. Version <occt>.N is
  asserted against the OCCT found, keeping occt_version() truthful.
- occt_handle.h: type caster for opencascade::handle<T> over OCCT's intrusive
  refcount. Wrappers are non-owning instances holding exactly one handle in
  their keep-alive list, reusing an existing wrapper so identity survives a
  round trip. Transient constructors go through ocp_new (never nb::init<>,
  which would let OCCT delete nanobind's storage); the caster refuses a
  refcount-0 object rather than corrupt the heap. Verified under ASAN with no
  memory-safety errors, plus an RSS bound over 50k create/destroy cycles.
- Sub-shapes are returned by value everywhere, making the TShape lifetime class
  that segfaulted a process-global face memo unrepresentable.
- Standard_Failure derives RuntimeError, with ~20 concrete types dispatched on
  the dynamic OCCT type (cad_pool marshals failures home by type name).
- Inc 0 surface: gp subset, TopAbs, TopoDS (+ downcasts), TopExp, TopLoc,
  TopTools, BRep, BinTools, Poly, Standard. 34 of the app's 139 symbols.
- n3xd_ocp: additive APIs kept out of the OCP namespace so parity testing stays
  meaningful. bintools (shape <-> bytes, GIL-free, byte-identical) and _debug.

Two findings worth the record, both verified against the stock wheel rather
than assumed: upstream binds __hash__ but leaves __eq__ at identity, which is
exactly what geom_memo.py's hash-bucket + IsSame scan is built around, so we
match it instead of "fixing" it; and BinTools can release the GIL after all, by
slurping the file-like object instead of bridging a streambuf that would call
back into Python.

Gate: BREP round-trips are byte-identical to cadquery-ocp-novtk across six
fixtures (the generator asserts stock idempotency first). That matters beyond
IPC — derive.py content-addresses BREP payloads by sha256 and stores the ref.
2026-08-10 16:10:28 +02:00