Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/design/iter-slm252-lot2-01-not-authorized-20260725.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"contract_hash": "b1a3a36449cad0aead49593a1894907ab283d44c6c692ce62c549231eacf8ce9",
"contract_id": "causal-supervision-routing-gate-v1",
"issue": {
"activation_requirement": "SLM-251 (LOT1-02) authorizes LOT2 and provides the selected parent, faithful treatment checkpoint/recipe, continued explicit control, curriculum, and fairness manifests.",
"alias": "LOT2-01",
"gate_contract_id": "causal-supervision-routing-gate-v1",
"linear_issue": "SLM-252",
"slug": "lot2-01-supervision-routing",
"title": "Run the causal supervision routing x timing x grounding factorial"
},
"lot1_01_disposition": "not_authorized",
"lot1_02_disposition": "not_authorized",
"schema_version": "lot_downstream_gate/v1",
"verdict": "not_authorized",
"verdict_rationale": "LOT2-01 (SLM-252) activation requires: SLM-251 (LOT1-02) authorizes LOT2 and provides the selected parent, faithful treatment checkpoint/recipe, continued explicit control, curriculum, and fairness manifests. The LOT1-02 launch gate reports 'not_authorized' (LOT1-01 disposition 'not_authorized'): no faithful K x c model path, curriculum, Stage 0 parent, or continued-explicit control exists, and SLM-249's oracle ceiling is not positive. Closing not_authorized in plan-only/bounded-diagnostic mode; no training, factorial, intervention, or systems code is added by this disposition.",
"version_stamp": {
"code_commit": "e484978344f756a606cc08e0cb5d7961d7447ad8",
"code_dirty": true,
"components": {
"harness.experiments": "v111"
},
"stamp_schema": "version_stamp/v1",
"stamped_at": "2026-07-25T16:05:28.682401+00:00"
}
}
15 changes: 15 additions & 0 deletions docs/design/iter-slm252-lot2-01-not-authorized-20260725.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SLM-252 LOT2-01 — Downstream-gate disposition (causal-supervision-routing-gate-v1)

Verdict: **not_authorized**

LOT2-01 (SLM-252) activation requires: SLM-251 (LOT1-02) authorizes LOT2 and provides the selected parent, faithful treatment checkpoint/recipe, continued explicit control, curriculum, and fairness manifests. The LOT1-02 launch gate reports 'not_authorized' (LOT1-01 disposition 'not_authorized'): no faithful K x c model path, curriculum, Stage 0 parent, or continued-explicit control exists, and SLM-249's oracle ceiling is not positive. Closing not_authorized in plan-only/bounded-diagnostic mode; no training, factorial, intervention, or systems code is added by this disposition.

## Upstream chain

- LOT1-02 launch gate (SLM-251): `not_authorized`
- LOT1-01 activation gate (SLM-250): `not_authorized`
- Activation requirement: SLM-251 (LOT1-02) authorizes LOT2 and provides the selected parent, faithful treatment checkpoint/recipe, continued explicit control, curriculum, and fairness manifests.

## Non-goals honored

No training campaign, factorial, readout/decoder, intervention, systems measurement, or production default change. This disposition is itself the deliverable while the upstream activation gate is unmet.
81 changes: 81 additions & 0 deletions scripts/evaluate_lot_downstream_gate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""Evaluate a LOT2+ issue's downstream activation gate in plan-only mode.

No training, factorial, intervention, or systems code is loaded or run.
Reads the real committed upstream contract artifacts and emits a per-issue
``LotDownstreamGateV1`` disposition.

Example:
python -m scripts.evaluate_lot_downstream_gate --issue SLM-252 \
--out outputs/runs/slm252_downstream_gate
"""

from __future__ import annotations

import argparse
import json
from pathlib import Path

from slm_training.harnesses.experiments.lot_downstream_gate import (
DOWNSTREAM_ISSUES,
evaluate_downstream_gate,
render_markdown,
)
from slm_training.harnesses.experiments.lot1_01_activation_gate import (
load_upstream_contract,
)


def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
description="LOT2+ downstream launch-gate evaluator (plan-only, no campaign code)"
)
parser.add_argument(
"--issue",
required=True,
choices=sorted(DOWNSTREAM_ISSUES),
help="Linear issue id to evaluate (registry: DOWNSTREAM_ISSUES)",
)
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=None,
help="Output directory (default outputs/runs/<issue>_downstream_gate)",
)
args = parser.parse_args(argv)

spec = DOWNSTREAM_ISSUES[args.issue]
out = args.out or Path("outputs/runs") / f"{args.issue.lower()}_downstream_gate"

contract = evaluate_downstream_gate(
spec,
load_upstream_contract(args.fidelity_contract),
load_upstream_contract(args.trace_gate_contract),
)

out.mkdir(parents=True, exist_ok=True)
stem = spec.slug.replace("-", "_")
(out / f"{stem}_gate.json").write_text(
json.dumps(contract.to_dict(), indent=2, sort_keys=True, default=str) + "\n",
encoding="utf-8",
)
markdown = render_markdown(contract)
(out / f"{stem}_gate.md").write_text(markdown, encoding="utf-8")
print(markdown)
return 0


if __name__ == "__main__":
raise SystemExit(main())
186 changes: 186 additions & 0 deletions src/slm_training/harnesses/experiments/lot_downstream_gate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
"""Generic LOT-project downstream launch-gate evaluator (plan-only closeout).

