Skip to content

W5b-1: immutable schema (C7) + no compat re-exports (C13) - #41

Merged
bnsd55 merged 2 commits into
mainfrom
w5b-immutable
Sep 18, 2026
Merged

bnsd55 merged 2 commits into
mainfrom
w5b-immutable

Conversation

@bnsd55

@bnsd55 bnsd55 commented Sep 18, 2026

Copy link
Copy Markdown
Owner

Implements GPT-REVIEW-2 section C items 7 and 13 on w5b-immutable, rebased on origin/main 649ba70 (post-#37/#38/#39 merges).

C7 — StructuredSchema / FieldDefinition immutable after construction

  • FieldDefinition is a frozen slots dataclass: every attribute set exactly once at construction; mutation raises FrozenInstanceError (dataclasses.FrozenInstanceError via the slots descriptors).
  • Deep-frozen at the boundary: choices is a tuple (copied from the caller's list), choice_descriptions a MappingProxyType over a copy, set_constraints a tuple of MappingProxyType constraint views — validated copies, nothing caller-mutable reachable.
  • compile_set_constraints(constraints) validates exactly as before (same SchemaCompileError set: unknown types, non-multi fields, implies cycles, cross-group contradictions, exact_k=0 exclusions) and returns a NEW frozen field (validated deep-frozen constraints); StructuredSchema.__init__ swaps it into the dict. compile_set_constraints(None) returns the same field. compile_set_constraints itself is otherwise untouched for coder3's W5-C.
  • StructuredSchema.fields is exposed as a read-only mapping (insert/delete/clear/pop raise TypeError/AttributeError); __getitem__/__len__ unchanged.
  • Compiled plans (compile_slot_plan/compile_labels_plan and their cache) are deep-frozen once at compile time (_freeze_plan: dicts→MappingProxyType, lists→tuples). Cache identity is preserved — the cached object IS the frozen one, so cache-hit tests still assert is. Consumers see identical content; the engine's row-assembly concatenations now wrap plan reads in list(...) (4 sites).
  • plan_hash now thaws the frozen plan (mappingproxy→dict) before hashing: the stdlib default=list path silently collapsed mappingproxies to their key lists, which hashed slots and labels plans identically — the existing mode-sensitivity test caught this.
  • to_dict() unchanged in shape (returns plain copies).

C13 — api.py: zero backward-compatibility re-exports

  • Deleted the compat re-export block and __all__ entries for resolve_model/MODEL_ALIASES (jevmlx.models is the import home; ARCHITECTURE rule "no backward compatibility" stays). api.__all__ now lists exactly the API's own surface (decide, decide_many, schema_from_model, Decision, FieldResult, NONE_OF_ABOVE, NONE_OF_ABOVE_DESCRIPTION, DEFAULT_MODEL).
  • Dropped api.py's unused MODEL_ALIASES/resolve_model imports; updated the one stale docstring pointer (jevmlx.api.resolve_modeljevmlx.models.resolve_model in engine.py). No callers referenced the deleted re-exports (verified repo-wide).

Tests

  • New tests/test_w5b1_immutable.py (12 tests): attribute/choices/descriptions/fields mutation raises; caller dicts not shared; set-constraints frozen + caller copies; compile returns new frozen field / same field on None; plans read-only incl. count sub-plan; cache identity on frozen plans; C13 __all__ contract.
  • Updated existing plan-shape assertions to the frozen (tuple) contract (test_trie.py, test_multi.py, test_w2e_rowcodes.py, test_w2c_codebook.py, test_w5a.py, test_api.py, test_w2_setcons.py).
  • 596 passed (not-slow), ruff check + format clean. Slow suite: the one failure (parity_real_model_twin, 0.071 vs 0.05s perf bound) reproduces on clean origin/main — pre-existing, not from this branch.

Coordination

  • compile_set_constraints touched only to freeze its output (per the W5-C/coder3 note); its validation logic is byte-identical.
  • Rebased on origin/main 649ba70 after W5-D's engine changes; the single conflict was my docstring pointer against the rewritten _load_engine_resolved docstring — resolved by keeping W5-D's text and re-adding the pointer.

set_constraints becomes a real __init__ parameter (default ()) so the
frozen-dataclass clone is the idiomatic replace(self,
set_constraints=frozen_tuple); the __new__ + object.__setattr__ copy loop
is gone.
@bnsd55
bnsd55 merged commit 1fd4bef into main Sep 18, 2026
2 checks passed
@bnsd55
bnsd55 deleted the w5b-immutable branch September 18, 2026 21:37
bnsd55 added a commit that referenced this pull request Sep 19, 2026
…metry in W5-D tests, CalibrationBundle in openai path

- _prior_cache_key no longer puts weakref.ref objects in the key tuple:
  hash(ref) delegates to the referent and mlx models are unhashable, so
  every prior-corrected run crashed with TypeError. Key by ids (refs stay
  alongside the value for the live check). Pre-existing on merged main
  649ba70 — reproduced on a clean checkout.
- openai_slots._decide_multi_field consumes the typed CalibrationBundle
- test_w5d count-row test reads internal_telemetry (finding 24)
- rebased onto 2500cf5 (PRs 37, 41, 42-44): compile_set_constraints keeps
  the frozen dataclasses.replace contract; satisfiability check = solver
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