-
Notifications
You must be signed in to change notification settings - Fork 1
fix(cat): seal administration evidence before NumPy protocols #1345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
0706103
test(cat): reject callback-bearing administration evidence
seonghobae 8a564d0
fix(cat): seal administration evidence before NumPy protocols
seonghobae 454ffaa
test(cat): preserve trusted administration compatibility
seonghobae 995784e
docs(cat): record administration evidence boundary
seonghobae 4308892
test(cat): reject impossible administrations before dense conversion
seonghobae f4ee035
fix(cat): preflight administration shape and length
seonghobae d1cac77
fix(cat): install administration resource preflight
seonghobae 4ede92e
chore(cat): keep resource preflight lint-clean
seonghobae 027c2cf
docs(cat): record bounded administration preflight
seonghobae a61ce4a
test(cat): bound standard-error administration before value scan
seonghobae cb1736b
fix(cat): bound standard-error administration before value scan
seonghobae 145c0be
fix(cat): bind standard-error resource guard on public alias
seonghobae 160cd49
docs(cat): record standard-error administration preflight
seonghobae a099969
test(cat): preserve standard-error deduplication semantics
seonghobae 38e3f20
fix(cat): preserve standard-error deduplication semantics
seonghobae c8b613c
docs(cat): record standard-error mask compatibility
seonghobae 90b7151
test(cat): bound standard-error mask preflight
seonghobae f7d4b86
fix(cat): bound standard-error mask evidence
seonghobae 7bd842b
docs(cat): record standard-error mask bound
seonghobae 1167074
Merge protected main into CAT evidence hardening
seonghobae b6e27da
test(cat): reject over-bank before response provider
seonghobae 8385299
fix(cat): bound administration before response carrier
seonghobae ebcf17f
docs(cat): record response-independent administration bound
seonghobae 2bc7ba2
merge: current main into cat-administration evidence lane
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # Seal dichotomous CAT administration evidence | ||
|
|
||
| ## Fixed | ||
|
|
||
| - Reject callback-bearing top-level array providers, ndarray/container subclasses, and non-real storage for partial CAT administered-item and response evidence before NumPy materialization or Rust ability-estimation dispatch. | ||
| - Preserve exact NumPy and ordinary built-in list/tuple numeric evidence, including concrete NumPy scalar compatibility, while retaining lossless signed-64 item-index validation, item range/uniqueness rules, and the exact 0/1 response contract. | ||
| - Reject over-rank, length-mismatched, and structurally impossible partial administrations from inert container metadata before value-wise scans or dense `int64`/`float64` marshalling; a validated EAP/MLE administration cannot exceed the calibrated bank item count because administered identities must be unique. | ||
| - Apply the over-bank EAP/MLE administration bound before inspecting the response carrier, so an unsupported response provider cannot force dense validation of an already impossible administration. | ||
| - Preserve `ability_standard_error`'s historical set-valued mask semantics: duplicate-laden and multidimensional administered evidence is normalized losslessly and deduplicated with `np.unique`, so the uniqueness-specific raw-length/rank preflight is not applied to that surface. | ||
| - Bound `ability_standard_error` administered-mask evidence to 20,000,000 logical cells from inert exact-container metadata before signed-64 value scanning, dense conversion, or `np.unique`, without imposing EAP/MLE uniqueness or rank semantics on the set-valued mask. | ||
| - Keep CAT probability, likelihood, EAP/MLE posterior/scoring, Fisher-information selection, stopping, and uncertainty arithmetic Rust-owned; this change is Python validation, bounded materialization, and marshalling only. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
python/fast_mlsirm/_cat_administration_resource_safety.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| """Resource preflight for dichotomous CAT administration evidence. | ||
|
|
||
| The CAT numerical owner remains Rust. This module rejects structurally | ||
| impossible EAP/MLE administrations and oversized standard-error mask evidence | ||
| from inert container metadata before existing CAT validators perform value-wise | ||
| scans or dense dtype marshalling. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from types import ModuleType | ||
| from typing import Any | ||
|
|
||
| import numpy as np | ||
|
|
||
| _SHAPE_ERROR = "administered and responses must be 1D arrays of equal length" | ||
| _LENGTH_ERROR = "administration length cannot exceed item bank size" | ||
| _STANDARD_ERROR_RESOURCE_ERROR = ( | ||
| "ability_standard_error administered evidence exceeds resource limit" | ||
| ) | ||
| _MAX_STANDARD_ERROR_ADMINISTERED_CELLS = 20_000_000 | ||
| _VALIDATE_MARKER = "__fast_mlsirm_cat_administration_resource_safe__" | ||
| _STANDARD_ERROR_MARKER = "__fast_mlsirm_cat_standard_error_resource_safe__" | ||
|
|
||
|
|
||
| def _vector_length(value: object) -> int | None: | ||
| """Return inert one-dimensional length, or ``None`` for unsupported carriers.""" | ||
| if type(value) is np.ndarray: | ||
| if value.ndim != 1: | ||
| raise ValueError(_SHAPE_ERROR) | ||
| return int(value.shape[0]) | ||
| if type(value) in (list, tuple): | ||
| return len(value) | ||
| return None | ||
|
|
||
|
|
||
| def _standard_error_logical_cells(value: object) -> int | None: | ||
| """Return inert mask size without imposing EAP/MLE rank or uniqueness rules.""" | ||
| if type(value) is np.ndarray: | ||
| return int(value.size) | ||
| if type(value) in (list, tuple): | ||
| return len(value) | ||
| return None | ||
|
|
||
|
|
||
| def _reject_over_bank_administration(bank: Any, administered: object) -> None: | ||
| """Reject exact-carrier administrations that cannot be unique in the bank.""" | ||
| administered_length = _vector_length(administered) | ||
| if administered_length is None: | ||
| return | ||
| n_items = int(np.asarray(bank.b).shape[0]) | ||
| if administered_length > n_items: | ||
| raise ValueError(_LENGTH_ERROR) | ||
|
|
||
|
|
||
| def install(cat_module: ModuleType) -> None: | ||
| """Install fail-fast CAT resource preflights idempotently.""" | ||
| original_validate = cat_module._validate_administration | ||
| if not bool(getattr(original_validate, _VALIDATE_MARKER, False)): | ||
|
|
||
| def safe_validate_administration( | ||
| bank: Any, | ||
| factor_id: np.ndarray, | ||
| administered: object, | ||
| responses: object, | ||
| ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: | ||
| # Unsupported administered providers retain the original callback/type | ||
| # rejection contract. Once administered exposes inert exact-container | ||
| # metadata, reject structurally impossible unique administrations before | ||
| # inspecting the response carrier so an invalid/unsupported response | ||
| # cannot force an oversized administered vector through dense validation. | ||
| administered_length = _vector_length(administered) | ||
| if administered_length is None: | ||
| return original_validate(bank, factor_id, administered, responses) | ||
|
|
||
| _reject_over_bank_administration(bank, administered) | ||
|
|
||
| responses_length = _vector_length(responses) | ||
| if responses_length is None: | ||
| return original_validate(bank, factor_id, administered, responses) | ||
|
|
||
| if administered_length != responses_length: | ||
| raise ValueError(_SHAPE_ERROR) | ||
|
|
||
| return original_validate(bank, factor_id, administered, responses) | ||
|
|
||
| setattr(safe_validate_administration, _VALIDATE_MARKER, True) | ||
| cat_module._validate_administration = safe_validate_administration | ||
|
|
||
| original_standard_error = cat_module.ability_standard_error | ||
| if not bool(getattr(original_standard_error, _STANDARD_ERROR_MARKER, False)): | ||
|
|
||
| def safe_ability_standard_error( | ||
| bank: Any, | ||
| factor_id: np.ndarray, | ||
| theta: np.ndarray, | ||
| *, | ||
| administered: object | None = None, | ||
| model: str = "MLS2PLM", | ||
| ) -> np.ndarray: | ||
| # Standard-error administration is a set-valued mask rather than the | ||
| # unique 1-D EAP/MLE history. Preserve duplicate and multidimensional | ||
| # exact NumPy evidence, but bound its logical size before signed-int64 | ||
| # value scans, dense conversion, and np.unique deduplication. | ||
| if administered is not None: | ||
| logical_cells = _standard_error_logical_cells(administered) | ||
| if ( | ||
| logical_cells is not None | ||
| and logical_cells > _MAX_STANDARD_ERROR_ADMINISTERED_CELLS | ||
| ): | ||
| raise ValueError(_STANDARD_ERROR_RESOURCE_ERROR) | ||
| return original_standard_error( | ||
| bank, | ||
| factor_id, | ||
| theta, | ||
| administered=administered, | ||
| model=model, | ||
| ) | ||
|
|
||
| setattr(safe_ability_standard_error, _STANDARD_ERROR_MARKER, True) | ||
| cat_module.ability_standard_error = safe_ability_standard_error | ||
|
seonghobae marked this conversation as resolved.
|
||
|
seonghobae marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.