Every LOT2/LOT3/LOT4 issue (SLM-252 … SLM-258) declares the same shape of
activation gate: the LOT1 chain must first authorize it — concretely, the
SLM-251 (LOT1-02) launch gate must be met, which itself requires the
SLM-248 transfer authorization and the SLM-249 oracle ceiling (evaluated
by :mod:`slm_training.harnesses.experiments.lot1_02_activation_gate`).
When the upstream chain is unmet, the downstream issue closes
``not_authorized`` in plan-only/bounded-diagnostic mode with no training,
factorial, intervention, or systems code.

This module evaluates that shared upstream gate once and stamps a
per-issue ``LotDownstreamGateV1`` disposition. It contains no model or
campaign code — evaluating the gate honestly *is* the 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,
)
from slm_training.harnesses.experiments.lot1_02_activation_gate import (
evaluate_lot1_02_launch_gate,
)

__all__ = [
"DOWNSTREAM_ISSUES",
"GATE_SCHEMA_VERSION",
"PENDING_CAMPAIGN_GATE",
"DownstreamIssueSpec",
"LotDownstreamGateV1",
"evaluate_downstream_gate",
"render_markdown",
]

GATE_SCHEMA_VERSION = "lot_downstream_gate/v1"

#: Verdict when the upstream contract chain is met: the issue's own
#: activation still requires the LOT1-02 campaign's published gate
#: (``FaithfulLatentTransferGateV1``), which does not exist until the
#: campaign actually runs. This is never a quality or launch claim.
PENDING_CAMPAIGN_GATE = "upstream_authorized_pending_campaign_gate"


@dataclass(frozen=True)
class DownstreamIssueSpec:
"""Identity of one LOT2+ issue whose activation rides on the LOT1 chain."""

linear_issue: str
alias: str
title: str
gate_contract_id: str
slug: str
activation_requirement: str

def to_dict(self) -> dict[str, Any]:
return dict(asdict(self))


DOWNSTREAM_ISSUES: dict[str, DownstreamIssueSpec] = {
"SLM-252": DownstreamIssueSpec(
linear_issue="SLM-252",
alias="LOT2-01",
title="Run the causal supervision routing x timing x grounding factorial",
gate_contract_id="causal-supervision-routing-gate-v1",
slug="lot2-01-supervision-routing",
activation_requirement=(
"SLM-251 (LOT1-02) authorizes LOT2 and provides the selected "
"parent, faithful treatment checkpoint/recipe, continued explicit "
"control, curriculum, and fairness manifests."
),
),
}


@dataclass(frozen=True)
class LotDownstreamGateV1:
"""Per-issue downstream disposition derived from the LOT1 launch gate."""

schema_version: str = GATE_SCHEMA_VERSION
contract_id: str = ""
issue: DownstreamIssueSpec | None = None
lot1_02_disposition: str = NOT_AUTHORIZED
lot1_01_disposition: str = NOT_AUTHORIZED
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["issue"] = self.issue.to_dict() if self.issue 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,
"issue": self.issue.to_dict() if self.issue is not None else None,
"lot1_02_disposition": self.lot1_02_disposition,
"verdict": self.verdict,
}
return hashlib.sha256(
json.dumps(payload, sort_keys=True, default=str).encode("utf-8")
).hexdigest()


def evaluate_downstream_gate(
spec: DownstreamIssueSpec,
fidelity_contract: dict[str, Any],
trace_gate_contract: dict[str, Any],
) -> LotDownstreamGateV1:
"""Evaluate one LOT2+ issue's activation against real upstream contracts.

The verdict is ``not_authorized`` unless the LOT1-02 launch gate is
met; even then it is only ``upstream_authorized_pending_campaign_gate``
— the issue's own campaign gate must still be published by a real run
before any factorial/intervention/systems work is authorized.
"""
lot1_02 = evaluate_lot1_02_launch_gate(fidelity_contract, trace_gate_contract)

