Skip to content

feat(core): pure loadUwrProfile validator (PR-UWR-RUNTIME-LOADER) - #18

Merged
Gio2050 merged 1 commit into
mainfrom
feat/uwr-runtime-loader
Jul 13, 2026
Merged

feat(core): pure loadUwrProfile validator (PR-UWR-RUNTIME-LOADER)#18
Gio2050 merged 1 commit into
mainfrom
feat/uwr-runtime-loader

Conversation

@Gio2050

@Gio2050 Gio2050 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Slot and authorization

This PR executes PR-UWR-RUNTIME-LOADER — the afi-core row of the §7 authorization ledger in afi-governance decisions/uwr-runtime-consumption-v0.1.md.

Go-ahead (RC-10.5): the row was flipped to "Yes — row flip merged by owner per RC-12 (recorded 2026-07-13)" by owner merge of afi-governance PR #11 (merge commit fbd0c46).

What this adds

validators/UwrProfileLoader.ts — a pure loadUwrProfile(profileJson: unknown): Readonly<UniversalWeightingRuleConfig> validator/mapper. No fs, no path resolution, no afi-config dependency: the caller supplies the already-parsed document. It enforces the RC-5 identity predicate exactly:

  1. four weights strictly equal defaultUwrConfig's per axis (near-misses refused, incl. 1-ULP drift);
  2. axes array equals ["structure", "execution", "risk", "insight"] in content and order (UP-4);
  3. profileId equals the pinned uwr-weighted-lifts-v0.1 and supersedes equals defaultUwrConfig.id (uwr-default-stub);
  4. ids are never compared for direct equality — supersession, not equality, is the pinned relation.

Refusals throw UwrProfileLoadError with a machine-checkable reason (the RC-4 fail-closed triggers for the future PR-UWR-RUNTIME-READ). Fail-closed hardening: all document fields are read once, as own properties only (inherited/prototype-supplied values and accessor-backed documents cannot satisfy the predicate or alter values post-validation), and the returned frozen config spreads defaultUwrConfig itself with the registered profile id — identity by construction: registry-supplied numbers can never flow into the result. The returned id records which governed profile the values were validated against; it does not signal registry consumption (RC-6/RC-8 semantics unchanged).

validators/__tests__/UwrProfileLoader.test.ts — 20 vitest tests: happy path, frozen/no-mutation, RC-5 identity with defaultUwrConfig, bit-identical computeUwrScore under loaded vs default config (incl. the UP-5 golden anchor 0.1875), full refusal matrix (shape, schema, profileId incl. alias-as-id and stub-id, supersedes, axes reorder/drop/extend/rename, weights shape/near-miss/NaN), hostile-input hardening (single-read accessors, prototype-chain inputs), and a dev-only sibling-registry integration test (it.skipIf, same pattern as the KAT suites) proving the live afi-config registry document loads.

validators/UniversalWeightingRule.ts — the RC-8-sanctioned TODO comment update only (+5/-1 comment lines; defaultUwrConfig values and computeUwrScore signature byte-untouched).

No subpath-export change was required: the existing "./validators/*" wildcard already exposes afi-core/validators/UwrProfileLoader.js (emission to dist/validators/ verified).

Validation (RC-10 gates)

  • afi-core vitest: 216 passed (216) — 196 baseline (both KAT executor suites included) + 20 new; build and typecheck green.
  • afi-config pin guards: CI-enforced on its main (ce8c1de), untouched by this PR.
  • afi-reactor: no changes (goldens trivially byte-stable); jest allowlist not applicable — the new tests are afi-core vitest, autodiscovered (CI runs npm test --if-present → vitest, which auto-selects non-watch run mode under CI; the build check passed on this head).
  • Adversarial scope check: diff touches exactly the three files above; no KAT vectors, schemas, registry files, or sibling repos.

Review

An 8-angle adversarial review ran before opening. Fixed: single-read/own-property hardening (TOCTOU + prototype-chain false-accepts), identity-by-construction return, WEIGHT_KEYS derived from the pinned axes and compile-checked against UniversalWeightingRuleConfig, merged validation loops (casts eliminated), test dedup. Declined with rationale: zod rewrite (predicate deliberately reads literally as RC-5 for auditability; reason codes are the contract), fixture trimming (the inline mirror is CI's only realistic-document coverage since the sibling test skips there), and two findings whose fixes exceed this slot's authorization — noted below.

Notes for the owner (out of this slot's scope, no action taken)

  • Provenance note: the RC-8 TODO edit is the first change to validators/UniversalWeightingRule.ts since 390b440, so the blob-identity wording in validators/__tests__/kats/README.md and the KAT test header ("blob-identical between 390b440 and 2541853") stays true as a claim about those pinned commits but no longer extends to HEAD. Comment-only divergence; the executable sha256 pin covers the KAT JSON and is untouched. Suggest folding a two-line dated addendum into PR-UWR-KAT-RERUN.
  • Cross-repo pin duplication: afi-reactor's UWR_PROFILE_ID and this loader's PINNED_UWR_PROFILE_ID both hardcode the profile id with no test asserting their equality (the reactor guardrail cross-checks against the sibling registry, which transitively ties them). A reactor-side import or guardrail extension belongs to PR-UWR-RUNTIME-READ / STAMP-SEMANTICS.

Scope guarantees

No runtime registry read; no reactor changes; no scoring behavior change (loaded config is provably value-identical — golden anchor asserted); no reward/mint/settlement; defaultUwrConfig unmodified; no KAT/schema/registry values touched; UP-8 untouched; testnet-provisional throughout; no production scoring-law claim.

🤖 Generated with Claude Code

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Gio2050
Gio2050 merged commit 806db49 into main Jul 13, 2026
1 of 2 checks passed
@Gio2050
Gio2050 deleted the feat/uwr-runtime-loader branch July 13, 2026 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant