Skip to content

feat: add bounded recurrent specialist substrate - #17

Merged
epi13 merged 8 commits into
mainfrom
feat/mncs-native-training-slice
Aug 27, 2026
Merged

feat: add bounded recurrent specialist substrate#17
epi13 merged 8 commits into
mainfrom
feat/mncs-native-training-slice

Conversation

@epi13

@epi13 epi13 commented Aug 27, 2026

Copy link
Copy Markdown
Owner

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.

epi13 added 5 commits August 26, 2026 04:52
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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 []}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +39 to +40
if not isinstance(value, str) or not value.startswith("sha256:") or len(value) != 71:
raise SpecialistError(f"{label} must be a sha256 identity")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +95 to +96
for line in sys.stdin:
if len(line.encode("utf-8")) > MAX_REQUEST_BYTES:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@epi13
epi13 merged commit d1ad46c into main Aug 27, 2026
8 checks passed
@epi13
epi13 deleted the feat/mncs-native-training-slice branch August 27, 2026 23:44
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