Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,10 @@ opus fallback. Roll math (multishot DPS) unit-tested before UI.
| 2026-07-05 | E10 final grill + fold | Multi-track on the post-sweep tree: **(A) wire-contract packet** — mimo died mid-exploration (free route unusable even on small packets today) → orchestrator ran the enumeration DIRECTLY (mechanical: types.ts fields vs mapper emissions, all 7 mappers): **SOUND, exhaustive** — every field emitted, every optional null-clears. **(B) validation-totality packet** — mimo DELIVERED (single-module): 8 findings adjudicated → F7b REFUTED (`max(ammo_per_shot,1)` already guards the DPS division; 0 = "consumes no ammo", legal), F3 NOT-FIXABLE (withPartTag.tag has no DesignRNG-side vocabulary — documented gap, same status as F7-union), 6 FIXED: gunType + compatibleGunTypes dangling refs (vocabulary-gated on `catalog` presence so fresh/sample projects don't false-flag — sidecar-gate parity), synergy withStyle dangling ref, negative damageMultiplier (heals on hit)/headshotMultiplier/ricochet.minAngleDeg, **per-collection duplicate-id detection ×9** (same-id entities silently collapse on upsert) — +5 regression tests. **(C) 3-lens workflow panel w/ adversarial verify** (ultracode): 7 confirmed / 0 refuted, all fixed — ADR 0006 misdescribed the extras bag as DENY-list when upserts are WHITELIST-only (`_EXTRAS_CAMEL_TO_SNAKE`; the load path IS deny-list — the doc would have made silent field loss look intermittent) → corrected w/ the register-your-field instruction; ADR envelope omitted the mandatory `format:"designrng.preset"` magic → documented; ADR "all five collections default to []" wrong for hard-required partTypes → corrected; **effectCatalog cited a nonexistent `model/effects.py` AND its per-effect params had drifted from gunModeller's real `effect_parameters.py`** — FUNCTIONAL fix, not just docs: catalog resynced verbatim (chain_lightning radius/damage/max_targets, status_effect duration_ticks/amplifier, vampiric heal/splash_heal, + 8 more entries; identifier vocabulary gains `entity`; projectile_entity corrected particle→entity) — the old lists FALSE-FLAGGED legal params in the typo guard and omitted them from the schema forms; verified live in the mirror; GUNRNG_CHANGES dead "see below" pointer + "other two[=three] dataclass fields" count fixed; `.claude/launch.json` (session-scratchpad path) gitignored before any blanket `git add`. **Coverage debt recorded: the flow-lens reviewer died on Anthropic session capacity (259k tokens in)** — mitigation: every per-chunk grill already walked its own seams and every create/edit/save flow was preview-verified live during E4–E8 folds; the lens was a redundancy pass. Cross-family debt from E6/E7 partially discharged via packet B + the deterministic packet A | vitest **512/512** · pytest **113/113** · compat **19/19** · typecheck/lint/build ✅ · mirror probe of resynced forms ✅ | **E10 grill folded — EXPANSION E1-E10 COMPLETE** | ship (commit/push/PR) |
| 2026-07-05 | E10 ship | 5 thematic commits on `plan/expansion-ammo-parts-presets` (core domain E1/E9 · sidecar pipeline E2-E3/E7 · editor UI E4-E6/E7 · presets E8 · docs E10) pushed; PR #5 retitled + rebodied to the full implementation (`gh` permitted this round). CI: **web PASS** (1m0s), sidecar skipping (cross-repo matrix, by design). Tree clean; `.claude/launch.json` gitignored | PR #5 · CI green | **EXPANSION SHIPPED — awaiting owner merge** | owner merge of PR #5; post-merge follow-ups live in GUNRNG_CHANGES status table + ADR 0006 open items |

| 2026-07-16 | P2.3a handling mirror | DesignRNG-native P2.2a part ordering + binary32 handling aggregate; hard editor/sidecar/export domains; precision-safe optional-number drafts; signed-int32 part-type order with pre-legacy raw-import refusal; native Roll handling card using the selected Roll parts; typed identity/slot/scalar/overflow diagnostics; high-precision numeric-value persistence/export pins. Arms NG consumer `dfb76e5` is shipped/green. The preview labels `.01`/`.65`/`.25s` as server-configurable defaults and explicitly leaves timed ADS to P3.2. Whole-profile P2.P1 quantization remains open. Namespace-exact export parity is gated on rebasing the `canonical-v3-identifiers` prerequisite. Node-only tests cover reducers/SSR; real OptionalNumberField/PartTypeRow/RollPanel DOM interactions remain explicitly recorded CDP/harness debt. | typecheck/lint/build ✅ · vitest **570/570** · sidecar pytest **168/168 + 2 platform skips** · isolated fixture verifier **18/18 + 2 platform skips** · legacy-v3 compat oracle **19/19** | implementation + HOLD fixes complete and fully gated in working tree, not yet shipped | rebase identifier prerequisite → independent re-grill → PR to `dev` |

| 2026-07-18 | P2.3a rebase onto canonical identifiers | `codex/p23a-handling-preview` rebased onto `main` `1c0a790` (ADR 0008 canonical v3 identifier boundary, #20/#21). Conflict resolutions keep main's boundary authoritative: bridge docstring + load-preflight order take main's shipped form (identity preflight, then P2.3a raw sort_order preflight); `libraryValidation.ts` reverts to main's alias-aware `bareId` comparisons (its `bareId` now folds `armsng:` too, so the P2.3a alias-duplicate tests hold) and keeps only the new sortOrder/handling-scalar domains; `partOrdering.ts`/`partHandling.ts` drop the private `canonicalProjectPartTypeId` canonicalizer and consume the shipped `identifierIdentity` — no parallel identity implementation survives. P2.3a's sidecar hooks (`save_part` handling refusal, `save_part_type`/`validate_project` sort_order domain, raw-import preflight) composed onto main's `_new_doc_id`/oracle-view rewrite without semantic loss. TS `orderSelectedParts` omits main's third-key part-id tie-break by design: `resolvePartHandling` refuses duplicate selected slots before ordering, so the tie is unreachable in the preview path. | typecheck/lint/build ✅ · vitest **588/588** · sidecar pytest **709 passed + 4 skips (41 subtests)** | rebase complete, fully gated on the canonical-identifier main | independent re-grill → PR to `dev` |

# CURRENT ROADMAP — PART-SURFACE V4 COORDINATION (2026-07-11)

This is DesignRNG's authoring-side P4 plan, coordinated with Arms NG `PLAN.md` P4
Expand Down Expand Up @@ -805,6 +809,14 @@ not a v4 owner or release gate. See ADR 0007.
legacy-oracle commit. **P4.D1 remains open:** the redistributable fixture and its
owner-selected license have not yet been published, so the shipped verifier foundation
alone does not complete the slice.
- **P2.3a handling mirror IMPLEMENTED (2026-07-16; rebased onto canonical identifiers
2026-07-18; pending independent grill):** Arms NG `dfb76e5` is the shipped/green consumer.
DesignRNG now owns native part ordering, binary32 handling composition, hard
authoring/export validation, and the Roll handling preview. The `canonical-v3-identifiers`
prerequisite (ADR 0008, `main` `1c0a790`) has landed and this branch sits on it: the
handling layer consumes the shipped `identifierIdentity` helper instead of a private
canonicalizer. This closes only R1.10 handling parity; whole-profile P2.P1 quantization
and P3.2 timed ADS remain open.
- The existing `snapPoints` / `snapLocation` editors and sidecar derivation are
**schema-v3-only compatibility surfaces**. Schema v4 replaces part-docking
snaps with base-owned surface bindings while retaining typed semantic locators.
Expand Down
15 changes: 15 additions & 0 deletions docs/CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ and the pack's **rarity curve**. DesignRNG's job is to author and curate that po
and is computed **sidecar-side** (`bridge.py sustained_dps_v2`) and carried on the roll payload,
not recomputed in TS (`docs/GUNRNG_CHANGES.md` §E7 is canonical; ADR 0004's "pellets=1,
display-only" is superseded-in-part). *Avoid:* DPS-per-shot, burst DPS.
- **Handling preview** — the Roll card's DesignRNG-native R1.10 view over the exact selected
parts: total `weightKg` and `adsTimeAdd`, folded in canonical part-type order with Java-float/
IEEE-754 binary32 rounding after every addition. It also shows movement and effective-ADS
values under clearly labelled Arms NG server-configurable defaults. It is not a timed ADS
animation: P3.2 owns consuming that duration. Typed composition errors (canonical part-id
collision, missing selected part, selected-part slot mismatch, duplicate slot, invalid scalar,
or overflow) are author-facing refusals, not zero/default data.

### Authored definitions (EXPANSION, 2026-07-05)
- **Authored definitions** — the collective term for the EXPANSION's newly-authorable
Expand Down Expand Up @@ -170,6 +177,14 @@ and the pack's **rarity curve**. DesignRNG's job is to author and curate that po
- The **Library** tab browses the pool; the **Modeller** edits one base/part's geometry + snaps at a
time (**Apply changes** writes it back); the **Roll** tab previews what the generator actually
produces from the pool.
- The Roll card's **handling preview** resolves from that roll's selected part ids, never from
sidecar map iteration order. Its native resolver compares bare, `gunrng:`, and `armsng:`
spellings as one local project identity while foreign namespaces remain exact — via the
shipped ADR 0008 `identifierIdentity` helper (`identifiers.ts`), never a second alias
implementation. The `canonical-v3-identifiers` prerequisite has landed on `main` and this
branch is rebased onto it. Persistence retains the parsed IEEE-754 binary64 numeric value
(not the author's lexical decimal spelling); only handling-preview arithmetic deliberately
converts to binary32.
- **DesignRNG** is the authority for the authored model, validation, migration/report,
and export contract. The independent-operation transition is not complete until P4.D1–D6.
The **Export sidecar** currently executes an import-backed schema-v3 compatibility path;
Expand Down
56 changes: 49 additions & 7 deletions docs/GUNRNG_CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ The v4 model, validation, migration/report, fixture, and export live in DesignRN
Arms NG as the coordinated runtime consumer.

**Operational qualification:** the transition is not complete. Current DesignRNG export
is import-backed schema-v3 compatibility; project-file v2 is not self-contained, and
P4.D0 must close the session-identity/hidden-state/destination-overwrite hazards before
the export path is accepted. P4.D6 is the clean no-token independence gate.
is import-backed schema-v3 compatibility and project-file v2 is not self-contained.
P4.D0 has closed the immediate session-identity and destination-safety hazards; P4.D6
remains the clean no-token independence gate.

## Status (authoring baseline 2026-07-05; authority updated 2026-07-12)
## Status (handling parity updated 2026-07-16)

The EXPANSION (E1–E9) is code-complete and grilled; DesignRNG now has authoring UI for
every R1.x item below **except** the pure-semantics/verification items, which remain
runtime-only obligations no authoring UI can discharge (they're rules the mod's code must
follow, not fields an author fills in). Every field is on the wire today as an ordinary
flat key (own authoring UI) or an existing gunModeller field DesignRNG now edits directly
(part types) — nothing here is blocked on DesignRNG-side work; everything below is a
GunRNG (mod-side) TODO.
(part types). Runtime status is tracked row by row; completed Arms NG consumers are no
longer described as open mod-side work.

| R1.x | Item | DesignRNG authoring UI | Status |
|---|---|---|---|
Expand All @@ -39,7 +39,7 @@ GunRNG (mod-side) TODO.
| R1.7 | Per-ammo falloff curve | AmmoEditor (E4) | **Authoring shipped** |
| R1.8 | Armor interaction (`armorIgnore`, `headshotMultiplier`) | AmmoEditor (E4) | **Authoring shipped** |
| R1.9 | Ammo economy (`craftCost`) | AmmoEditor (E4) | **Authoring shipped** (mod-side recipe generation still TODO) |
| R1.10 | Part weight & handling | PartPanel Advanced group (E6) | **Authoring shipped** |
| R1.10 | Part weight & handling | PartPanel Advanced group + native Roll handling preview | **Runtime shipped/green at Arms NG `dfb76e5`; DesignRNG mirror implemented 2026-07-16** |
| R1.11 | Muzzle silence + recoil split; new part types | PartPanel Advanced (silence/recoil, E6) + Library "Part types" strip (any custom type, E6) | **Authoring shipped** (mechanism); specific `muzzle`/`grip`/`underbarrel` seed content was **not** bundled — reconciled below |
| R1.12 | Part synergies (conditional modifiers) | PartPanel synergy editor (E6) | **Authoring shipped**, catalog-vocabulary only (imported-pack condition ids not yet reachable — F7, tracked below) |
| R1.13 | Modifier stacking + application order | Roll preview consumes authored part-type `sortOrder` | **Runtime + semantic/order preview parity implemented 2026-07-12**; whole-profile numeric quantization remains P2.P1 |
Expand Down Expand Up @@ -169,6 +169,48 @@ gates recipes from it (exact recipe policy is a mod decision; the field is the c
`weight_kg: float` (movement/handling penalty while equipped — TaCZ attachments) and
`ads_time_add: float` (seconds, additive ADS-in time). Applies to ALL part types.

Arms NG `dfb76e5` consumes both fields. DesignRNG's native preview converts every
authored scalar to IEEE-754 binary32 first, folds in ascending authored part-type
`sort_order` (legacy missing-definition fallbacks 10/20/30/40/50 for receiver/barrel/
stock/magazine/sight, then 1000; ordinal canonical-id tie), and rounds after every
addition. `weight_kg` must become finite and non-negative; `ads_time_add` must become
finite. Invalid authored scalars block validation/export through the DesignRNG-owned
sidecar gate. Missing selected parts, duplicate selected slots, and either aggregate
overflow are typed Roll-composition refusals surfaced on the card. Canonical gun-part-id
collisions and a Roll-selected part whose reported slot disagrees with its authored slot
also refuse with dedicated error codes, before any colliding map entry can overwrite another.

Part-type `sort_order` is a signed 32-bit integer (`-2147483648..2147483647`), matching
Arms NG's `Codec.INT`. The Library draft/parser, numeric-input bounds, renderer hard gate,
`savePartType` RPC, and direct validate/export gate enforce the same domain. The DesignRNG
raw importer scans `part_types/*.json` before the legacy loader can call `int(...)`, so
fractional, one-beyond, unsafe-integer, and boolean values refuse with their source path and
cannot mutate the active session.

The card labels policy values as **server-configurable defaults**: movement
`max(0.65, 1 - total_weight_kg × 0.01)` and effective ADS
`clamp(0.25s + ads_time_add, 0.05s, 3s)`. It does not claim a timed ADS transition is
active; P3.2 owns that consumption. Persistence preserves the parsed binary64 numeric value,
not lexical JSON spelling (trailing zeroes/exponent form may normalize); only preview arithmetic
uses `Math.fround`. The pinned `64.88005` value survives editor/save/export/reload numerically.

The native handling resolver applies the local-alias comparison through the shipped ADR 0008
identity boundary (`identifiers.ts` `identifierIdentity` renderer-side; `v3_identifiers.py`
sidecar-side). The `canonical-v3-identifiers` prerequisite has landed on `main` and this branch
is rebased onto it, so sidecar collision/export assertions stay owned by that boundary — the
handling slice adds no second alias implementation.

**UI coverage note:** this repository's Vitest environment is Node-only and currently installs
no jsdom, happy-dom, React test renderer, or Testing Library. The slice pins
`OptionalNumberField`'s focus/blur contract through its public draft reducer plus SSR accessibility,
and `PartTypeRow`'s min/max/diagnostic markup through SSR. A real RollPanel overlapping-request
interaction (including newest-request/project snapshot pairing) and an actual focus/blur DOM event
remain CDP/DOM-harness coverage debt; no P2.3a CDP interaction run is claimed by this branch.

This closes R1.10 handling-aggregate parity only. It does **not** close named debt
P2.P1: the rest of the schema-v3 profile still contains Python-binary64 and integer
rounding differences described under R1.13.

### R1.11 Muzzle silence + recoil split (NEW part fields, with new part types)
`silence {sound_radius_blocks, sound_event?}` (shrinks gunshot propagation, optional sound
swap — TaCZ silencer) and `recoil_pitch_mult`/`recoil_yaw_mult` (Arma suppressor bundles
Expand Down
Loading
Loading