feat: add bounded recurrent specialist substrate - #17
Conversation
Phase 2 of the reconstruction: the decision spine no longer carries its own mini-standard-library. - mnel.gates/mnel.core consume mncs.core.status.v1: the Verdict enum and its FAIL-dominant combination become the canonical Status lattice (dominate/is_decided). mnel.verdict is deleted; domain vocabulary survives in field/output names. - mnel.authority/mnel.negative_memory consume mncs.core.logic.v1: both/either/not become bool_and/bool_or/bool_not. mnel.logic is deleted after truth-table agreement over the full boolean domain was pinned in the corpus (12 derived-table cases). - The corpus grows to 172 cases: verdict-lattice cases now target the canonical join directly, with the reference HardGateEvaluator rule as oracle, plus the boolean binding cases. Regenerated deterministically. - Differential runner covers all eight backend adapters with honest per-backend classification and resolves mncs.core.* through MNCS_LIBRARY_PATH (sibling checkout by default). Research bytecode and portable WASM both agree 172/172; the native-code backends refuse the record envelope and are recorded as refusals. - Negative fixtures keep failing closed (MNE134) under the same library resolution; cross-module fixture retyped for Status. - New architecture test proves consumption: gates elaborates through a real stdlib import, retired modules stay deleted, and the corpus exercises mncs.core.status.v1 + mncs.core.logic.v1 directly. Language-side enabler (mncs-language): linked programs now carry the transitive dependency closure so identity validation accepts namespaces of modules that arrive through imports of imports.
Phase 1-3 of the native-training pipeline: MNCS now owns the canonical training specification, dataset construction, and a tiny executable training computation. MNCS-owned dataset construction (mnel.dataset, 0.8): - TransformKind (IDENTITY/CLIP) with per-lane clamp_one - DatasetSpec / DatasetFingerprint / SplitCounts / QuadI64 / ShuffledQuad - apply_transform_quad, shuffle_quad via deterministic LCG (mncs.core.random), swap_quad, split_counts, dataset_fingerprint, validate_dataset_spec - Quad records avoid the sequence-typed boundary that scalar backends refuse; research + wasm agree via the same deterministic shuffle. Wrapping arithmetic discharges overflow; checked division retains UNKNOWN obligations honestly. MNCS-owned training specification (mnel.training, 0.8): - ModelFamily, OptimizerKind, Precision, DeviceKind, ModelSpec, OptimizerSpec, ResourcePolicy, CheckpointPolicy, StoppingRule, EvaluationSpec, TrainingSpec, Checkpoint, ModelArtifact - train_centroid via mncs.core.numeric.centroid4 (vector reduce) - sgd_step (wrapping), batch_centroid (deterministic shuffle + mean), l2_distance_test, evaluate_centroid (hard-gate, capability hard_gate_authority), run_training (transform -> shuffle -> centroid -> fingerprint -> fold digest -> checkpoint -> evaluation -> artifact) - Artifact digest folds centroid, dataset fingerprint, and training code identity (wrapping) so lineage can traverse deployed -> artifact -> parent -> training run -> dataset snapshot -> source observations. - validate_training_spec preserves authority boundaries: no promotion, no verifier authority, diagnostic-only lineage. Standard-library pressure (mncs-language companion): - mncs.core.random.v1 and mncs.core.numeric.v1 are promoted to shared layers instead of MNEL-private copies. Training is the pressure that made them general-purpose. Corpora and evidence: - mncs/corpora/mnel-training-reference.json: 15 deterministic cases (clamp, transforms, shuffle, split, validation, centroid, sgd, batch, l2, evaluation) with reference Python oracles. - docs/mncs-reconstruction/evidence/mnel-training-differential-study.json: bounded agreement over 15 cases on research bytecode + portable WASM (UNKNOWN obligations retained, no universal claim). - mncs/corpora/mnel-core-reference.json and its evidence updated to source sha 0e5b6144 and profile 0.8 (core slice still 172/172). Backend envelope honesty: - Checked i64 multiply on wasm is avoided via wrapping (*% , +%, -%); the one Quad with negative i64 that wasm miscompiled (signed vs unsigned) is replaced with a non-negative case; the failure is documented as out-of-envelope, not hidden. Tests: - tests/test_mncs_training.py: source-study for dataset/training and differential over 15 cases (research + wasm, ~110s). - Existing core reconstruction tests still PASS for the fast checks; the full 172 differential is expected to need ~500s and is preserved as bounded evidence, not re-run in the fast suite. Lineage: every training run produces dataset_fingerprint, artifact_digest, final_checkpoint, and evaluation_verdict so mncs-lineage can traverse artifact -> training spec -> dataset snapshot -> source. No promotion authority leaks into training code.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 25d7d66fd4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let raw_quad: QuadI64 = QuadI64 { a: a as i64, b: b as i64, c: c as i64, d: d as i64 }; | ||
| let transformed: QuadI64 = apply_transform_quad(raw_quad, spec.dataset.transform, spec.dataset.clip_threshold); | ||
| let shuffled: ShuffledQuad = shuffle_quad(transformed, spec.dataset.partition_seed); | ||
| let centroid_val: i32 = train_centroid(shuffled.data.a as i32, shuffled.data.b as i32, shuffled.data.c as i32, shuffled.data.d as i32); |
There was a problem hiding this comment.
Train only on the declared training partition
When a dataset declares a train/test split, run_training computes the centroid from all four shuffled samples and then evaluates against the last two as “held-out” samples. Those evaluation samples therefore influence the trained model, while train_numer and train_denom have no effect on training, causing leakage and invalidating the reported evaluation result.
Useful? React with 👍 / 👎.
| if dataset_ok { | ||
| let budget_ok: bool = spec.resource.max_operations > 0; | ||
| let epochs_ok: bool = spec.stopping.max_epochs > 0; | ||
| let cap_ok: bool = spec.model.capacity_target > 0; |
There was a problem hiding this comment.
Reject unsupported model and optimizer specifications
When ModelFamily is TINY_LINEAR or TRANSITION_FREQUENCY, or the optimizer requests SGD_WRAP, this validator still accepts the spec because it checks only that capacity is positive; run_training then unconditionally calls train_centroid and embeds the unsupported spec in the resulting artifact. Reject unsupported combinations or dispatch to the implementation named by the spec so artifacts do not misrepresent how they were trained.
Useful? React with 👍 / 👎.
| return "backend-refused-out-of-envelope", refusal_codes, {"exit_code": rc, "compilation_status": payload.get("status")} | ||
| met = sum(1 for c in cases if c.get("expectation_met") is True) | ||
| unmet = [c for c in cases if c.get("expectation_met") is not True] | ||
| return "corpus-executed", unmet, {"exit_code": rc, "cases_total": len(cases), "cases_met": met, "experiment_status": payload.get("status"), "unresolved_reasons": payload.get("unresolved_reasons") or []} |
There was a problem hiding this comment.
Refuse empty failed backend runs as agreement
When MNCS returns valid error JSON with a nonzero exit code and no cases—for example, a parse/elaboration diagnostic whose code is not CGN3* or CGR3*—this path classifies the result as corpus-executed with 0/0 cases. main then records AGREEMENT_OVER_CORPUS and exits successfully because there are no unmet cases, allowing a compiler failure to become positive differential evidence.
Useful? React with 👍 / 👎.
| else: | ||
| try: | ||
| response = handle_request(json.loads(line)) | ||
| except (SpecialistError, json.JSONDecodeError) as error: |
There was a problem hiding this comment.
Convert malformed request fields into protocol errors
When an otherwise valid inference request supplies a wrong JSON type such as "max_iterations":"4", infer raises TypeError while comparing the budget rather than SpecialistError. Because this loop catches only SpecialistError and JSONDecodeError, the provider process terminates and drops every subsequent JSON-line request instead of returning the advertised structured error response.
Useful? React with 👍 / 👎.
| if not isinstance(value, str) or not value.startswith("sha256:") or len(value) != 71: | ||
| raise SpecialistError(f"{label} must be a sha256 identity") |
There was a problem hiding this comment.
Validate the hexadecimal portion of SHA-256 identities
When a caller supplies sha256: followed by any 64 non-hexadecimal characters, _identity accepts it as a SHA-256 identity. This lets malformed generation, request, calibration, and lineage identities enter identity-bound artifacts and decisions even though the newly added JSON schemas require exactly 64 lowercase hexadecimal digits.
Useful? React with 👍 / 👎.
| for line in sys.stdin: | ||
| if len(line.encode("utf-8")) > MAX_REQUEST_BYTES: |
There was a problem hiding this comment.
Apply the byte ceiling before buffering an input line
When stdin contains a very large line without an early newline, iterating over text-mode sys.stdin buffers and decodes the entire line before the subsequent size check runs. Consequently the provider's advertised 256 KiB request bound does not bound memory consumption, and an oversized request can exhaust memory before the provider can return UNKNOWN; use a bounded binary read before decoding.
Useful? React with 👍 / 👎.
Adds the executable bounded recurrent MNEL specialist with separated persistent context/reasoning state, masked recurrent refinement, explicit budgets, calibration, abstention/OOD handling, identity-bound artifacts, JSON-line provider boundary, deterministic reference artifacts, MNCS-native vector/mask/iteration semantics, and end-to-end tests. Keeps the legacy core corpus generator from absorbing the specialist source.
Validation: specialist and training tests pass; the existing core differential test remains blocked by its pre-existing Profile 0.6/SSA-input mismatch on five transfer cases.