if lot1_02.verdict == AUTHORIZED_WIRING_ONLY:
verdict = PENDING_CAMPAIGN_GATE
rationale = (
"The LOT1 contract-level prerequisites are met, but "
f"{spec.alias} ({spec.linear_issue}) still requires the LOT1-02 "
"campaign's published FaithfulLatentTransferGateV1 with a "
"positive authorization before any objective/architecture work "
"is authorized. No campaign has run; this is not a launch claim."
)
else:
verdict = NOT_AUTHORIZED
rationale = (
f"{spec.alias} ({spec.linear_issue}) activation requires: "
f"{spec.activation_requirement} The LOT1-02 launch gate reports "
f"'{lot1_02.verdict}' (LOT1-01 disposition "
f"'{lot1_02.lot1_01_disposition}'): no faithful K x c model "
"path, curriculum, Stage 0 parent, or continued-explicit control "
"exists, and SLM-249's oracle ceiling is not positive. Closing "
"not_authorized in plan-only/bounded-diagnostic mode; no "
"training, factorial, intervention, or systems code is added by "
"this disposition."
)

return LotDownstreamGateV1(
contract_id=spec.gate_contract_id,
issue=spec,
lot1_02_disposition=lot1_02.verdict,
lot1_01_disposition=lot1_02.lot1_01_disposition,
verdict=verdict,
verdict_rationale=rationale,
version_stamp=build_version_stamp("harness.experiments"),
)


def render_markdown(contract: LotDownstreamGateV1) -> str:
spec = contract.issue
lines = [
f"# {spec.linear_issue} {spec.alias} — Downstream-gate disposition ({contract.contract_id})",
"",
f"Verdict: **{contract.verdict}**",
"",
contract.verdict_rationale,
"",
"## Upstream chain",
"",
f"- LOT1-02 launch gate (SLM-251): `{contract.lot1_02_disposition}`",
f"- LOT1-01 activation gate (SLM-250): `{contract.lot1_01_disposition}`",
f"- Activation requirement: {spec.activation_requirement}",
"",
"## Non-goals honored",
"",
"No training campaign, factorial, readout/decoder, intervention, "
"systems measurement, or production default change. This disposition "
"is itself the deliverable while the upstream activation gate is unmet.",
"",
]
return "\n".join(lines)
31 changes: 30 additions & 1 deletion src/slm_training/resources/versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -1912,7 +1912,7 @@
]
},
"harness.experiments": {
"version": "v117",
"version": "v118",
"kind": "harness",
"paths": [
"scripts/run_slm298_capacity_context_curriculum.py",
Expand All @@ -1921,6 +1921,11 @@
"tests/test_scripts/test_run_slm298_capacity_context_curriculum.py"
],
"history": [
{
"version": "v118",
"date": "2026-07-25",
"note": "add generic LOT2+ downstream launch-gate evaluator (lot_downstream_gate.py) closing SLM-252 LOT2-01 not_authorized off the unmet LOT1-02 launch gate; no campaign code"
},
{
"version": "v117",
"date": "2026-07-25",
Expand Down Expand Up @@ -1976,6 +1981,11 @@
"date": "2026-07-25",
"note": "add SLM-300 AP-015 self-context exposure-bias curriculum manifest, policy-origin-mixture wiring/fixture harness, and mixture-zero legacy-equivalence invariant"
},
{
"version": "v111",
"date": "2026-07-25",
"note": "add generic LOT2+ downstream launch-gate evaluator (lot_downstream_gate.py) closing SLM-252 LOT2-01 not_authorized off the unmet LOT1-02 launch gate; no campaign code"
},
{
"version": "v110",
"date": "2026-07-25",
Expand Down Expand Up @@ -9784,6 +9794,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.lot_downstream_gate": {
"version": "v1",
"kind": "gate",
"paths": [
"src/slm_training/harnesses/experiments/lot_downstream_gate.py",
"scripts/evaluate_lot_downstream_gate.py",
"tests/test_harnesses/experiments/test_lot_downstream_gate.py",
"tests/test_scripts/test_evaluate_lot_downstream_gate.py",
"docs/design/iter-slm252-lot2-01-not-authorized-20260725.json",
"docs/design/iter-slm252-lot2-01-not-authorized-20260725.md"
],
"history": [
{
"version": "v1",
"date": "2026-07-25",
"note": "initial registration; generic LOT2+ downstream gate closes SLM-252 LOT2-01 not_authorized against the real upstream contracts"
}
]
}
}
}
Loading
Loading