From 823d26c3b6c716ff61e264e3220e8acf95f6694e Mon Sep 17 00:00:00 2001 From: Orual Date: Sat, 1 Aug 2026 14:18:29 -0400 Subject: [PATCH] epic-86-task-D --- .current-task/dependency-summary.md | 10 + .current-task/manifest.txt | 19 ++ .current-task/plan.md | 300 ++++++++++++++++++++++++++++ .current-task/task.md | 43 ++++ 4 files changed, 372 insertions(+) create mode 100644 .current-task/dependency-summary.md create mode 100644 .current-task/manifest.txt create mode 100644 .current-task/plan.md create mode 100644 .current-task/task.md diff --git a/.current-task/dependency-summary.md b/.current-task/dependency-summary.md new file mode 100644 index 0000000..f28333a --- /dev/null +++ b/.current-task/dependency-summary.md @@ -0,0 +1,10 @@ +# Dependency Summary — Task D + +Epic: PM-86 (epic-86 workspace) +Base bookmark: main +Epic workspace: ../epic-86 + +Dependencies: Task D has NO predecessors. +Blocks: See .current-epic/dependencies.dot + +This task can start implementation immediately — all dependencies are satisfied. diff --git a/.current-task/manifest.txt b/.current-task/manifest.txt new file mode 100644 index 0000000..922105b --- /dev/null +++ b/.current-task/manifest.txt @@ -0,0 +1,19 @@ +Flavor: polymodel-jj-parallel +Epic-Key: PM-86 +Epic-URL: https://radiant-industries.atlassian.net/browse/PM-86 +Project: PM +Epic-workspace: ../epic-86 +Base-bookmark: main + +Tasks: +A PM-87 https://radiant-industries.atlassian.net/browse/PM-87 Authoritative viewer load/readiness state machine +B PM-88 https://radiant-industries.atlassian.net/browse/PM-88 Shared renderer load reservation ledger and hard budgets +C PM-76 https://radiant-industries.atlassian.net/browse/PM-76 LDraw library projection and ATProto dependency manifest +D PM-77 https://radiant-industries.atlassian.net/browse/PM-77 LDraw corpus and compatibility harness +E PM-78 https://radiant-industries.atlassian.net/browse/PM-78 Thomas-compatible Rust LDraw semantic core +F PM-79 https://radiant-industries.atlassian.net/browse/PM-79 Minimal LDraw vertical slice and generic scene IR contract +G PM-80 https://radiant-industries.atlassian.net/browse/PM-80 Compound LDraw resolver and versioned worker protocol +H PM-81 https://radiant-industries.atlassian.net/browse/PM-81 LDraw points, surfaces, explicit edges, and conditional lines +I PM-82 https://radiant-industries.atlassian.net/browse/PM-82 LDraw TEXMAP and embedded texture pipeline +J PM-83 https://radiant-industries.atlassian.net/browse/PM-83 Format registry and LDraw publishing/viewer integration +K PM-84 https://radiant-industries.atlassian.net/browse/PM-84 Interoperability, fuzzing, performance, and visual baselines diff --git a/.current-task/plan.md b/.current-task/plan.md new file mode 100644 index 0000000..fbc5263 --- /dev/null +++ b/.current-task/plan.md @@ -0,0 +1,300 @@ +# PM-77 Plan — LDraw corpus and compatibility harness (generation 3) + +## Task + +- **Epic:** PM-86 — [LDraw/LEGO model support and flexible renderer](https://radiant-industries.atlassian.net/browse/PM-86) +- **Task:** PM-77 — [LDraw corpus and compatibility harness](https://radiant-industries.atlassian.net/browse/PM-77) +- **Task prefix:** D +- **Task cache:** `.current-epic/task-D.md` +- **Epic workspace:** `../epic-86` +- **Base bookmark:** `main` +- **Task workspace expectation:** `../epic-86-task-D` +- **Task bookmark expectation:** `epic-86-task-D` +- **Plan output:** `.current-epic/plan-D.md` +- **Dependencies:** none +- **Downstream blockers:** E/PM-78, F/PM-79, K/PM-84 +- **Design source:** [PM-75 design](https://radiant-industries.atlassian.net/wiki/spaces/PM/pages/5570561) + +## Context and intent + +PM-77 is the reproducible test foundation for the LDraw semantic and renderer work. It adds a dependency-light, target-safe Rust testkit, authored specification corpus, versioned canonical records, and a native-only compatibility harness. The corpus is normative only where expectations are derived from ratified LDraw/OMR requirements or an explicit Polymodel safety decision; outputs from LDParse, Thomas fixtures, weldr, ldr_tools, OMR, and official-library artifacts remain observations until a compatibility-ledger decision adopts them. + +The plan is written so E can implement its semantic core against a machine-checkable gate contract and so F/H/K can consume stable v1 records without depending on native parser tooling. + +## Safety, workspace, and implementation skills + +1. In the task workspace, run `jj workspace root`, `jj status`, and `jj bookmark list`. Stop immediately if the workspace is the default workspace or the checked-out bookmark is `main`. +2. Confirm the workspace is `../epic-86-task-D` and the bookmark is `epic-86-task-D`. Do not create workspaces or bookmarks from this plan. +3. After the parent copies the task cache into the implementation workspace, read `.current-task/task.md` and `.current-task/plan.md`; the cached task contract is authoritative. +4. Do not edit `.current-epic/manifest.txt`, `.current-epic/dependencies.dot`, `.current-epic/task-state.json`, `.current-epic/merge-gate.json`, `.current-epic/events.log`, generated `crates/polymodel-api`, or renderer production behavior. +5. Load `polytoken:investigating-a-codebase` before implementation and use the repository's existing test/just conventions. No frontend-design skill applies. Load `reviewing-code-for-shipping-quality` before the final implementation review. + +## Replace-vs-edit assessment + +| Area | Decision | Reason and boundary | +|---|---|---| +| `crates/polymodel-ldraw-testkit` | **Create** | No existing crate owns cross-parser fixtures, provenance, profiles, canonical records, or E-facing gates. Keep it independent of parser/renderer implementations and compileable for wasm. | +| Corpus, expected records, ledger, and provenance files | **Create** | Existing `public/models/` files are STL/STEP assets and must not be relabeled as LDraw fixtures. Add behavior-named, exact-byte files under the new testkit-owned corpus. | +| `tools/ldraw-compat-harness` | **Create** | No existing compatibility tool exists. A standalone native tool is structurally safer than adding Python/process dependencies to the renderer or app. | +| LDParse driver/environment | **Create** | LDParse is a Python library, not a binary. Commit a hash-pinned driver and lockfile/environment rather than patching an assumed executable. | +| Fuzz/property smoke harness | **Create** | No existing LDraw fuzz surface exists. Add a bounded deterministic command at the test boundary; do not add branches to unrelated production code. | +| Root `Cargo.toml` and `justfile` | **Edit minimally** | The workspace already uses `members = [".", "crates/*"]`; the new crate is auto-included, so add no explicit member entry. Add only required dependencies and recipes, including new recipes as `test-all` prerequisites. Preserve existing commands and renderer split checks. | +| `polymodel-renderer-protocol`, `polymodel-mesh`, app, generated API | **Do not edit** | PM-77 supplies test contracts and fixtures; it must not introduce a heavy dependency path or production parser behavior. | + +## Required deliverable layout + +The implementor may choose equivalent module names, but the following boundaries and artifacts are mandatory: + +- `crates/polymodel-ldraw-testkit/`: dependency-light Rust crate with embedded/compile-time fixture inventory, public profiles, expected/canonical records, provenance validation, matrix validation, corpus gates, and deterministic serialization. It must not depend on `three-d`, `three-d-asset`, `stl_io`, `polymodel-mesh`, filesystem, network, archive, process, or parser implementation crates. +- `crates/polymodel-ldraw-testkit/corpus/` (or a documented testkit-owned `testdata/ldraw/`): authored inputs, expected records, matrix, ledger, manifests, provenance/license records, semantic-limit vectors, and the H-owned conditional-line family. +- `tools/ldraw-compat-harness/`: native-only Rust harness and adapter modules, plus `ldparse_driver.py`, `.python-version`, `pyproject.toml`, `uv.lock`, vendored/pinned LDParse source or verified source archive, and README/build evidence. Tests are offline and deterministic. +- `fuzz/` or a testkit-owned property target: bounded seeded smoke/regression command with committed malformed/adversarial inputs and reports. +- `justfile`: `ldraw-corpus`, `ldraw-differential`, `ldraw-fuzz-smoke`, and `ldraw-wasm-check`; all four are prerequisites of `test-all`. +- Root `Cargo.toml`: only dependency changes required by the new crate/tool. Do not add a redundant workspace-member line because `crates/*` already includes it. + +## Cross-task contracts that this task must publish + +### 1. Versioned canonical record contract + +D commits canonical syntax, semantic, and scene record schema version `v1`, with stable field ordering, explicit integer widths, canonical decimal/float/non-finite tokens, normalized separators, raw bytes/tails/spans, diagnostic order, provenance, and schema compatibility rules. E and F may add fields only through a documented compatible extension; they must not change committed v1 golden meaning or expected records without a schema-version bump and a reviewed migration. The v1 schema and representative golden snapshots are therefore a cross-task artifact, not disposable test scaffolding. + +### 2. Machine-checkable semantic corpus gates + +A **corpus gate** is a named, profile-scoped Rust assertion over one fixture's authored expected record and the adapter-produced actual record. The testkit exposes a wasm-safe trait and result types, for example: + +```rust +pub trait CorpusGate { + fn name(&self) -> &'static str; + fn profile(&self) -> Profile; + fn assert_case( + &self, + fixture: &FixtureCase, + expected: &ExpectedRecord, + actual: &CanonicalRecord, + ) -> Result<(), GateFailure>; +} +``` + +The testkit also exposes a `CorpusGateSet` that rejects duplicate gate names, missing profile coverage, or a fixture with no applicable gate. E implements the adapter/semantic side of this contract in its wasm-compatible crate and runs the gates against its parsed records; the testkit owns the assertion definitions and fixture expectations. Process execution and oracle differential reporting are separate native-only code and are never required by E's gate evaluation. + +The minimum v1 gate set is named and profile-scoped as follows: + +1. `syntax_types_0_to_5`: each primitive/meta line is classified correctly, with raw tail, source span, line-ending, and malformed-field behavior checked for strict, compatibility, and lossless rows where applicable. +2. `profile_acceptance_and_diagnostics`: strict/compatibility/lossless accept, reject, preserve, diagnostic code, severity, and deterministic diagnostic-order expectations are exact. +3. `mpd_and_data_boundaries`: `FILE`/`NOFILE`, `!DATA`, duplicate/missing terminators, payload concatenation/base64, unreachable blocks, and decoded limits match the expected record. +4. `path_and_resolution_independence`: canonical names, forbidden syntax, root identity, shadowing, and unresolved-resource behavior are represented without requiring a filesystem or resolver side effect; E's parser result remains deterministic when resolver availability changes. +5. `bfc_state_and_invertnext`: file-local certification, winding, XOR inversion, one-shot `INVERTNEXT`, blanks, intervening commands, malformed references, EOF, and stable diagnostic codes match the profile row. +6. `colours_and_ldconfig`: colour 16/24 semantics, direct colours, alpha/luminance/finish/material fields, unknown colours, and scoped `!COLOUR` output are preserved or diagnosed exactly. +7. `graph_identity_and_instances`: iterative include traversal, stable file/model IDs, cycle detection, cache reuse, repeated-model parse-once behavior, and distinct instance identity match expected graph records. +8. `steps_and_transforms`: STEP boundaries, finite right-handed LDU transforms, reflection state, bounds inputs, and no-early-scaling expectations match canonical records. +9. `numeric_finiteness_and_raw_preservation`: signed zero, decimal/exponent spelling, finite extremes, overflow/underflow, non-finite rejection, invalid counts, and lossless raw representation match profile expectations. +10. `semantic_limits_and_cancellation`: each D-owned LDraw semantic limit has limit and limit+1 expected outcomes, deterministic diagnostics, cancellation checkpoints, and post-cancellation cleanup. + +Each gate has at least one happy, error, and boundary/adversarial fixture where the profile permits it. Gate IDs and profile names are serialized in failure reports so E's acceptance claim “all PM-77 semantic corpus gates” is mechanically checkable rather than a prose promise. Gate definitions, their pure evaluation tests, and E-facing traits must compile with `cargo check --tests --target wasm32-unknown-unknown`; only native oracle/process tests are target-gated. + +### 3. Ownership of limits + +D owns **LDraw-semantic** limits and vectors: maximum resource/file bytes (100 MiB/resource), line length (1 MiB/line), files (16,384), include depth (256), commands (5,000,000), instances (5,000,000), triangles (20,000,000), lines (20,000,000), textures (1,024), fetches (8), diagnostics (10,000), plus malformed/overflow and cleanup behavior at each limit and limit+1. D does not duplicate reservation formulas. + +B/PM-88 owns **reservation-arithmetic** vectors: every class/domain/load/global/unified ceiling, checked u64 overflow, `ceil_div`, `align_up`, WASM/GPU/texture/canvas formulas, invalid dimensions, and resize old+new overlap. D's adapter contract can carry reservation outcomes, but B's implementation and arithmetic corpus remain authoritative. + +## Implementation steps + +### 1. Establish inventory, profiles, records, and gate API + +Define fixture identity, exact bytes, relative path, line-ending mode, behavior tags, authority class, profile (`strict`, `compatibility`, `lossless`), expected outcome, source spans/raw tails, diagnostics, semantic/scene records, adapter observations, and provenance. Embed the inventory and fixture bytes or use another target-safe representation; runtime filesystem/network access is forbidden in the reusable crate. + +Implement the `CorpusGate`/`CorpusGateSet` contract above, the ten named v1 gates, profile applicability validation, deterministic `GateFailure`, and machine-readable coverage reporting. Keep expected records separate from observations. Reject duplicate IDs, duplicate gate/profile rows, missing expected records, missing required categories, unreferenced files, and incomplete provenance. + +**Done when:** `cargo test -p polymodel-ldraw-testkit` validates the inventory and gate set, intentionally malformed inventory/gate cases fail, all ten gates have named profile rows, and `cargo check --tests -p polymodel-ldraw-testkit --target wasm32-unknown-unknown` passes without forbidden dependencies. + +### 2. Author the complete ratified-spec corpus + +Create exact-byte, behavior-named fixtures and independently reviewed expected records for: + +- types 0–5, comments/meta, subfile references, lines, triangles, quads, conditional syntax, whitespace, CRLF/LF, blank lines, BOM/UTF-8, unterminated final lines, raw tails, byte/line spans, and malformed boundaries; +- MPD `FILE`/`NOFILE`, `!DATA`, duplicate names, missing terminators, unreachable blocks, payload decode and embedded-resource limits; +- BFC `CERTIFY`, `NOCERTIFY`, `CCW`, `CW`, `INVERTNEXT`, nested/subfile state, blanks/intervening commands, malformed references, EOF, and exact diagnostic outcomes; +- colour definitions, colour 16/24, direct colours, alpha/material/finish/luminance, unknown colours, and LDConfig-derived values; +- `!TEXMAP` start/next/fallback/stop, points, explicit edges, and conditional-line syntax; +- numeric spelling and finiteness boundaries, invalid counts, overflow/underflow, and stable diagnostics; +- semantic limit and limit+1 cases from the ownership list, cancellation checkpoints, and cleanup after aborted work. + +Hand-author expectations from ratified specifications and PM-75; an upstream output must never rewrite an expected file. Record fixture hashes and authority/source citations. + +**Done when:** the inventory report shows every acceptance category with happy, error, boundary, and adversarial cases; every fixture has an independently reviewed expected record and exact input-byte hash; all ten gate families can select at least one fixture. + +### 3. Add all four canonical path/root contexts + +Build a dedicated path-policy fixture family for PM-75 §3.3. For **each** context below, include happy resolution, shadowing/precedence, collision, out-of-root, and forbidden-syntax cases (literal `%`, backslash, empty/dot/dot-dot segment, leading/trailing slash, controls, colon, query, and fragment): + +1. current MPD virtual-file table: exact-case lookup, duplicate names, and MPD shadowing of external roots; +2. uploaded manifest: relative directory then manifest root, exact-case keys, duplicate canonical keys, and explicit-prefix behavior; +3. uploaded LDraw roots: `MODELS → PARTS → P`, with explicit `s/`, `8/`, and `48/`, ASCII-fold lookup/collision, and no fallback after an explicit prefix; +4. pinned official library: `PARTS → P`, explicit `s/`, `8/`, and `48/`, canonical spelling, ASCII-fold collision, and ingestion invalidation. + +Expected records must include canonical spelling, root identity, target identity, cache identity, and resolver-independent parser behavior. Include repeated-reference and cycle cases that exercise canonical identity without using a real filesystem. + +**Done when:** matrix validation proves all four contexts and all five sub-families are represented, MPD shadowing and explicit-prefix no-fallback are asserted, and no fixture can activate URI/network access. + +### 4. Add H-owned conditional-line classifier fixtures + +Reserve a complete `h-conditional-*` fixture family in the D corpus and mark H/PM-81 as the owner of the hand-computed coordinates and expected packed outcomes. D supplies the fixture schema, hashes, profile/matrix rows, and expected-record versioning; H consumes these vectors without redefining the classifier contract. + +Include at minimum one hand-computed vector for each of the six PM-75 §3.5 outcomes: + +- `Visible` — same-side controls; +- `SuppressedInterior` — strictly opposite-side controls; +- `SuppressedOffscreen` — endpoint segment has no surviving clip interval; +- `SuppressedAmbiguous` — projectable control has unsafe/non-positive `w`; +- `SuppressedDegenerate` — clipped endpoint segment is shorter than epsilon; +- `Invalid` — non-finite homogeneous input with the stable diagnostic. + +Also include epsilon boundary vectors immediately below, exactly at, and immediately above segment `epsilon` and oriented-area `±epsilon`; `w_epsilon` below/exactly/above and `w <= 0`; near/far/side-plane clipping; off-frustum but projectable controls; unsafe control `w`; behind-camera endpoint; reflection; perspective and orthographic projections; same/opposite/collinear controls. Expected records must assert that only `Visible` emits a segment and suppressed outcomes emit no diagnostic unless the contract says otherwise. + +**Done when:** all six outcomes and every epsilon/`w_epsilon` boundary have committed coordinates, hand-computed expected records, owner metadata `H/PM-81`, and matrix rows; H can consume them through the v1 record format without adding a new corpus schema. + +### 5. Pin external artifacts and provenance + +Add minimized, legally attributable artifacts for Thomas fixtures, OMR and official-library examples, weldr, and ldr_tools. Every non-authored artifact records source URL, exact commit/blob/archive, SHA-256, license or operator-attested permission, original test identity, modifications, and authority class. Keep selected files and notices in the repository; acquisition is a separate maintenance operation and normal tests are offline. + +Use PM-75's exact LDParse revisions: + +- master: `877667417d6cab57c04aed9cb3d5bfe7efa0589c`; +- modernization: `0fe78dcee22982f26cceced1b483340faa4d04e9`. + +Record both revisions, their source URLs, source/archive SHA-256, and license evidence in the ledger. The provenance validator recomputes every committed artifact hash and rejects altered, unlisted, or under-attributed files. + +**Done when:** all selected artifacts and permission/license records are committed, provenance tests pass offline, both exact LDParse revisions are source-verified, and a clean checkout can reproduce the pinned inputs without floating branches or network access. + +### 6. Build the reproducible native LDParse and oracle adapters + +Model adapter classes explicitly: + +- `InProcessRustAdapter`: crate-pinned, target-safe Rust implementation adapter for E/F/K records; +- `OutOfProcessAdapter`: subprocess adapter with explicit executable/driver identity, environment, timeout, termination, stdout/stderr, exit status, and version evidence. + +LDParse is **only** an `OutOfProcessAdapter`; it is not treated as a binary. Commit `tools/ldraw-compat-harness/ldparse_driver.py`, a pinned `.python-version` specifying **CPython 3.12.8**, `pyproject.toml`, and `uv.lock` with hashes. Vendor the two source revisions or commit verified source archives and their SHA-256; the driver must import only the source matching the selected revision and print a deterministic JSON record. The README must document `uv sync --locked` and the offline invocation. The harness must reject a wrong interpreter, lockfile drift, source hash/revision mismatch, missing version evidence, network-enabled acquisition, timeout, crash, malformed driver output, or normalization failure. + +The required LDParse oracle surface is fixed, not discovered at implementation time: the driver and corpus must exercise line types 0–5 with raw tails/spans, MPD `FILE`/`NOFILE` boundaries, include/model graph and cache/instance identity, BFC certification/winding/`INVERTNEXT`, STEP boundaries, finite numeric/diagnostic outcomes, and deterministic acceptance/rejection for those cases. Every invocation maps to a fixture and expected record. TEXMAP, conditional-line classification, renderer batches, and any other feature not in this minimum surface are not silently claimed as LDParse coverage; they are marked `unsupported-by-ldparse` in the ledger and tested through authored expectations or another independently pinned adapter. + +For all process adapters, load only inventory-listed fixtures, enforce wall-clock/input/resource budgets, capture complete evidence, normalize without erasing raw tails/spans/order/diagnostics/BFC/paths/colours/geometry distinctions, and emit machine-readable mismatches linked to fixture and ledger IDs. weldr/ldr_tools expected values must be independently derived, never copied from one another. + +**Done when:** `uv sync --locked` succeeds under CPython 3.12.8 offline with the committed source pins; the native driver produces deterministic JSON for every required LDParse fixture; the harness tests wrong pin/interpreter, timeout, crash, unsupported-surface, and malformed-output failures; no required surface is covered by an escape clause. + +### 7. Implement canonical v1 serialization and compatibility ledger + +Serialize syntax/semantic/scene records with stable field order, stable non-semantic collection ordering only, explicit integer widths, canonical finite decimal/float formatting, explicit non-finite tokens, lowercase hex digests, normalized path separators, and explicit spans/raw bytes/diagnostics/provenance. Do not sort semantically ordered statements, geometry indices, BFC transitions, or diagnostic order. + +Add golden snapshots for syntax, MPD graph, BFC/colour state, points/edges/conditional geometry, scene hierarchy/instances/bounds, all ten gate families, and representative limit/cancellation outcomes. Add a compatibility ledger row for each disagreement with specification citation, observations, selected behavior, rationale, owner/date, and regression fixture; validation requires every oracle output and disagreement to link to a row. + +**Done when:** repeated serialization is byte-identical, valid insertion-order independence is tested, ordered data remains ordered, v1 schema/version rules are documented, and no upstream observation is accepted as normative without a ledger decision. + +### 8. Add bounded fuzz/property/adversarial smoke + +Create a deterministic native smoke command with committed malformed inputs and minimized regressions, fixed seeds, fixed iteration/case budgets, byte/depth/time limits, and killable process execution. Cover whitespace/line endings, malformed numerics, path traversal and collisions, MPD duplicates/cycles/deep chains, DATA/TEXMAP truncation, BFC transitions, semantic limits and limit+1, cancellation/cleanup, and canonicalization stability. Reports record seed, iterations, budgets, toolchain, adapter identity, and pass/fail. + +Expose the adapter seam for E's in-process parser and K's later expansion without making the testkit native-only. Add no unbounded or networked fuzz job. + +**Done when:** `just ldraw-fuzz-smoke` runs from a clean checkout with fixed seeds and deterministic output, every named adversarial class has a committed regression input, and cancellation/limit behavior cannot hang or panic. + +### 9. Wire commands, target checks, documentation, and merge gate + +Add these commands: + +- `ldraw-corpus`: inventory, provenance, matrix, gate, and snapshot tests; +- `ldraw-wasm-check`: `cargo check --tests -p polymodel-ldraw-testkit --target wasm32-unknown-unknown` plus the reusable E-facing gate path; +- `ldraw-fuzz-smoke`: bounded property/adversarial regression; +- `ldraw-differential`: offline native harness with `uv run --locked` and pinned source/toolchain evidence. + +Update `test-all` so these four recipes are explicit prerequisites in addition to the existing `fix check lint test test-server test-renderer`. This makes corpus, fuzz, differential, and wasm checks part of the ordinary merge gate rather than documentation-only commands. Keep native-only process work out of wasm recipes and preserve `verify-renderer-split`. + +Document fixture authoring, expected-record review, gate implementation for E, H vector ownership, provenance/permission review, pin updates, ledger decisions, Python setup, offline commands, and schema versioning. + +**Done when:** every recipe is runnable and documented; `just test-all` actually invokes all four new recipes; wasm compilation succeeds for testkit/gate code; native-only boundaries are explicit; no app dependency tree gains forbidden renderer/parser crates. + +## Test strategy + +This task has no provider, daemon, TUI, browser, or UI behavior. Tier 2 TestProvider, Tier 3 daemon integration, and Tier 4 TestBackend do not apply. + +| Behavior | Tier and infrastructure | Required cases | +|---|---|---| +| Inventory, profiles, and named corpus gates | Tier 1 pure Rust tests in `polymodel-ldraw-testkit` over embedded bytes/records | happy path; duplicate/missing gate; missing profile row; missing expected record; every one of ten gates; strict/compatibility/lossless applicability | +| E-facing gate evaluation and wasm safety | Tier 1 pure gate tests plus `cargo check --tests --target wasm32-unknown-unknown` for testkit and E adapter path | all gate names; no filesystem/process/network; wasm compile; expected gate failure details | +| Authored syntax/semantic expectations | Tier 1 corpus tests through adapter trait | types 0–5; raw tails/spans; MPD/DATA; BFC; colours; four path contexts; cycles; TEXMAP; numeric boundaries; diagnostics | +| Path/root policy | Tier 1 table-driven fixture tests | all four contexts, each with happy/shadow/collision/out-of-root/forbidden syntax; exact-case, ASCII-fold collision, explicit-prefix no-fallback, MPD shadow | +| H conditional-line family | Tier 1 fixture/schema validation in D; H-owned downstream classifier tests consume v1 records | six outcomes; epsilon and `w_epsilon` below/exact/above; clip planes; unsafe controls; reflection; perspective/orthographic; hand-computed coordinates | +| Provenance and integrity | Tier 1 deterministic hash tests | valid artifact; altered bytes; missing source/revision/license; modification/authority mismatch; unlisted file | +| Canonical v1 records | Tier 1 golden/snapshot tests | repeated serialization; valid insertion-order independence; ordered BFC/diagnostics/geometry preservation; raw bytes/spans; floats/non-finite; schema version | +| Semantic limits and cancellation | Tier 1 bounded adapter/property tests | each D-owned semantic limit and limit+1; malformed/overflow; depth/cycles; cancellation; cleanup; no hang/panic. Reservation arithmetic is covered by B/PM-88, not duplicated here | +| LDParse differential | Native standalone integration command, Tier outside Tiers 2–4 | CPython 3.12.8/uv.lock; both exact revisions; required minimum surface; deterministic JSON; wrong pin/interpreter; source mismatch; timeout; crash; unsupported surface; malformed output | +| Thomas/weldr/ldr_tools/OMR evidence | Native standalone integration plus Tier 1 ledger/provenance tests | attribution; independent expected values; source/hash; disagreement requires ledger decision; no oracle becomes normative implicitly | +| Fuzz/property/adversarial | deterministic seeded native smoke command | committed regressions for whitespace, numerics, paths, cycles, MPD/DATA/TEXMAP, BFC, limits, cancellation, serialization; fixed budget/timeout/kill path | +| Workspace and renderer split | target checks and existing recipes | `just check`; wasm testkit check; `just verify-renderer-split`; app tree remains free of `three-d`, `three-d-asset`, `stl_io`, `polymodel-mesh` | + +Run focused validation in this order, then the complete merge gate: + +```text +just check +just ldraw-corpus +just ldraw-wasm-check +just ldraw-fuzz-smoke +just ldraw-differential +just fix +just test +just test-server +just test-renderer +just test-all +``` + +`just test-all` is the final merge gate and must visibly execute `ldraw-corpus`, `ldraw-wasm-check`, `ldraw-fuzz-smoke`, and `ldraw-differential`. A failure must be fixed in the task diff or reported with the exact failing fixture/tool and reproducible command; no undocumented assumption is an acceptable result. + +## Finding dispositions from planner-D2 + +- **D-plan-2-C1 (critical): fixed.** The plan defines `CorpusGate`, named/profile-scoped assertions over fixture expected and actual canonical records, a gate set, wasm-safe E implementation boundary, and ten minimum v1 gates. +- **D-plan-2-C2 (critical): fixed.** PM-75's exact master and modernization revisions are named; the required LDParse surface is enumerated; the plan does not defer build-surface discovery or offer a “fully exercised or limited” escape clause. +- **D-plan-2-H1 (high): fixed.** The `h-conditional-*` family covers all six outcomes, hand-computed coordinates, epsilon/`w_epsilon` boundaries, clipping, control, reflection, and projection cases and is owner-allocated to H. +- **D-plan-2-H2 (high): fixed.** Path fixtures explicitly cover all four PM-75 §3.3 contexts, with happy/shadow/collision/out-of-root/forbidden-syntax sub-families and precedence/no-fallback checks. +- **D-plan-2-H3 (high): fixed.** D's LDraw-semantic limits and limit+1 vectors are enumerated and explicitly separated from B's reservation-arithmetic boundaries. +- **D-plan-2-H4 (high): fixed.** LDParse is explicitly modeled as a Python library behind a committed `ldparse_driver.py`, not as a binary; source pins, driver, interpreter, and lockfile are part of the deliverable. +- **D-plan-2-H5 (high): fixed.** `test-all` is required to depend on all four new corpus/wasm/fuzz/differential recipes, and the plan requires verifying that they actually run. +- **D-plan-2-H6 (high): fixed.** CPython 3.12.8, `.python-version`, `pyproject.toml`, `uv.lock`, `uv sync --locked`, and offline/hash-pinned behavior are specified. +- **D-plan-2-M1 (medium): fixed.** Gate definitions/evaluation and E's adapter path are wasm-compileable; only native subprocess/oracle differential code is target-gated. +- **D-plan-2-M2 (medium): fixed.** Canonical syntax/semantic/scene records are explicitly a committed v1 cross-task contract with golden snapshots and schema-bump rules. +- **D-plan-2-M3 (medium): fixed.** In-process Rust and out-of-process adapters are separate abstractions; LDParse is only out-of-process. +- **D-plan-2-L1 (low): fixed.** The root uses `members = [".", "crates/*"]`; the plan tells the implementor not to add a redundant member declaration. + +## Commit and review requirements + +Commit the implementation on the task change with a concise PM-77 message and exactly these trailers: + +```text +Epic: PM-86 +Task: PM-77 +``` + +Implementation reviewers must verify: + +- every task acceptance category and every required happy/error/boundary/adversarial case has committed input and expected output; +- all ten named semantic corpus gates are machine-validated, profile-scoped, wasm-safe, and consumable by E; +- v1 canonical records, snapshots, and compatibility rules are stable for E/F/H/K; +- all four path contexts and the complete H conditional-line family are present with hand-computed expectations; +- D/B ownership of semantic versus reservation-arithmetic limits is not blurred; +- provenance is hash-validated, legally attributed, and records source/blob, original test, modifications, and authority; +- LDParse uses both exact PM-75 revisions, CPython 3.12.8, `uv.lock`, the committed driver, and the fixed minimum oracle surface; +- upstream observations are separated from authored expectations and every disagreement has a ledger decision; +- weldr/ldr_tools expectations are independently derived; +- the testkit remains dependency-light and wasm-compatible, and the renderer split is unchanged; +- fuzz/property execution is bounded, seeded, killable, and included in `just test-all`; +- `jj diff` contains fixture bytes, expected outputs, provenance/permission records, pins, commands, documentation, and the `test-all` wiring, with no generated API or unrelated production/UI files. + +## Ready-for-parent-merge handoff + +Before returning to the parent orchestrator, provide: + +1. task workspace/bookmark and commit ID; +2. changed-file summary, corpus byte/file counts, schema version, and all pinned upstream revisions/toolchain identifiers; +3. the verified LDParse minimum surface and the explicit ledger rows for features outside it; +4. exact focused command output, including `cargo check --tests --target wasm32-unknown-unknown` and `just test-all`, proving the four new recipes ran; +5. confirmation that `jj diff` was reviewed and no prohibited state/source/generated files were modified; +6. any remaining risk as a reproducible failing command or missing external permission, never as an undocumented assumption. diff --git a/.current-task/task.md b/.current-task/task.md new file mode 100644 index 0000000..f04af2f --- /dev/null +++ b/.current-task/task.md @@ -0,0 +1,43 @@ +# Task D — PM-77: Implement: LDraw corpus and compatibility harness + +**Jira:** [PM-77](https://radiant-industries.atlassian.net/browse/PM-77) +**Status:** To Do +**Priority:** Medium +**Labels:** compatibility, fixtures, implement, ldraw, tests +**Execution Prefix:** D | Sort Order: 40 +**Epic:** [PM-86](https://radiant-industries.atlassian.net/browse/PM-86) +**Design source:** [PM-75 design](https://radiant-industries.atlassian.net/wiki/spaces/PM/pages/5570561) + +## Dependencies + +Blocks: E (PM-78), F (PM-79), K (PM-84) +No predecessors. + +## Goal + +Create the reproducible parser/semantic/visual test foundation before production implementation. + +## Scope + +Authored ratified-spec micro-fixtures and strict/compatibility/lossless matrix; buildable pinned LDParse differential harness; attributed Thomas fixtures; pinned OMR/official-library artifacts; minimized weldr/ldr_tools parser/MPD/resolver/BFC/geometry tests with independently derived expectations; fuzz/property/adversarial budget harness; deterministic semantic/scene serialization. + +Fixture provenance records source URL, exact commit/blob, SHA-256, licence or operator-attested permission, original test, modifications and authority class. Upstream implementation output is never normative without a compatibility-ledger decision. + +## Acceptance + +Coverage includes types 0–5, raw tails/spans, MPD/DATA, exact BFC state, colours, canonical/root path vectors, cycles, TEXMAP, points/edges, diagnostics, numerical boundaries, resource limits and cancellation. The LDParse oracle is reproducibly buildable in its pinned environment or explicitly limited to the verified buildable surface with fixtures proving each oracle use. + +## Merge-ready tests + +* `just check` +* `just fix` +* focused corpus/harness tests +* fuzz/property corpus smoke/regression command established by this task +* wasm32 check for reusable harness/core fixtures where applicable +* `just test-all` before handoff + +The isolated jj workspace must be green and independently merge-ready; fixtures, permissions, expected outputs and harness invocation are committed, not described for later. + +## Comments + +None. -- 2.51.2