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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ connected through SSH local forwarding.
return + facade, keyword-parameter rename, payload-key rename,
env-var rename) are
offline by default.
`--live` skips with exit 0 when Ollama is down; that skip is not a
quality pass. `--require-live` writes `eval-runs/live-status.json`
`{"skipped": true}` and exits 2 so CI can fail closed:
`--live` and `--require-live` write `eval-runs/live-status.json`
`{"skipped": true}` and exit 2 when Ollama is down. A skipped live
check is not success:

```bash
.venv/bin/python scripts/prove_multifile_refactor.py
Expand Down
6 changes: 3 additions & 3 deletions docs/evaluation-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,9 @@ PYTHONPATH=src .venv/bin/python -m unittest discover -s tests -v
GitHub Actions (`.github/workflows/tests.yml`) runs the same no-GPU path on every push.

Live protocol (workstation with Ollama). If the server is down, `--live`
prints `SKIP live` and exits 0. `--require-live` writes
`eval-runs/live-status.json` `{"skipped": true}` and exits 2. That skip
is not a model-quality pass:
and `--require-live` print `SKIP live`, write
`eval-runs/live-status.json` `{"skipped": true}`, and exit 2. A skipped
live check is not success:

```bash
.venv/bin/python scripts/run_eval.py --live --model fast
Expand Down
8 changes: 4 additions & 4 deletions scripts/prove_multifile_refactor.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/usr/bin/env python3
"""Score the harder multi-file refactor corpus.

Default path is offline fixtures (CI / no GPU). ``--live`` calls real
``local_refactor`` through stdio MCP and skips with exit 0 when Ollama
is down. ``--require-live`` is the same path but exits 2 on skip and
writes ``eval-runs/live-status.json``. A skip is not a model-quality pass.
Default path is offline fixtures (CI / no GPU). ``--live`` and
``--require-live`` call real ``local_refactor`` through stdio MCP.
When Ollama is down they write ``eval-runs/live-status.json`` and exit 2.
A skipped live check is not success.
"""

from __future__ import annotations
Expand Down
2 changes: 1 addition & 1 deletion scripts/prove_refactor_acceptance.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Single-file whitespace extract only. For the harder multi-file corpus,
use ``scripts/prove_multifile_refactor.py`` (offline fixtures by default;
``--live`` skips when Ollama is down; ``--require-live`` exits 2).
``--live`` and ``--require-live`` exit 2 when Ollama is down).
"""

from __future__ import annotations
Expand Down
11 changes: 4 additions & 7 deletions scripts/run_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ def _run_fixtures(case_id: str | None, suite: str) -> int:
return failed


async def _run_live(
case_id: str | None, model: str, suite: str, *, require_live: bool
) -> int:
async def _run_live(case_id: str | None, model: str, suite: str) -> int:
from local_coding_slm.ollama_client import OllamaSettings, is_reachable
from local_coding_slm.server import _load_dotenv

Expand All @@ -103,9 +101,9 @@ async def _run_live(
_write_live_status(skipped=True)
print(
f"SKIP live: Ollama unreachable at {settings.host_label()} "
"(offline fixtures still pass; this is not a model-quality fail)"
"(skipped live check is not success)"
)
return 2 if require_live else 0
return 2
_write_live_status(skipped=False)

from mcp import ClientSession, StdioServerParameters
Expand Down Expand Up @@ -160,7 +158,7 @@ def main() -> None:
parser.add_argument(
"--require-live",
action="store_true",
help="Same as --live, but exit 2 when Ollama is down instead of skip-0.",
help="Same as --live. A skipped live check exits 2.",
)
parser.add_argument("--model", choices=("fast", "strong"), default="fast")
parser.add_argument("--case", dest="case_id", default=None)
Expand All @@ -178,7 +176,6 @@ def main() -> None:
args.case_id,
args.model,
args.suite,
require_live=args.require_live,
)
)
)
Expand Down
2 changes: 1 addition & 1 deletion spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ OLLAMA_BASE_URL
│ ├── run_mcp.sh ← project MCP entry (loads .env)
│ ├── prove_acceptance.py
│ ├── prove_refactor_acceptance.py
│ ├── prove_multifile_refactor.py ← harder multi-file suite; --live skip-0, --require-live skip-2
│ ├── prove_multifile_refactor.py ← harder multi-file suite; skipped live exits 2
│ ├── run_eval.py ← fixture corpus; --live on the workstation
│ ├── run_harness.py ← timed MCP campaign (stub or live)
│ └── check_deployment_safety.py ← defensive bind / tag / git checks
Expand Down
2 changes: 1 addition & 1 deletion tests/test_eval_harder.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def test_live_flag_skips_when_ollama_is_down(self) -> None:
text=True,
check=False,
)
self.assertEqual(proc.returncode, 0, proc.stderr)
self.assertEqual(proc.returncode, 2, proc.stderr)
self.assertIn("SKIP live", proc.stdout)

def test_require_live_exits_2_when_ollama_is_down(self) -> None:
Expand Down
44 changes: 44 additions & 0 deletions tests/test_fitness_skipped_live.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Fitness function: the harness must not treat a skipped live check as success."""

from __future__ import annotations

import json
import os
import subprocess
import sys
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]


class SkippedLiveFitnessTests(unittest.TestCase):
def test_skipped_live_check_is_not_success(self) -> None:
env = os.environ.copy()
env["PYTHONPATH"] = str(ROOT / "src") + os.pathsep + env.get("PYTHONPATH", "")
env["OLLAMA_BASE_URL"] = "http://127.0.0.1:1"
status_path = ROOT / "eval-runs" / "live-status.json"
if status_path.exists():
status_path.unlink()
proc = subprocess.run(
[
sys.executable,
str(ROOT / "scripts" / "run_eval.py"),
"--live",
"--case",
"whitespace_extract",
],
cwd=str(ROOT),
env=env,
capture_output=True,
text=True,
check=False,
)
self.assertNotEqual(proc.returncode, 0, proc.stdout + proc.stderr)
self.assertIn("SKIP live", proc.stdout)
payload = json.loads(status_path.read_text(encoding="utf-8"))
self.assertEqual(payload, {"skipped": True})


if __name__ == "__main__":
unittest.main()
Loading