From 941730cbbe0ac6a956b87085b54ff874089e54e1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 25 Jul 2026 15:39:55 +0000 Subject: [PATCH 1/2] SLM-250: close LOT1-01 not_authorized via real activation-gate evaluator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LOT1-01's own hard activation gates require SLM-248's fidelity-contract verdict to be authorize_bounded_implementation and SLM-249's trace gate verdict to be oracle_ceiling_positive. The real committed upstream artifacts report needs_target_trace_contract and inconclusive respectively (SLM-249's own allowed_lot1_implementation field says "none: ... not authorized by this issue"). Per the issue's own text, this closes not_authorized in plan-only mode without any Kxc model/training code. Adds a small, reusable, tested LotusOpenUIModelContractV1 evaluator that reads the two upstream contracts and derives the verdict from their real published fields (not hardcoded to always fail — a synthetic both-gates-met case is tested to flip the result to authorized_wiring_only). Re-running the same CLI after SLM-249 gets a real oracle-ceiling campaign will honestly reflect the new disposition. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KShriKrGosZr67yVPFgi78 --- ...lm250-lot1-01-not-authorized-20260725.json | 37 +++ ...-slm250-lot1-01-not-authorized-20260725.md | 93 +++++++ scripts/evaluate_lot1_01_activation_gate.py | 64 +++++ .../experiments/lot1_01_activation_gate.py | 241 ++++++++++++++++++ src/slm_training/resources/versions.json | 50 +++- .../test_lot1_01_activation_gate.py | 138 ++++++++++ .../test_evaluate_lot1_01_activation_gate.py | 36 +++ 7 files changed, 646 insertions(+), 13 deletions(-) create mode 100644 docs/design/iter-slm250-lot1-01-not-authorized-20260725.json create mode 100644 docs/design/iter-slm250-lot1-01-not-authorized-20260725.md create mode 100644 scripts/evaluate_lot1_01_activation_gate.py create mode 100644 src/slm_training/harnesses/experiments/lot1_01_activation_gate.py create mode 100644 tests/test_harnesses/experiments/test_lot1_01_activation_gate.py create mode 100644 tests/test_scripts/test_evaluate_lot1_01_activation_gate.py diff --git a/docs/design/iter-slm250-lot1-01-not-authorized-20260725.json b/docs/design/iter-slm250-lot1-01-not-authorized-20260725.json new file mode 100644 index 000000000..7d47cfa81 --- /dev/null +++ b/docs/design/iter-slm250-lot1-01-not-authorized-20260725.json @@ -0,0 +1,37 @@ +{ + "contract_hash": "2fad1057fe77352daebf2b8b792d599cf62494ca023169da0570bab9e133d3f7", + "contract_id": "lotus-openui-model-contract-v1", + "gate_1_fidelity_authorization": { + "actual_verdict": "needs_target_trace_contract", + "gate_name": "fidelity_contract_authorization", + "met": false, + "rationale": "Differentiation from every existing repo mechanism (masked recursive denoiser, SemanticPlanV1 predictors/consumers, causal FTPO adapters, explicit compiler traces, valid-state tree-edit/lattice search) is clean and survives line-by-line comparison -- see non_duplication_map, all rows no_duplication. The blocker is narrower: LOTUS's explicit-to-latent curriculum (mechanism row 5) and its causal_latent_use claim class both presuppose a step-decomposable 'explicit trace' analogous to GSM8K CoT steps that this repo does not yet define for OpenUI program synthesis. Defining that target-trace contract honestly -- without assuming math-payload equivalence to GSM8K, and without silently reusing causal_trace.py's visible-token decode capture or SemanticPlanV1's plan IR as if either already were that trace -- is out of scope for this docs/spec-only issue (no corpus generation beyond bounded target-contract probes). Authorizing bounded implementation now would force either an undefined curriculum or a quietly borrowed non-LOTUS trace source; neither is honest. This is not a 'differentiation is weak' close and not a semantic-floor block -- it is a scoped prerequisite.", + "required_verdict": "authorize_bounded_implementation", + "source_contract_hash": "801ce267b64f52b88e6e80fa091084c5f1a6628de60658d2d161db82f5117af2", + "source_contract_id": "lotus-openui-fidelity-contract-v1", + "source_linear_issue": "SLM-248" + }, + "gate_2_trace_oracle_ceiling": { + "actual_verdict": "inconclusive", + "gate_name": "trace_oracle_ceiling", + "met": false, + "rationale": "The trace contract, typed step schema, deterministic extractor, and lossless visible serialization are implemented and tested against the repository's existing SemanticPlanV1/production_codec owners (no new compiler/parser/evaluator). A bounded n=16 fixture probe (not a production corpus) confirms every probe record decomposes into all six declared stages with zero truncation, giving a provisional K=6/c=479-chars budget. The oracle ceiling experiment itself -- the only evidence that could support an oracle_ceiling_positive, no_downstream_ceiling, or explicit_trace_equivalent_to_existing_plan verdict -- is specified as a matched multi-arm, multi-seed plan but deliberately not run: the LOT0-01 authorization scopes this issue to a fixture-scale plan only, with GPU training and corpus generation explicitly blocked. Declaring any positive or negative ceiling verdict without running that plan would be exactly the 'no claim that explicit trace benefit implies latent benefit' failure this issue's acceptance criteria forbid. leakage_or_ambiguity_blocked and target_support_insufficient are also not honest: no leakage was found and the bounded probe supports the stage set within its declared scope. inconclusive -- pending the oracle-ceiling campaign -- is the only accurate verdict.", + "required_verdict": "oracle_ceiling_positive", + "source_contract_hash": "6cdd695bf5b32036519f1ee2e787a44e4afbb045fc059f75a92a2d069f0ee7c5", + "source_contract_id": "compiler-reasoning-trace-v1", + "source_linear_issue": "SLM-249" + }, + "linear_issue": "SLM-250", + "schema_version": "lotus_openui_model_contract/v1", + "verdict": "not_authorized", + "verdict_rationale": "Hard activation gate(s) unmet: fidelity_contract_authorization, trace_oracle_ceiling. Gate 1 (SLM-248 fidelity authorization) reports verdict 'needs_target_trace_contract' (requires 'authorize_bounded_implementation'). Gate 2 (SLM-249 trace oracle ceiling) reports verdict 'inconclusive' (requires 'oracle_ceiling_positive'). Closing not_authorized in plan-only mode; no K x c model or training code is added by this disposition.", + "version_stamp": { + "code_commit": "79810740906c5eeae601b0379fa083f4c48f0d68", + "code_dirty": true, + "components": { + "harness.experiments": "v111" + }, + "stamp_schema": "version_stamp/v1", + "stamped_at": "2026-07-25T15:39:13.771319+00:00" + } +} diff --git a/docs/design/iter-slm250-lot1-01-not-authorized-20260725.md b/docs/design/iter-slm250-lot1-01-not-authorized-20260725.md new file mode 100644 index 000000000..58e300cf8 --- /dev/null +++ b/docs/design/iter-slm250-lot1-01-not-authorized-20260725.md @@ -0,0 +1,93 @@ +# SLM-250 LOT1-01 — not_authorized disposition + +## What + +LOT1-01 asks to implement the faithful causal K×c looped-latent model path, +gated on two hard activation gates against its own upstream contracts: + +1. SLM-248 (LOT0-01) `LotusOpenUIFidelityContractV1.authorization.verdict` + must be `authorize_bounded_implementation`. +2. SLM-249 (LOT0-02) `CompilerReasoningTraceGateV1.gate.verdict` must be + `oracle_ceiling_positive` (or another explicit authorization supplying + K/c/stage targets). + +"Otherwise close `not_authorized` in plan-only mode without production model +code." + +## Evaluated result + +Both gates were evaluated against the real, committed upstream artifacts: + +- **Gate 1** (`docs/design/lotus-openui-fidelity-contract-v1.json`): actual + verdict is `needs_target_trace_contract`, not `authorize_bounded_implementation`. + **Unmet.** +- **Gate 2** (`docs/design/compiler-reasoning-trace-v1.json`): actual verdict + is `inconclusive`, not `oracle_ceiling_positive`; the gate's own + `allowed_lot1_implementation` field explicitly says + `"none: ... not authorized by this issue"`. **Unmet.** + +Both gates unmet ⇒ **verdict: `not_authorized`**. No K×c latent-workspace +model, loop driver, curriculum hooks, or training code is added. + +## What was built instead + +Since evaluating this gate honestly *is* the LOT1-01 deliverable when the +gate is unmet, this issue adds a small, reusable, tested activation-gate +evaluator rather than a bare Linear comment: + +- `src/slm_training/harnesses/experiments/lot1_01_activation_gate.py` — + `LotusOpenUIModelContractV1` schema, `GateEvaluation`, and + `evaluate_activation_gates()`, a pure function that reads the two upstream + contract dicts and derives the verdict from their real published fields + (never hardcoded to always fail — synthetic contracts reporting both + required verdicts flip the result to `authorized_wiring_only`, tested). +- `scripts/evaluate_lot1_01_activation_gate.py` — plan-only CLI; loads the + two real committed JSON artifacts and emits the disposition. No model + import, no training, no GPU path. +- Tests proving: the real current contracts yield `not_authorized`; a + synthetic both-gates-met case yields `authorized_wiring_only`; a + mixed/missing-fields case fails closed to `not_authorized`; the contract + hash is stable and changes with the verdict. + +This evaluator is reusable: once SLM-249 is rerun with a real oracle-ceiling +campaign (or SLM-248's verdict changes), re-running the same CLI against the +updated artifacts will honestly reflect the new disposition without any +narrative rewrite. + +## Files added + +- `src/slm_training/harnesses/experiments/lot1_01_activation_gate.py` +- `scripts/evaluate_lot1_01_activation_gate.py` +- `tests/test_harnesses/experiments/test_lot1_01_activation_gate.py` +- `tests/test_scripts/test_evaluate_lot1_01_activation_gate.py` +- `docs/design/iter-slm250-lot1-01-not-authorized-20260725.md` +- `docs/design/iter-slm250-lot1-01-not-authorized-20260725.json` + +## Commands + +```bash +python -m scripts.evaluate_lot1_01_activation_gate \ + --fidelity-contract docs/design/lotus-openui-fidelity-contract-v1.json \ + --trace-gate-contract docs/design/compiler-reasoning-trace-v1.json \ + --out outputs/runs/slm250_activation_gate +``` + +## Verification + +- `pytest tests/test_harnesses/experiments/test_lot1_01_activation_gate.py tests/test_scripts/test_evaluate_lot1_01_activation_gate.py -q` → 9 passed +- `python -m scripts.verify_version_stamps --check` → ok + +## Acceptance criteria mapping + +- "close `not_authorized` in plan-only mode without production model code" — + satisfied exactly; no model/training file is touched. +- "no RSC/TwoTower path is reused as the treatment" — no model path is + touched at all. +- "no production default change" — satisfied. +- LOT1-02/LOT2/LOT3/LOT4 remain gated behind LOT1-01, unchanged. + +## Non-goals honored + +No K×c latent-workspace model code, no learned plan predictor, no causal +intervention campaign, no large training run or quality claim, no adaptive +depth/halting, no production default change. diff --git a/scripts/evaluate_lot1_01_activation_gate.py b/scripts/evaluate_lot1_01_activation_gate.py new file mode 100644 index 000000000..d7ea4c7a8 --- /dev/null +++ b/scripts/evaluate_lot1_01_activation_gate.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +"""Evaluate SLM-250 (LOT1-01)'s hard activation gates in plan-only mode. + +No model, training, or K x c workspace code is loaded or executed. This +reads the two real committed upstream contract artifacts and emits the +required ``LotusOpenUIModelContractV1`` disposition. + +Example: + python -m scripts.evaluate_lot1_01_activation_gate \ + --fidelity-contract docs/design/lotus-openui-fidelity-contract-v1.json \ + --trace-gate-contract docs/design/compiler-reasoning-trace-v1.json \ + --out outputs/runs/slm250_activation_gate +""" + +from __future__ import annotations + +import argparse +from pathlib import Path + +from slm_training.harnesses.experiments.lot1_01_activation_gate import ( + evaluate_activation_gates, + load_upstream_contract, + render_markdown, +) + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser( + description="SLM-250 LOT1-01 hard-activation-gate evaluator (plan-only, no model code)" + ) + parser.add_argument( + "--fidelity-contract", + type=Path, + default=Path("docs/design/lotus-openui-fidelity-contract-v1.json"), + help="SLM-248 LotusOpenUIFidelityContractV1 JSON artifact", + ) + parser.add_argument( + "--trace-gate-contract", + type=Path, + default=Path("docs/design/compiler-reasoning-trace-v1.json"), + help="SLM-249 CompilerReasoningTraceGateV1 JSON artifact", + ) + parser.add_argument( + "--out", + type=Path, + default=Path("outputs/runs/slm250_activation_gate"), + ) + args = parser.parse_args(argv) + + fidelity_contract = load_upstream_contract(args.fidelity_contract) + trace_gate_contract = load_upstream_contract(args.trace_gate_contract) + + contract = evaluate_activation_gates(fidelity_contract, trace_gate_contract) + + args.out.mkdir(parents=True, exist_ok=True) + contract.to_json(args.out / "lotus_openui_model_contract.json") + markdown = render_markdown(contract) + (args.out / "lotus_openui_model_contract.md").write_text(markdown, encoding="utf-8") + print(markdown) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/slm_training/harnesses/experiments/lot1_01_activation_gate.py b/src/slm_training/harnesses/experiments/lot1_01_activation_gate.py new file mode 100644 index 000000000..5599c26d1 --- /dev/null +++ b/src/slm_training/harnesses/experiments/lot1_01_activation_gate.py @@ -0,0 +1,241 @@ +"""SLM-250 LOT1-01 hard-activation-gate evaluator. + +LOT1-01 ("Implement the faithful causal K x c looped-latent model path") +declares two hard activation gates against its own upstream contracts: + +1. SLM-248 (LOT0-01) ``LotusOpenUIFidelityContractV1.authorization.verdict`` + must be ``authorize_bounded_implementation``. +2. SLM-249 (LOT0-02) ``CompilerReasoningTraceGateV1.gate.verdict`` must be + ``oracle_ceiling_positive`` (or another explicit authorization that + supplies K/c/stage targets). + +"Otherwise close ``not_authorized`` in plan-only mode without production +model code." This module evaluates those two gates against the real, +committed upstream contract artifacts (``docs/design/lotus-openui-fidelity-contract-v1.json`` +and ``docs/design/compiler-reasoning-trace-v1.json``) and emits the required +``LotusOpenUIModelContractV1`` disposition. It contains no model, training, +or K x c workspace code -- evaluating this gate honestly *is* the LOT1-01 +deliverable when the gate is unmet. +""" + +from __future__ import annotations + +import hashlib +import json +from dataclasses import asdict, dataclass, field +from pathlib import Path +from typing import Any + +from slm_training.harness_core.versioning import build_version_stamp + +__all__ = [ + "AUTHORIZED_WIRING_ONLY", + "CONTRACT_ID", + "MODEL_CONTRACT_SCHEMA_VERSION", + "NOT_AUTHORIZED", + "REQUIRED_FIDELITY_VERDICT", + "REQUIRED_TRACE_VERDICT", + "GateEvaluation", + "LotusOpenUIModelContractV1", + "evaluate_activation_gates", + "load_upstream_contract", + "render_markdown", +] + +MODEL_CONTRACT_SCHEMA_VERSION = "lotus_openui_model_contract/v1" +CONTRACT_ID = "lotus-openui-model-contract-v1" + +# The exact verdict strings LOT1-01's own hard activation gates require. +REQUIRED_FIDELITY_VERDICT = "authorize_bounded_implementation" +REQUIRED_TRACE_VERDICT = "oracle_ceiling_positive" + +NOT_AUTHORIZED = "not_authorized" +AUTHORIZED_WIRING_ONLY = "authorized_wiring_only" + + +@dataclass(frozen=True) +class GateEvaluation: + """One hard-activation-gate check against a single upstream contract.""" + + gate_name: str + source_contract_id: str + source_contract_hash: str + source_linear_issue: str + required_verdict: str + actual_verdict: str + met: bool + rationale: str + + def to_dict(self) -> dict[str, Any]: + return dict(asdict(self)) + + +@dataclass(frozen=True) +class LotusOpenUIModelContractV1: + schema_version: str = MODEL_CONTRACT_SCHEMA_VERSION + contract_id: str = CONTRACT_ID + linear_issue: str = "SLM-250" + gate_1_fidelity_authorization: GateEvaluation | None = None + gate_2_trace_oracle_ceiling: GateEvaluation | None = None + verdict: str = NOT_AUTHORIZED + verdict_rationale: str = "" + version_stamp: dict[str, Any] = field(default_factory=dict) + + def to_dict(self) -> dict[str, Any]: + data = dict(asdict(self)) + data["gate_1_fidelity_authorization"] = ( + self.gate_1_fidelity_authorization.to_dict() + if self.gate_1_fidelity_authorization is not None + else None + ) + data["gate_2_trace_oracle_ceiling"] = ( + self.gate_2_trace_oracle_ceiling.to_dict() + if self.gate_2_trace_oracle_ceiling is not None + else None + ) + data["contract_hash"] = self.contract_hash() + return data + + def to_json(self, path: Path) -> None: + path.write_text( + json.dumps(self.to_dict(), indent=2, sort_keys=True, default=str) + "\n", + encoding="utf-8", + ) + + def contract_hash(self) -> str: + payload = { + "schema_version": self.schema_version, + "contract_id": self.contract_id, + "linear_issue": self.linear_issue, + "gate_1_fidelity_authorization": ( + self.gate_1_fidelity_authorization.to_dict() + if self.gate_1_fidelity_authorization is not None + else None + ), + "gate_2_trace_oracle_ceiling": ( + self.gate_2_trace_oracle_ceiling.to_dict() + if self.gate_2_trace_oracle_ceiling is not None + else None + ), + "verdict": self.verdict, + } + return hashlib.sha256( + json.dumps(payload, sort_keys=True, default=str).encode("utf-8") + ).hexdigest() + + +def load_upstream_contract(path: Path) -> dict[str, Any]: + """Load an upstream contract JSON artifact from disk.""" + return json.loads(path.read_text(encoding="utf-8")) + + +def _evaluate_fidelity_gate(fidelity_contract: dict[str, Any]) -> GateEvaluation: + authorization = fidelity_contract.get("authorization") or {} + actual = authorization.get("verdict", "") + met = actual == REQUIRED_FIDELITY_VERDICT + return GateEvaluation( + gate_name="fidelity_contract_authorization", + source_contract_id=fidelity_contract.get("contract_id", ""), + source_contract_hash=fidelity_contract.get("contract_hash", ""), + source_linear_issue=authorization.get("linear_issue", "SLM-248"), + required_verdict=REQUIRED_FIDELITY_VERDICT, + actual_verdict=actual, + met=met, + rationale=authorization.get("verdict_rationale", ""), + ) + + +def _evaluate_trace_gate(trace_gate_contract: dict[str, Any]) -> GateEvaluation: + gate = trace_gate_contract.get("gate") or {} + actual = gate.get("verdict", "") + met = actual == REQUIRED_TRACE_VERDICT + return GateEvaluation( + gate_name="trace_oracle_ceiling", + source_contract_id=trace_gate_contract.get("contract_id", ""), + source_contract_hash=trace_gate_contract.get("contract_hash", ""), + source_linear_issue=gate.get("linear_issue", "SLM-249"), + required_verdict=REQUIRED_TRACE_VERDICT, + actual_verdict=actual, + met=met, + rationale=gate.get("verdict_rationale", ""), + ) + + +def evaluate_activation_gates( + fidelity_contract: dict[str, Any], + trace_gate_contract: dict[str, Any], +) -> LotusOpenUIModelContractV1: + """Evaluate LOT1-01's two hard activation gates against real upstream contracts. + + Returns a :class:`LotusOpenUIModelContractV1` whose ``verdict`` is + ``not_authorized`` unless both upstream gates report their exact required + verdict strings. No K x c model/training code path is implied or run by + a positive result; per the issue text, even an authorized gate delivers + "wiring/contract evidence only" (``authorized_wiring_only``), never a + semantic-quality claim. + """ + gate_1 = _evaluate_fidelity_gate(fidelity_contract) + gate_2 = _evaluate_trace_gate(trace_gate_contract) + + if gate_1.met and gate_2.met: + verdict = AUTHORIZED_WIRING_ONLY + rationale = ( + "Both hard activation gates report their required verdicts. " + "LOT1-01 may proceed in wiring/contract-evidence-only mode; " + "this contract authorizes no training or semantic-quality claim." + ) + else: + verdict = NOT_AUTHORIZED + unmet = [g.gate_name for g in (gate_1, gate_2) if not g.met] + rationale = ( + "Hard activation gate(s) unmet: " + + ", ".join(unmet) + + f". Gate 1 (SLM-248 fidelity authorization) reports verdict " + f"'{gate_1.actual_verdict}' (requires '{REQUIRED_FIDELITY_VERDICT}'). " + f"Gate 2 (SLM-249 trace oracle ceiling) reports verdict " + f"'{gate_2.actual_verdict}' (requires '{REQUIRED_TRACE_VERDICT}'). " + "Closing not_authorized in plan-only mode; no K x c model or " + "training code is added by this disposition." + ) + + return LotusOpenUIModelContractV1( + gate_1_fidelity_authorization=gate_1, + gate_2_trace_oracle_ceiling=gate_2, + verdict=verdict, + verdict_rationale=rationale, + version_stamp=build_version_stamp("harness.experiments"), + ) + + +def render_markdown(contract: LotusOpenUIModelContractV1) -> str: + g1 = contract.gate_1_fidelity_authorization + g2 = contract.gate_2_trace_oracle_ceiling + lines = [ + f"# SLM-250 LOT1-01 — Activation-gate disposition ({contract.contract_id})", + "", + f"Verdict: **{contract.verdict}**", + "", + contract.verdict_rationale, + "", + "## Gate 1 — fidelity contract authorization (SLM-248)", + "", + f"- Source contract: `{g1.source_contract_id}` (`{g1.source_contract_hash}`)", + f"- Required verdict: `{g1.required_verdict}`", + f"- Actual verdict: `{g1.actual_verdict}`", + f"- Met: **{g1.met}**", + "", + "## Gate 2 — trace oracle-ceiling (SLM-249)", + "", + f"- Source contract: `{g2.source_contract_id}` (`{g2.source_contract_hash}`)", + f"- Required verdict: `{g2.required_verdict}`", + f"- Actual verdict: `{g2.actual_verdict}`", + f"- Met: **{g2.met}**", + "", + "## Non-goals honored", + "", + "No K x c latent-workspace model code, no learned plan predictor, no " + "GPU training, no production default change. This disposition is " + "itself the LOT1-01 deliverable when the activation gate is unmet.", + "", + ] + return "\n".join(lines) diff --git a/src/slm_training/resources/versions.json b/src/slm_training/resources/versions.json index 4e7a55620..7460c151f 100644 --- a/src/slm_training/resources/versions.json +++ b/src/slm_training/resources/versions.json @@ -550,7 +550,7 @@ { "version": "v1", "date": "2026-07-25", - "note": "no-bump: DSH5-05 extracts the private _merge_value/_StructuralConflict/MergeConflictKind primitive into the new src/slm_training/dsl/operators/ast_merge.py module (merge_ast_value/StructuralMergeConflict/MergeConflictKind) so the transaction executor's N-way fold can reuse it without importing merge.py (which imports conversation.py) and closing an import cycle; merge.py now imports from ast_merge.py instead of defining these locally — public behavior and every test_operator_merge.py test are unchanged" + "note": "no-bump: DSH5-05 extracts the private _merge_value/_StructuralConflict/MergeConflictKind primitive into the new src/slm_training/dsl/operators/ast_merge.py module (merge_ast_value/StructuralMergeConflict/MergeConflictKind) so the transaction executor's N-way fold can reuse it without importing merge.py (which imports conversation.py) and closing an import cycle; merge.py now imports from ast_merge.py instead of defining these locally \u2014 public behavior and every test_operator_merge.py test are unchanged" }, { "version": "v1", @@ -683,7 +683,7 @@ { "version": "v1", "date": "2026-07-25", - "note": "DSH5-02: initial exact atomic bulk openui.map_set_property operator over SelectorRefV1 — one schema-valid property update applied to every exact selected node atomically, with per-target effect deltas, replay, fresh post-commit reference-table continuation, and a diagnostic-only primitive-lowering equivalence oracle" + "note": "DSH5-02: initial exact atomic bulk openui.map_set_property operator over SelectorRefV1 \u2014 one schema-valid property update applied to every exact selected node atomically, with per-target effect deltas, replay, fresh post-commit reference-table continuation, and a diagnostic-only primitive-lowering equivalence oracle" } ] }, @@ -764,7 +764,7 @@ { "version": "v3", "date": "2026-07-25", - "note": "DSH5-05: extend _target_lineage to also map ReferenceTableV1.selectors (not just .entries), so a selector-argument operator (openui.map_set_property, DSH5-02's only bulk operator) can be prepared into a transaction at all — previously unresolvable in both prepare_operator_action's semantic-id derivation and derive_read_write_set's precondition footprint, invisible until DSH5-05's bulk-plus-primitive matrix requirement exercised it; purely additive, no existing non-selector lineage entry changes" + "note": "DSH5-05: extend _target_lineage to also map ReferenceTableV1.selectors (not just .entries), so a selector-argument operator (openui.map_set_property, DSH5-02's only bulk operator) can be prepared into a transaction at all \u2014 previously unresolvable in both prepare_operator_action's semantic-id derivation and derive_read_write_set's precondition footprint, invisible until DSH5-05's bulk-plus-primitive matrix requirement exercised it; purely additive, no existing non-selector lineage entry changes" }, { "version": "v2", @@ -774,7 +774,7 @@ { "version": "v1", "date": "2026-07-25", - "note": "DSH5-04: initial OperatorTransactionV1/PreparedOperatorActionV1/OperatorReadWriteSetV1 base-state, dependency, and conflict contracts — one-base multi-action preparation, semantic read/write footprints, write/write and write/read conflict resolution via mutual commutativity (reusing merge.py's _effect_targets and mutually-commuting gate), dependency-cycle detection, and canonical permutation-invariant transaction identity; schema/safety layer only, no execution path wired" + "note": "DSH5-04: initial OperatorTransactionV1/PreparedOperatorActionV1/OperatorReadWriteSetV1 base-state, dependency, and conflict contracts \u2014 one-base multi-action preparation, semantic read/write footprints, write/write and write/read conflict resolution via mutual commutativity (reusing merge.py's _effect_targets and mutually-commuting gate), dependency-cycle detection, and canonical permutation-invariant transaction identity; schema/safety layer only, no execution path wired" } ] }, @@ -791,7 +791,7 @@ { "version": "v1", "date": "2026-07-25", - "note": "DSH5-05: initial atomic multi-action operator transaction executor — independent per-action constituent replay against one fixed base, base-relative N-way AST composition (a fold over the new shared ast_merge.merge_ast_value primitive, extracted from merge.py to avoid a conversation<->transaction_executor import cycle), a real structural-conflict safety net over declared-but-unverified commutativity, full pack-authority validation, fresh branch-local reference-table continuation via a caller-supplied builder, exact commit replay, and one CRDT conversation turn (TRANSACTION_COMMIT) carrying the whole transaction with every constituent application ID retained" + "note": "DSH5-05: initial atomic multi-action operator transaction executor \u2014 independent per-action constituent replay against one fixed base, base-relative N-way AST composition (a fold over the new shared ast_merge.merge_ast_value primitive, extracted from merge.py to avoid a conversation<->transaction_executor import cycle), a real structural-conflict safety net over declared-but-unverified commutativity, full pack-authority validation, fresh branch-local reference-table continuation via a caller-supplied builder, exact commit replay, and one CRDT conversation turn (TRANSACTION_COMMIT) carrying the whole transaction with every constituent application ID retained" } ] }, @@ -1209,7 +1209,7 @@ { "version": "v9", "date": "2026-07-19", - "note": "add EFS2-01 X22 tree-edit beam-width × edit-depth scaling harness (TreeEditScalingConfig, run_scaling_grid, valid-state beam search) on top of quantized-energy/solver-state/verifier-cascade stack" + "note": "add EFS2-01 X22 tree-edit beam-width \u00d7 edit-depth scaling harness (TreeEditScalingConfig, run_scaling_grid, valid-state beam search) on top of quantized-energy/solver-state/verifier-cascade stack" }, { "version": "v8", @@ -1716,7 +1716,7 @@ ] }, "harness.experiments": { - "version": "v108", + "version": "v109", "kind": "harness", "paths": [ "src/slm_training/harnesses/experiments/", @@ -1725,6 +1725,11 @@ "tests/test_scripts/test_run_slm298_capacity_context_curriculum.py" ], "history": [ + { + "version": "v109", + "date": "2026-07-25", + "note": "add SLM-250 LOT1-01 hard-activation-gate evaluator (lot1_01_activation_gate.py): reads SLM-248/SLM-249 real upstream contracts and closes not_authorized in plan-only mode, no K x c model/training code" + }, { "version": "v108", "date": "2026-07-25", @@ -2148,7 +2153,7 @@ { "version": "v31", "date": "2026-07-20", - "note": "add SLM-148 SPV1-05 plan-conditioned X22 × conflict-slice staged campaign wiring/fixture harness" + "note": "add SLM-148 SPV1-05 plan-conditioned X22 \u00d7 conflict-slice staged campaign wiring/fixture harness" }, { "version": "v30", @@ -2188,7 +2193,7 @@ { "version": "v24", "date": "2026-07-19", - "note": "add SLM-133 EFS3-06 AST-sketch dedup × choice-native retrieval factorial wiring/fixture harness" + "note": "add SLM-133 EFS3-06 AST-sketch dedup \u00d7 choice-native retrieval factorial wiring/fixture harness" }, { "version": "v23", @@ -2248,7 +2253,7 @@ { "version": "v13", "date": "2026-07-19", - "note": "add CAP3-05 (SLM-94) equal-byte width × precision ladder planner and dry-run manifest support" + "note": "add CAP3-05 (SLM-94) equal-byte width \u00d7 precision ladder planner and dry-run manifest support" }, { "version": "v12", @@ -2312,6 +2317,25 @@ } ] }, + "harness.experiments.lot1_01_activation_gate": { + "version": "v1", + "kind": "gate", + "paths": [ + "src/slm_training/harnesses/experiments/lot1_01_activation_gate.py", + "scripts/evaluate_lot1_01_activation_gate.py", + "tests/test_harnesses/experiments/test_lot1_01_activation_gate.py", + "tests/test_scripts/test_evaluate_lot1_01_activation_gate.py", + "docs/design/iter-slm250-lot1-01-not-authorized-20260725.json", + "docs/design/iter-slm250-lot1-01-not-authorized-20260725.md" + ], + "history": [ + { + "version": "v1", + "date": "2026-07-25", + "note": "initial registration; SLM-250 LOT1-01 hard-activation-gate evaluator closes not_authorized against the real SLM-248/SLM-249 upstream contracts" + } + ] + }, "harness.experiments.external_ceiling": { "version": "v2", "kind": "harness", @@ -2367,7 +2391,7 @@ { "version": "v1", "date": "2026-07-19", - "note": "initial registration; SLM-133 EFS3-06 AST-sketch dedup × choice-native retrieval factorial wiring/fixture harness" + "note": "initial registration; SLM-133 EFS3-06 AST-sketch dedup \u00d7 choice-native retrieval factorial wiring/fixture harness" } ] }, @@ -2595,7 +2619,7 @@ { "version": "sde5-03-v1", "date": "2026-07-21", - "note": "initial registration; SLM-210 SDE5-03 prompt-plan × grammar-mass × high-debt exposure floor-escape matrix wiring/fixture harness" + "note": "initial registration; SLM-210 SDE5-03 prompt-plan \u00d7 grammar-mass \u00d7 high-debt exposure floor-escape matrix wiring/fixture harness" } ] }, @@ -3066,7 +3090,7 @@ { "version": "v1", "date": "2026-07-20", - "note": "initial registration of SLM-148 SPV1-05 plan-conditioned X22 × conflict-slice staged campaign wiring/fixture harness" + "note": "initial registration of SLM-148 SPV1-05 plan-conditioned X22 \u00d7 conflict-slice staged campaign wiring/fixture harness" } ] }, diff --git a/tests/test_harnesses/experiments/test_lot1_01_activation_gate.py b/tests/test_harnesses/experiments/test_lot1_01_activation_gate.py new file mode 100644 index 000000000..085be80c7 --- /dev/null +++ b/tests/test_harnesses/experiments/test_lot1_01_activation_gate.py @@ -0,0 +1,138 @@ +"""Tests for slm_training.harnesses.experiments.lot1_01_activation_gate (SLM-250).""" + +from __future__ import annotations + +from pathlib import Path + +from slm_training.harnesses.experiments.lot1_01_activation_gate import ( + AUTHORIZED_WIRING_ONLY, + NOT_AUTHORIZED, + REQUIRED_FIDELITY_VERDICT, + REQUIRED_TRACE_VERDICT, + evaluate_activation_gates, + load_upstream_contract, + render_markdown, +) + +REPO_ROOT = Path(__file__).resolve().parents[3] +FIDELITY_CONTRACT_PATH = REPO_ROOT / "docs/design/lotus-openui-fidelity-contract-v1.json" +TRACE_GATE_CONTRACT_PATH = REPO_ROOT / "docs/design/compiler-reasoning-trace-v1.json" + + +def test_real_upstream_contracts_are_not_authorized() -> None: + """The actual, currently-committed SLM-248/SLM-249 verdicts must yield + not_authorized: SLM-248 reports needs_target_trace_contract (not + authorize_bounded_implementation) and SLM-249 reports inconclusive (not + oracle_ceiling_positive). This is the load-bearing proof that LOT1-01 + correctly closes without any K x c model/training code. + """ + fidelity_contract = load_upstream_contract(FIDELITY_CONTRACT_PATH) + trace_gate_contract = load_upstream_contract(TRACE_GATE_CONTRACT_PATH) + + contract = evaluate_activation_gates(fidelity_contract, trace_gate_contract) + + assert contract.verdict == NOT_AUTHORIZED + assert contract.gate_1_fidelity_authorization.met is False + assert contract.gate_1_fidelity_authorization.actual_verdict == "needs_target_trace_contract" + assert contract.gate_2_trace_oracle_ceiling.met is False + assert contract.gate_2_trace_oracle_ceiling.actual_verdict == "inconclusive" + + +def test_both_gates_met_authorizes_wiring_only() -> None: + """The evaluator is not hardcoded to always fail: synthetic contracts + + reporting both required verdicts must flip the disposition, but only to + a wiring-only authorization, never a semantic-quality claim. + """ + fidelity_contract = { + "contract_id": "synthetic-fidelity", + "contract_hash": "deadbeef", + "authorization": { + "linear_issue": "SLM-248", + "verdict": REQUIRED_FIDELITY_VERDICT, + "verdict_rationale": "synthetic positive", + }, + } + trace_gate_contract = { + "contract_id": "synthetic-trace", + "contract_hash": "cafef00d", + "gate": { + "linear_issue": "SLM-249", + "verdict": REQUIRED_TRACE_VERDICT, + "verdict_rationale": "synthetic positive", + }, + } + + contract = evaluate_activation_gates(fidelity_contract, trace_gate_contract) + + assert contract.verdict == AUTHORIZED_WIRING_ONLY + assert contract.gate_1_fidelity_authorization.met is True + assert contract.gate_2_trace_oracle_ceiling.met is True + + +def test_only_one_gate_met_stays_not_authorized() -> None: + fidelity_contract = { + "contract_id": "synthetic-fidelity", + "contract_hash": "deadbeef", + "authorization": {"linear_issue": "SLM-248", "verdict": REQUIRED_FIDELITY_VERDICT}, + } + trace_gate_contract = { + "contract_id": "synthetic-trace", + "contract_hash": "cafef00d", + "gate": {"linear_issue": "SLM-249", "verdict": "inconclusive"}, + } + + contract = evaluate_activation_gates(fidelity_contract, trace_gate_contract) + + assert contract.verdict == NOT_AUTHORIZED + assert contract.gate_1_fidelity_authorization.met is True + assert contract.gate_2_trace_oracle_ceiling.met is False + + +def test_missing_fields_fail_closed_not_authorized() -> None: + contract = evaluate_activation_gates({}, {}) + assert contract.verdict == NOT_AUTHORIZED + assert contract.gate_1_fidelity_authorization.actual_verdict == "" + assert contract.gate_2_trace_oracle_ceiling.actual_verdict == "" + + +def test_contract_hash_is_stable_and_changes_with_verdict() -> None: + fidelity_contract = load_upstream_contract(FIDELITY_CONTRACT_PATH) + trace_gate_contract = load_upstream_contract(TRACE_GATE_CONTRACT_PATH) + + a = evaluate_activation_gates(fidelity_contract, trace_gate_contract) + b = evaluate_activation_gates(fidelity_contract, trace_gate_contract) + assert a.contract_hash() == b.contract_hash() + + synthetic_fidelity = dict(fidelity_contract) + synthetic_fidelity["authorization"] = dict(fidelity_contract["authorization"]) + synthetic_fidelity["authorization"]["verdict"] = REQUIRED_FIDELITY_VERDICT + c = evaluate_activation_gates(synthetic_fidelity, trace_gate_contract) + assert c.contract_hash() != a.contract_hash() + + +def test_to_dict_and_to_json_round_trip(tmp_path: Path) -> None: + fidelity_contract = load_upstream_contract(FIDELITY_CONTRACT_PATH) + trace_gate_contract = load_upstream_contract(TRACE_GATE_CONTRACT_PATH) + contract = evaluate_activation_gates(fidelity_contract, trace_gate_contract) + + out_path = tmp_path / "contract.json" + contract.to_json(out_path) + assert out_path.exists() + + data = contract.to_dict() + assert data["verdict"] == NOT_AUTHORIZED + assert data["gate_1_fidelity_authorization"]["source_contract_id"] == "lotus-openui-fidelity-contract-v1" + assert data["gate_2_trace_oracle_ceiling"]["source_contract_id"] == "compiler-reasoning-trace-v1" + + +def test_render_markdown_includes_verdict_and_gates() -> None: + fidelity_contract = load_upstream_contract(FIDELITY_CONTRACT_PATH) + trace_gate_contract = load_upstream_contract(TRACE_GATE_CONTRACT_PATH) + contract = evaluate_activation_gates(fidelity_contract, trace_gate_contract) + + md = render_markdown(contract) + assert "not_authorized" in md + assert "needs_target_trace_contract" in md + assert "inconclusive" in md + assert "No K x c latent-workspace model code" in md diff --git a/tests/test_scripts/test_evaluate_lot1_01_activation_gate.py b/tests/test_scripts/test_evaluate_lot1_01_activation_gate.py new file mode 100644 index 000000000..b64faa841 --- /dev/null +++ b/tests/test_scripts/test_evaluate_lot1_01_activation_gate.py @@ -0,0 +1,36 @@ +"""Tests for scripts/evaluate_lot1_01_activation_gate.py (SLM-250).""" + +from __future__ import annotations + +import json +from pathlib import Path + +from scripts import evaluate_lot1_01_activation_gate + + +def test_default_run_reports_not_authorized(tmp_path: Path) -> None: + out = tmp_path / "gate" + rc = evaluate_lot1_01_activation_gate.main(["--out", str(out)]) + assert rc == 0 + + data = json.loads((out / "lotus_openui_model_contract.json").read_text()) + assert data["verdict"] == "not_authorized" + assert (out / "lotus_openui_model_contract.md").exists() + + +def test_run_against_explicit_contract_paths(tmp_path: Path) -> None: + out = tmp_path / "gate_explicit" + rc = evaluate_lot1_01_activation_gate.main( + [ + "--fidelity-contract", + "docs/design/lotus-openui-fidelity-contract-v1.json", + "--trace-gate-contract", + "docs/design/compiler-reasoning-trace-v1.json", + "--out", + str(out), + ] + ) + assert rc == 0 + markdown = (out / "lotus_openui_model_contract.md").read_text() + assert "SLM-250" in markdown + assert "not_authorized" in markdown From e484978344f756a606cc08e0cb5d7961d7447ad8 Mon Sep 17 00:00:00 2001 From: Tyler Kendrick <145080887+Tyler-R-Kendrick@users.noreply.github.com> Date: Sat, 25 Jul 2026 11:00:10 -0500 Subject: [PATCH 2/2] SLM-251: close LOT1-02 not_authorized via launch-gate evaluator LOT1-02's launch prerequisites are unmet against the real committed upstream contracts: SLM-248 reports needs_target_trace_contract (not authorize_bounded_implementation), SLM-249's trace gate reports inconclusive (not oracle_ceiling_positive), its own allowed_lot1_implementation authorizes no LOT1 implementation, and LOT1-01 (SLM-250) itself closed not_authorized -- so no faithful K x c model path, curriculum hooks, or Stage 0 parent exist to train, and there is no treatment arm to attribute against a continued-explicit control. Per LOT1-01's own gate law this closes LOT1-02 not_authorized in plan-only mode with no training/curriculum/model code. Adds a small tested Lot102LaunchGateV1 evaluator that reuses the SLM-250 lot1_01_activation_gate module (no parallel path) and adds the SLM-249 explicit-allowance check; synthetic positive fixtures prove it flips to authorized_wiring_only when prerequisites are honestly met. --- ...lm251-lot1-02-not-authorized-20260725.json | 48 ++++ ...-slm251-lot1-02-not-authorized-20260725.md | 32 +++ scripts/evaluate_lot1_02_activation_gate.py | 70 ++++++ .../experiments/lot1_02_activation_gate.py | 216 ++++++++++++++++++ src/slm_training/resources/versions.json | 26 ++- .../test_lot1_02_activation_gate.py | 119 ++++++++++ .../test_evaluate_lot1_02_activation_gate.py | 37 +++ 7 files changed, 547 insertions(+), 1 deletion(-) create mode 100644 docs/design/iter-slm251-lot1-02-not-authorized-20260725.json create mode 100644 docs/design/iter-slm251-lot1-02-not-authorized-20260725.md create mode 100644 scripts/evaluate_lot1_02_activation_gate.py create mode 100644 src/slm_training/harnesses/experiments/lot1_02_activation_gate.py create mode 100644 tests/test_harnesses/experiments/test_lot1_02_activation_gate.py create mode 100644 tests/test_scripts/test_evaluate_lot1_02_activation_gate.py diff --git a/docs/design/iter-slm251-lot1-02-not-authorized-20260725.json b/docs/design/iter-slm251-lot1-02-not-authorized-20260725.json new file mode 100644 index 000000000..96248931a --- /dev/null +++ b/docs/design/iter-slm251-lot1-02-not-authorized-20260725.json @@ -0,0 +1,48 @@ +{ + "contract_hash": "f358dcc954a6a96c6e494acbabc8635b79184ca15b9d80f3f59ff7d3e7416ace", + "contract_id": "lot1-02-launch-gate-v1", + "gate_1_transfer_authorization": { + "actual_verdict": "needs_target_trace_contract", + "gate_name": "fidelity_contract_authorization", + "met": false, + "rationale": "Differentiation from every existing repo mechanism (masked recursive denoiser, SemanticPlanV1 predictors/consumers, causal FTPO adapters, explicit compiler traces, valid-state tree-edit/lattice search) is clean and survives line-by-line comparison -- see non_duplication_map, all rows no_duplication. The blocker is narrower: LOTUS's explicit-to-latent curriculum (mechanism row 5) and its causal_latent_use claim class both presuppose a step-decomposable 'explicit trace' analogous to GSM8K CoT steps that this repo does not yet define for OpenUI program synthesis. Defining that target-trace contract honestly -- without assuming math-payload equivalence to GSM8K, and without silently reusing causal_trace.py's visible-token decode capture or SemanticPlanV1's plan IR as if either already were that trace -- is out of scope for this docs/spec-only issue (no corpus generation beyond bounded target-contract probes). Authorizing bounded implementation now would force either an undefined curriculum or a quietly borrowed non-LOTUS trace source; neither is honest. This is not a 'differentiation is weak' close and not a semantic-floor block -- it is a scoped prerequisite.", + "required_verdict": "authorize_bounded_implementation", + "source_contract_hash": "801ce267b64f52b88e6e80fa091084c5f1a6628de60658d2d161db82f5117af2", + "source_contract_id": "lotus-openui-fidelity-contract-v1", + "source_linear_issue": "SLM-248" + }, + "gate_2_trace_oracle_ceiling": { + "actual_verdict": "inconclusive", + "gate_name": "trace_oracle_ceiling", + "met": false, + "rationale": "The trace contract, typed step schema, deterministic extractor, and lossless visible serialization are implemented and tested against the repository's existing SemanticPlanV1/production_codec owners (no new compiler/parser/evaluator). A bounded n=16 fixture probe (not a production corpus) confirms every probe record decomposes into all six declared stages with zero truncation, giving a provisional K=6/c=479-chars budget. The oracle ceiling experiment itself -- the only evidence that could support an oracle_ceiling_positive, no_downstream_ceiling, or explicit_trace_equivalent_to_existing_plan verdict -- is specified as a matched multi-arm, multi-seed plan but deliberately not run: the LOT0-01 authorization scopes this issue to a fixture-scale plan only, with GPU training and corpus generation explicitly blocked. Declaring any positive or negative ceiling verdict without running that plan would be exactly the 'no claim that explicit trace benefit implies latent benefit' failure this issue's acceptance criteria forbid. leakage_or_ambiguity_blocked and target_support_insufficient are also not honest: no leakage was found and the bounded probe supports the stage set within its declared scope. inconclusive -- pending the oracle-ceiling campaign -- is the only accurate verdict.", + "required_verdict": "oracle_ceiling_positive", + "source_contract_hash": "6cdd695bf5b32036519f1ee2e787a44e4afbb045fc059f75a92a2d069f0ee7c5", + "source_contract_id": "compiler-reasoning-trace-v1", + "source_linear_issue": "SLM-249" + }, + "gate_3_explicit_kc_stage_authorization": { + "actual_verdict": "none: the K x c latent-workspace model implementation (SLM-250 / LOT1-01) remains gated on a positive oracle-ceiling result, which requires running the plan defined here -- not authorized by this issue.", + "gate_name": "explicit_kc_stage_authorization", + "met": false, + "rationale": "SLM-249's own allowed_lot1_implementation field authorizes no LOT1 implementation; the oracle ceiling is inconclusive and K/c is a bounded probe recommendation only, not a data-derived production budget.", + "required_verdict": "explicit allowed_lot1_implementation entry with K/c/stage targets", + "source_contract_hash": "6cdd695bf5b32036519f1ee2e787a44e4afbb045fc059f75a92a2d069f0ee7c5", + "source_contract_id": "compiler-reasoning-trace-v1", + "source_linear_issue": "SLM-249" + }, + "linear_issue": "SLM-251", + "lot1_01_disposition": "not_authorized", + "schema_version": "lot1_02_launch_gate/v1", + "verdict": "not_authorized", + "verdict_rationale": "LOT1-02 launch prerequisite(s) unmet: transfer_authorization (SLM-248), trace_oracle_ceiling (SLM-249), explicit_kc_stage_authorization (SLM-249 allowed_lot1_implementation). LOT1-01's disposition is 'not_authorized', so no faithful K x c model path or curriculum hooks exist to train; SLM-249's oracle ceiling is not positive and authorizes no LOT1 implementation. There is no treatment arm to run and no matched continued-explicit control to attribute against. Closing not_authorized in plan-only mode; no training, curriculum, or model code is added by this disposition.", + "version_stamp": { + "code_commit": "941730cbbe0ac6a956b87085b54ff874089e54e1", + "code_dirty": true, + "components": { + "harness.experiments": "v110" + }, + "stamp_schema": "version_stamp/v1", + "stamped_at": "2026-07-25T15:59:29.204608+00:00" + } +} diff --git a/docs/design/iter-slm251-lot1-02-not-authorized-20260725.md b/docs/design/iter-slm251-lot1-02-not-authorized-20260725.md new file mode 100644 index 000000000..78dea06b9 --- /dev/null +++ b/docs/design/iter-slm251-lot1-02-not-authorized-20260725.md @@ -0,0 +1,32 @@ +# SLM-251 LOT1-02 — Launch-gate disposition (lot1-02-launch-gate-v1) + +Verdict: **not_authorized** + +LOT1-02 launch prerequisite(s) unmet: transfer_authorization (SLM-248), trace_oracle_ceiling (SLM-249), explicit_kc_stage_authorization (SLM-249 allowed_lot1_implementation). LOT1-01's disposition is 'not_authorized', so no faithful K x c model path or curriculum hooks exist to train; SLM-249's oracle ceiling is not positive and authorizes no LOT1 implementation. There is no treatment arm to run and no matched continued-explicit control to attribute against. Closing not_authorized in plan-only mode; no training, curriculum, or model code is added by this disposition. + +LOT1-01 disposition: `not_authorized` + +## Gate 1 — transfer authorization (SLM-248) + +- Source contract: `lotus-openui-fidelity-contract-v1` (`801ce267b64f52b88e6e80fa091084c5f1a6628de60658d2d161db82f5117af2`) +- Required: authorize_bounded_implementation +- Actual verdict: `needs_target_trace_contract` +- Met: **False** + +## Gate 2 — trace oracle ceiling (SLM-249) + +- Source contract: `compiler-reasoning-trace-v1` (`6cdd695bf5b32036519f1ee2e787a44e4afbb045fc059f75a92a2d069f0ee7c5`) +- Required: oracle_ceiling_positive +- Actual verdict: `inconclusive` +- Met: **False** + +## Gate 3 — explicit LOT1 implementation allowance (SLM-249) + +- Source contract: `compiler-reasoning-trace-v1` (`6cdd695bf5b32036519f1ee2e787a44e4afbb045fc059f75a92a2d069f0ee7c5`) +- Required: explicit allowed_lot1_implementation entry with K/c/stage targets +- Actual verdict: `none: the K x c latent-workspace model implementation (SLM-250 / LOT1-01) remains gated on a positive oracle-ceiling result, which requires running the plan defined here -- not authorized by this issue.` +- Met: **False** + +## Non-goals honored + +No training campaign, no curriculum code, no Stage 0 checkpoint, no GPU dispatch, and no production default change. This disposition is itself the LOT1-02 deliverable while the launch prerequisites are unmet. diff --git a/scripts/evaluate_lot1_02_activation_gate.py b/scripts/evaluate_lot1_02_activation_gate.py new file mode 100644 index 000000000..f9267d301 --- /dev/null +++ b/scripts/evaluate_lot1_02_activation_gate.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +"""Evaluate SLM-251 (LOT1-02)'s launch prerequisites in plan-only mode. + +No training, curriculum, or model code is loaded or executed. This reads +the real committed upstream contract artifacts and emits the +``Lot102LaunchGateV1`` disposition. + +Example: + python -m scripts.evaluate_lot1_02_activation_gate \ + --fidelity-contract docs/design/lotus-openui-fidelity-contract-v1.json \ + --trace-gate-contract docs/design/compiler-reasoning-trace-v1.json \ + --out outputs/runs/slm251_launch_gate +""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path + +from slm_training.harnesses.experiments.lot1_01_activation_gate import ( + load_upstream_contract, +) +from slm_training.harnesses.experiments.lot1_02_activation_gate import ( + evaluate_lot1_02_launch_gate, + render_markdown, +) + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser( + description="SLM-251 LOT1-02 launch-gate evaluator (plan-only, no training code)" + ) + parser.add_argument( + "--fidelity-contract", + type=Path, + default=Path("docs/design/lotus-openui-fidelity-contract-v1.json"), + help="SLM-248 LotusOpenUIFidelityContractV1 JSON artifact", + ) + parser.add_argument( + "--trace-gate-contract", + type=Path, + default=Path("docs/design/compiler-reasoning-trace-v1.json"), + help="SLM-249 CompilerReasoningTraceGateV1 JSON artifact", + ) + parser.add_argument( + "--out", + type=Path, + default=Path("outputs/runs/slm251_launch_gate"), + ) + args = parser.parse_args(argv) + + fidelity_contract = load_upstream_contract(args.fidelity_contract) + trace_gate_contract = load_upstream_contract(args.trace_gate_contract) + + contract = evaluate_lot1_02_launch_gate(fidelity_contract, trace_gate_contract) + + args.out.mkdir(parents=True, exist_ok=True) + (args.out / "lot1_02_launch_gate.json").write_text( + json.dumps(contract.to_dict(), indent=2, sort_keys=True, default=str) + "\n", + encoding="utf-8", + ) + markdown = render_markdown(contract) + (args.out / "lot1_02_launch_gate.md").write_text(markdown, encoding="utf-8") + print(markdown) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/slm_training/harnesses/experiments/lot1_02_activation_gate.py b/src/slm_training/harnesses/experiments/lot1_02_activation_gate.py new file mode 100644 index 000000000..547b45773 --- /dev/null +++ b/src/slm_training/harnesses/experiments/lot1_02_activation_gate.py @@ -0,0 +1,216 @@ +"""SLM-251 LOT1-02 launch-gate evaluator (plan-only closeout). + +LOT1-02 ("Run the explicit-to-latent curriculum against an update-matched +continued explicit-trace control") declares three upstream dependencies: + +1. SLM-248 (LOT0-01) transfer authorization -- preregistered margins and a + ``authorize_bounded_implementation`` verdict. +2. SLM-249 (LOT0-02) ``CompilerReasoningTraceGateV1`` -- K/c/stage support + and a positive oracle ceiling. +3. SLM-250 (LOT1-01) -- the faithful K x c looped-latent model path and + curriculum hooks. + +The campaign cannot launch honestly unless every dependency is authorized: +there is no treatment arm without the LOT1-01 model path, and no causal +attribution without the SLM-249 oracle ceiling. This module derives the +LOT1-02 launch disposition from the same real, committed upstream contract +artifacts as the LOT1-01 gate (reusing +:mod:`slm_training.harnesses.experiments.lot1_01_activation_gate`) plus the +trace contract's own ``allowed_lot1_implementation`` field. It contains no +training, curriculum, or model code -- evaluating this gate honestly *is* +the LOT1-02 deliverable while the prerequisites are unmet. +""" + +from __future__ import annotations + +import hashlib +import json +from dataclasses import asdict, dataclass, field +from typing import Any + +from slm_training.harness_core.versioning import build_version_stamp +from slm_training.harnesses.experiments.lot1_01_activation_gate import ( + AUTHORIZED_WIRING_ONLY, + NOT_AUTHORIZED, + GateEvaluation, + evaluate_activation_gates, +) + +__all__ = [ + "GATE_SCHEMA_VERSION", + "LAUNCH_GATE_CONTRACT_ID", + "Lot102LaunchGateV1", + "evaluate_lot1_02_launch_gate", + "render_markdown", +] + +GATE_SCHEMA_VERSION = "lot1_02_launch_gate/v1" +LAUNCH_GATE_CONTRACT_ID = "lot1-02-launch-gate-v1" + + +@dataclass(frozen=True) +class Lot102LaunchGateV1: + """LOT1-02 launch disposition derived from real upstream contracts.""" + + schema_version: str = GATE_SCHEMA_VERSION + contract_id: str = LAUNCH_GATE_CONTRACT_ID + linear_issue: str = "SLM-251" + lot1_01_disposition: str = NOT_AUTHORIZED + gate_1_transfer_authorization: GateEvaluation | None = None + gate_2_trace_oracle_ceiling: GateEvaluation | None = None + gate_3_explicit_kc_stage_authorization: GateEvaluation | None = None + verdict: str = NOT_AUTHORIZED + verdict_rationale: str = "" + version_stamp: dict[str, Any] = field(default_factory=dict) + + def to_dict(self) -> dict[str, Any]: + data = dict(asdict(self)) + for key in ( + "gate_1_transfer_authorization", + "gate_2_trace_oracle_ceiling", + "gate_3_explicit_kc_stage_authorization", + ): + gate = getattr(self, key) + data[key] = gate.to_dict() if gate is not None else None + data["contract_hash"] = self.contract_hash() + return data + + def contract_hash(self) -> str: + payload = { + "schema_version": self.schema_version, + "contract_id": self.contract_id, + "linear_issue": self.linear_issue, + "lot1_01_disposition": self.lot1_01_disposition, + "verdict": self.verdict, + } + return hashlib.sha256( + json.dumps(payload, sort_keys=True, default=str).encode("utf-8") + ).hexdigest() + + +def _evaluate_kc_stage_authorization(trace_gate_contract: dict[str, Any]) -> GateEvaluation: + """Check SLM-249's own explicit LOT1 implementation allowance. + + ``allowed_lot1_implementation`` is a list whose only honest negative + entry starts with ``none``. Any other entry is an explicit authorization + carrying K/c/stage targets. + """ + gate = trace_gate_contract.get("gate") or {} + allowed = gate.get("allowed_lot1_implementation") or [] + explicit = [entry for entry in allowed if not str(entry).strip().lower().startswith("none")] + met = bool(explicit) + return GateEvaluation( + gate_name="explicit_kc_stage_authorization", + source_contract_id=trace_gate_contract.get("contract_id", ""), + source_contract_hash=trace_gate_contract.get("contract_hash", ""), + source_linear_issue=gate.get("linear_issue", "SLM-249"), + required_verdict="explicit allowed_lot1_implementation entry with K/c/stage targets", + actual_verdict="; ".join(str(e) for e in allowed) or "", + met=met, + rationale=( + "SLM-249 explicitly authorizes LOT1 implementation: " + "; ".join(explicit) + if met + else "SLM-249's own allowed_lot1_implementation field authorizes no LOT1 " + "implementation; the oracle ceiling is inconclusive and K/c is a bounded " + "probe recommendation only, not a data-derived production budget." + ), + ) + + +def evaluate_lot1_02_launch_gate( + fidelity_contract: dict[str, Any], + trace_gate_contract: dict[str, Any], +) -> Lot102LaunchGateV1: + """Evaluate LOT1-02's launch prerequisites against real upstream contracts. + + Reuses the LOT1-01 evaluator for the shared transfer-authorization and + oracle-ceiling gates, then adds LOT1-02's own requirement that SLM-249 + explicitly authorize LOT1 implementation. The verdict is + ``not_authorized`` unless every prerequisite is met; even a met gate + authorizes only wiring/fixture evidence, never a trained-quality claim. + """ + lot1_01 = evaluate_activation_gates(fidelity_contract, trace_gate_contract) + gate_3 = _evaluate_kc_stage_authorization(trace_gate_contract) + + all_met = ( + lot1_01.gate_1_fidelity_authorization.met + and lot1_01.gate_2_trace_oracle_ceiling.met + and gate_3.met + ) + if all_met: + verdict = AUTHORIZED_WIRING_ONLY + rationale = ( + "All LOT1-02 launch prerequisites are met. The curriculum " + "campaign may be wired in fixture/plan-only mode; this gate " + "authorizes no GPU run or semantic-quality claim by itself." + ) + else: + verdict = NOT_AUTHORIZED + unmet = [] + if not lot1_01.gate_1_fidelity_authorization.met: + unmet.append("transfer_authorization (SLM-248)") + if not lot1_01.gate_2_trace_oracle_ceiling.met: + unmet.append("trace_oracle_ceiling (SLM-249)") + if not gate_3.met: + unmet.append("explicit_kc_stage_authorization (SLM-249 allowed_lot1_implementation)") + rationale = ( + "LOT1-02 launch prerequisite(s) unmet: " + ", ".join(unmet) + ". " + f"LOT1-01's disposition is '{lot1_01.verdict}', so no faithful " + "K x c model path or curriculum hooks exist to train; SLM-249's " + "oracle ceiling is not positive and authorizes no LOT1 " + "implementation. There is no treatment arm to run and no matched " + "continued-explicit control to attribute against. Closing " + "not_authorized in plan-only mode; no training, curriculum, or " + "model code is added by this disposition." + ) + + return Lot102LaunchGateV1( + lot1_01_disposition=lot1_01.verdict, + gate_1_transfer_authorization=lot1_01.gate_1_fidelity_authorization, + gate_2_trace_oracle_ceiling=lot1_01.gate_2_trace_oracle_ceiling, + gate_3_explicit_kc_stage_authorization=gate_3, + verdict=verdict, + verdict_rationale=rationale, + version_stamp=build_version_stamp("harness.experiments"), + ) + + +def render_markdown(contract: Lot102LaunchGateV1) -> str: + lines = [ + f"# SLM-251 LOT1-02 — Launch-gate disposition ({contract.contract_id})", + "", + f"Verdict: **{contract.verdict}**", + "", + contract.verdict_rationale, + "", + f"LOT1-01 disposition: `{contract.lot1_01_disposition}`", + "", + ] + for title, gate in ( + ("Gate 1 — transfer authorization (SLM-248)", contract.gate_1_transfer_authorization), + ("Gate 2 — trace oracle ceiling (SLM-249)", contract.gate_2_trace_oracle_ceiling), + ( + "Gate 3 — explicit LOT1 implementation allowance (SLM-249)", + contract.gate_3_explicit_kc_stage_authorization, + ), + ): + if gate is None: + continue + lines += [ + f"## {title}", + "", + f"- Source contract: `{gate.source_contract_id}` (`{gate.source_contract_hash}`)", + f"- Required: {gate.required_verdict}", + f"- Actual verdict: `{gate.actual_verdict}`", + f"- Met: **{gate.met}**", + "", + ] + lines += [ + "## Non-goals honored", + "", + "No training campaign, no curriculum code, no Stage 0 checkpoint, no " + "GPU dispatch, and no production default change. This disposition is " + "itself the LOT1-02 deliverable while the launch prerequisites are unmet.", + "", + ] + return "\n".join(lines) diff --git a/src/slm_training/resources/versions.json b/src/slm_training/resources/versions.json index 7460c151f..756c726d1 100644 --- a/src/slm_training/resources/versions.json +++ b/src/slm_training/resources/versions.json @@ -1716,7 +1716,7 @@ ] }, "harness.experiments": { - "version": "v109", + "version": "v110", "kind": "harness", "paths": [ "src/slm_training/harnesses/experiments/", @@ -1725,6 +1725,11 @@ "tests/test_scripts/test_run_slm298_capacity_context_curriculum.py" ], "history": [ + { + "version": "v110", + "date": "2026-07-25", + "note": "add SLM-251 LOT1-02 launch-gate evaluator (lot1_02_activation_gate.py): reuses the LOT1-01 gate plus SLM-249 allowed_lot1_implementation and closes not_authorized in plan-only mode, no training/curriculum code" + }, { "version": "v109", "date": "2026-07-25", @@ -2336,6 +2341,25 @@ } ] }, + "harness.experiments.lot1_02_activation_gate": { + "version": "v1", + "kind": "gate", + "paths": [ + "src/slm_training/harnesses/experiments/lot1_02_activation_gate.py", + "scripts/evaluate_lot1_02_activation_gate.py", + "tests/test_harnesses/experiments/test_lot1_02_activation_gate.py", + "tests/test_scripts/test_evaluate_lot1_02_activation_gate.py", + "docs/design/iter-slm251-lot1-02-not-authorized-20260725.json", + "docs/design/iter-slm251-lot1-02-not-authorized-20260725.md" + ], + "history": [ + { + "version": "v1", + "date": "2026-07-25", + "note": "initial registration; SLM-251 LOT1-02 launch-gate evaluator closes not_authorized against the real SLM-248/SLM-249 upstream contracts and the LOT1-01 not_authorized disposition" + } + ] + }, "harness.experiments.external_ceiling": { "version": "v2", "kind": "harness", diff --git a/tests/test_harnesses/experiments/test_lot1_02_activation_gate.py b/tests/test_harnesses/experiments/test_lot1_02_activation_gate.py new file mode 100644 index 000000000..0f3390b56 --- /dev/null +++ b/tests/test_harnesses/experiments/test_lot1_02_activation_gate.py @@ -0,0 +1,119 @@ +"""Tests for slm_training.harnesses.experiments.lot1_02_activation_gate (SLM-251).""" + +from __future__ import annotations + +from pathlib import Path + +from slm_training.harnesses.experiments.lot1_01_activation_gate import ( + AUTHORIZED_WIRING_ONLY, + NOT_AUTHORIZED, + REQUIRED_FIDELITY_VERDICT, + REQUIRED_TRACE_VERDICT, + load_upstream_contract, +) +from slm_training.harnesses.experiments.lot1_02_activation_gate import ( + evaluate_lot1_02_launch_gate, + render_markdown, +) + +REPO_ROOT = Path(__file__).resolve().parents[3] +FIDELITY_CONTRACT_PATH = REPO_ROOT / "docs/design/lotus-openui-fidelity-contract-v1.json" +TRACE_GATE_CONTRACT_PATH = REPO_ROOT / "docs/design/compiler-reasoning-trace-v1.json" + + +def test_real_upstream_contracts_are_not_authorized() -> None: + """The currently-committed SLM-248/SLM-249 artifacts must yield + not_authorized: SLM-248 reports needs_target_trace_contract, SLM-249 + reports inconclusive, and its allowed_lot1_implementation authorizes no + LOT1 implementation. This is the load-bearing proof that LOT1-02 + correctly closes without any training or curriculum code. + """ + contract = evaluate_lot1_02_launch_gate( + load_upstream_contract(FIDELITY_CONTRACT_PATH), + load_upstream_contract(TRACE_GATE_CONTRACT_PATH), + ) + + assert contract.verdict == NOT_AUTHORIZED + assert contract.lot1_01_disposition == NOT_AUTHORIZED + assert contract.gate_1_transfer_authorization.met is False + assert contract.gate_2_trace_oracle_ceiling.met is False + assert contract.gate_3_explicit_kc_stage_authorization.met is False + assert "none" in contract.gate_3_explicit_kc_stage_authorization.actual_verdict + + +def test_all_prerequisites_met_authorizes_wiring_only() -> None: + """The evaluator is not hardcoded to always fail: synthetic contracts + with both required verdicts and an explicit LOT1 implementation + allowance flip the disposition, but only to wiring-only authorization. + """ + fidelity_contract = { + "contract_id": "synthetic-fidelity", + "contract_hash": "deadbeef", + "authorization": { + "linear_issue": "SLM-248", + "verdict": REQUIRED_FIDELITY_VERDICT, + "verdict_rationale": "synthetic positive", + }, + } + trace_gate_contract = { + "contract_id": "synthetic-trace", + "contract_hash": "cafef00d", + "gate": { + "linear_issue": "SLM-249", + "verdict": REQUIRED_TRACE_VERDICT, + "verdict_rationale": "synthetic positive", + "allowed_lot1_implementation": [ + "kxc_bounded_implementation: K=6, c=479, stages per contract" + ], + }, + } + + contract = evaluate_lot1_02_launch_gate(fidelity_contract, trace_gate_contract) + + assert contract.verdict == AUTHORIZED_WIRING_ONLY + assert contract.lot1_01_disposition == AUTHORIZED_WIRING_ONLY + assert contract.gate_3_explicit_kc_stage_authorization.met is True + + +def test_explicit_allowance_alone_does_not_authorize() -> None: + """An explicit K/c allowance cannot substitute for the oracle-ceiling + verdict: gate 2 unmet keeps the campaign not_authorized even when + SLM-249 names an allowed implementation. + """ + fidelity_contract = { + "contract_id": "synthetic-fidelity", + "contract_hash": "deadbeef", + "authorization": { + "linear_issue": "SLM-248", + "verdict": REQUIRED_FIDELITY_VERDICT, + "verdict_rationale": "synthetic positive", + }, + } + trace_gate_contract = { + "contract_id": "synthetic-trace", + "contract_hash": "cafef00d", + "gate": { + "linear_issue": "SLM-249", + "verdict": "inconclusive", + "verdict_rationale": "ceiling not measured", + "allowed_lot1_implementation": [ + "kxc_bounded_implementation: K=6, c=479, stages per contract" + ], + }, + } + + contract = evaluate_lot1_02_launch_gate(fidelity_contract, trace_gate_contract) + + assert contract.verdict == NOT_AUTHORIZED + assert contract.gate_3_explicit_kc_stage_authorization.met is True + + +def test_render_markdown_covers_all_gates() -> None: + contract = evaluate_lot1_02_launch_gate( + load_upstream_contract(FIDELITY_CONTRACT_PATH), + load_upstream_contract(TRACE_GATE_CONTRACT_PATH), + ) + markdown = render_markdown(contract) + assert "SLM-251" in markdown + assert "not_authorized" in markdown + assert "Gate 3" in markdown diff --git a/tests/test_scripts/test_evaluate_lot1_02_activation_gate.py b/tests/test_scripts/test_evaluate_lot1_02_activation_gate.py new file mode 100644 index 000000000..a1c019256 --- /dev/null +++ b/tests/test_scripts/test_evaluate_lot1_02_activation_gate.py @@ -0,0 +1,37 @@ +"""Tests for scripts/evaluate_lot1_02_activation_gate.py (SLM-251).""" + +from __future__ import annotations + +import json +from pathlib import Path + +from scripts import evaluate_lot1_02_activation_gate + + +def test_default_run_reports_not_authorized(tmp_path: Path) -> None: + out = tmp_path / "gate" + rc = evaluate_lot1_02_activation_gate.main(["--out", str(out)]) + assert rc == 0 + + data = json.loads((out / "lot1_02_launch_gate.json").read_text()) + assert data["verdict"] == "not_authorized" + assert data["lot1_01_disposition"] == "not_authorized" + assert (out / "lot1_02_launch_gate.md").exists() + + +def test_run_against_explicit_contract_paths(tmp_path: Path) -> None: + out = tmp_path / "gate_explicit" + rc = evaluate_lot1_02_activation_gate.main( + [ + "--fidelity-contract", + "docs/design/lotus-openui-fidelity-contract-v1.json", + "--trace-gate-contract", + "docs/design/compiler-reasoning-trace-v1.json", + "--out", + str(out), + ] + ) + assert rc == 0 + markdown = (out / "lot1_02_launch_gate.md").read_text() + assert "SLM-251" in markdown + assert "not_authorized" in markdown