nx_id_param_core.nx
buildroot/runtime/nx_id_param_core.nx
about
nx_id_param_core.nx -- THE PURE IDENTITY-PARAMETER CORE. /compare/procgen C36, symbol
id_param_core. Extracted 2026-08-28 on the pattern nx_worldpipe_core proved for TERRAIN the same
week: a pure, allocation-free arithmetic core that both the NAS-side generate/judge loop and the
shipping engine import, so the two can never disagree about who a character is. Terrain got this
treatment first; a body is the same problem with a different field.
THE DEFECT IT CLOSES, MEASURED RATHER THAN ASSUMED. nx_breeding's gn_wild draws every trait as
g[t] = lo(t) + gn_hash3(seed, t, 1) % span
-- twelve INDEPENDENT uniform draws with ZERO covariance, of which exactly ONE (GN_T_HUE) is a
colour. Downstream, nx_skin_ita maps that single scalar onto a straight L* locus at FIXED a* and
FIXED b*, so the entire cast varies along ONE LINE in a perceptually uniform space. That is the
mechanical content of the operator's "our colour palette is barely used": not a palette that is
under-used, but an identity space that is one-dimensional and uncorrelated. A cast drawn that way
cannot read as deliberate, because nothing about any character relates to anything else about it.
WHAT IS ALREADY RIGHT, SAID PLAINLY SO THIS CORE IS NOT CREDITED WITH IT: gn_hash3(seed, t, ...)
is ALREADY a split stream keyed on the trait id, so adding trait 12 cannot reshuffle traits 0..11
and every character is already bit-identically reproducible from its seed. That property is
INHERITED here, not invented here. What is new is CORRELATION.
THE MODEL: ONE FACTOR, STATED RATHER THAN FITTED. An axis is
x = (m*load + r*sqrt(UNIT^2 - load^2)) / UNIT
with m the shared master variate, r the axis's own independent residual, and load in 0..UNIT.
This is the standard one-factor construction, and it has two properties a hand-rolled blend does
not: corr(x, m) is load/UNIT BY CONSTRUCTION, and the marginal spread of x is the SAME whatever
the load -- so tightening a family resemblance never quietly costs variety. Both are gate teeth,
measured with a real estimator rather than asserted.
WHY A FACTOR MODEL AND NOT A COVARIANCE MATRIX. A full matrix needs entries fitted to a
population we have not measured -- numbers with no source, which is the defect rule 11 exists to
stop. A factor model needs ONE loading per axis and states what it means: how much of this axis
is the shared cause. For pigmentation that shared cause is not a statistical convenience, it is
physical -- skin, hair and iris colour are all produced by the same melanin chromophore -- so a
single latent factor is the honest structure and the loadings are the only free parameters.
SETTING load TO ZERO REPRODUCES THE INCUMBENT EXACTLY: an independent uniform draw per axis.
The gate uses that as its control, so the defect and the fix are measured on ONE ruler.
LIB, no main (ecosystem convention). license_tier: ORIGINAL No hw writes (Rule 26).
dependencies 2 imports · 2 importers
imports: nx_syscalls.nxnx_breeding.nx
imported by: nx_id_palette.nxnx_id_param_gate.nx
structs
| none |
consts
| 43 | const IDP_UNIT: i64 = 1000 |
| 44 | const IDP_V: i64 = 1 |
| 48 | const IDP_SALT_MASTER: i64 = 7001 |
| 49 | const IDP_SALT_RESID: i64 = 7002 |
| 52 | const IDP_CORR_UNDEF: i64 = 0 - 100000 |
| 90 | const IDP_AVAL_MUL: i64 = 1274126177 |
| 91 | const IDP_AVAL_1: i64 = 13 |
| 92 | const IDP_AVAL_2: i64 = 16 |
| 93 | const IDP_AVAL_MASK: i64 = 4611686018427387903 |
functions
| 57 | func id_param_core() -> i64 { return IDP_V } called by 1: main |
| 61 | func idp_isqrt(v: i64) -> i64 |
| 94 | func idp_avalanche(h0: i64) -> i64 called by 1: idp_stream |
| 105 | func idp_stream_raw(seed: i64, axis: i64, salt: i64) -> i64 { return gn_hash3(seed, axis, salt) } |
| 106 | func idp_unit_raw(seed: i64, axis: i64, salt: i64) -> i64 { return idp_stream_raw(seed, axis, salt) % (IDP_UNIT + 1) } |
| 107 | func idp_centered_raw(seed: i64, axis: i64, salt: i64) -> i64 { return 2 * idp_unit_raw(seed, axis, salt) - IDP_UNIT } |
| 110 | func idp_stream(seed: i64, axis: i64, salt: i64) -> i64 { return idp_avalanche(gn_hash3(seed, axis, salt)) } |
| 113 | func idp_unit(seed: i64, axis: i64, salt: i64) -> i64 |
| 117 | func idp_centered(seed: i64, axis: i64, salt: i64) -> i64 |
| 123 | func idp_master(seed: i64, factor: i64) -> i64 |
| 142 | func idp_fan(master: i64, load: i64, seed: i64, axis: i64) -> i64 |
| 155 | func idp_to_span(c: i64, span: i64) -> i64 |
| 164 | func idp_corr_permil(xs: *i64, ys: *i64, n: i64) -> i64 |
| 190 | func idp_spread(xs: *i64, n: i64) -> i64 |