feat: add MNCS-native dataset and training slice with lineage - #16
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: 6c17afe575
ℹ️ 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".
| observation: ObservationFacts, | ||
| limits: BudgetLimits, |
There was a problem hiding this comment.
Update the corpus for the expanded experiment signature
The function now requires ObservationFacts and BudgetLimits, and its result also gained disposition, but generate_mncs_core_corpus.py still supplies only [facts, *gates, transfer, maturity] and encodes the old three-field ExperimentOutcome. Consequently, the five end-to-end experiment cases have the wrong arity and expected record identity, so the core differential test cannot reproduce the checked 172/172 agreement against this source.
Useful? React with 👍 / 👎.
| 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.
Keep held-out samples out of centroid training
For every run_training invocation, the centroid is computed from all four shuffled lanes, while lanes c and d are subsequently evaluated as held-out tests. Those test values therefore directly influence the fitted centroid, causing evaluation leakage and potentially producing an optimistic gate verdict; derive the centroid only from the train partition selected by DatasetSpec before evaluating the remaining lanes.
Useful? React with 👍 / 👎.
| let base: u64 = (centroid_val as u64) +% print.source; | ||
| let mixed: u64 = (base *% 31) +% spec.optimizer.seed; | ||
| let digest: u64 = (mixed *% 31) +% spec.training_code_identity; |
There was a problem hiding this comment.
Include dataset identity fields in the artifact digest
The purported content-addressed digest includes only the centroid, source identity, optimizer seed, and training-code identity, omitting the transform, threshold, partition seed, split ratio, model, and other artifact content. For example, changing only spec.dataset.partition_seed yields a different fingerprint/spec but the same centroid because training averages all four permuted values, and therefore the same digest; consumers using this field as the artifact identity can conflate distinct training runs and corrupt lineage.
Useful? React with 👍 / 👎.
| # --- clamp_one --------------------------------------------------------- | ||
| for val, bound, expected in [(5, 10, 5), (15, 10, 10), (-15, 10, -10), (0, 5, 0)]: |
There was a problem hiding this comment.
Regenerate the checked training corpus from its generator
The checked mnel-training-reference.json contains 15 cases, but running this committed generator deterministically emits 47 cases and changes the file. Since the differential runner reads the checked corpus directly, 32 cases defined here—including additional transform, split-boundary, validation, batching, and evaluation cases—are absent from the recorded study, and the committed corpus/evidence cannot be reproduced from their declared generator.
Useful? React with 👍 / 👎.
| "module": "mnel.core", | ||
| "language_profile": "0.5", | ||
| "module": "mnel.all", | ||
| "language_profile": "0.6", |
There was a problem hiding this comment.
Report the actual aggregate language profile
Whenever this runner regenerates the core evidence, it records profile 0.6, even though its executed source is mnel/all.mncs, which now declares mncs 0.8. This makes newly generated provenance disagree with both the program actually executed and the checked evidence record, undermining reproducibility of the differential study.
Useful? React with 👍 / 👎.
Implements the first executable vertical slice of the MNCS-native training pipeline (Phase 1-3):
Dataset (mnel.dataset, 0.8):
Training (mnel.training, 0.8):
Stdlib pressure (companion mncs-language PR #81):
Corpora & evidence:
Validation:
Authority preserved: no promotion, no evaluator authority, diagnostic-only lineage.