feat(phase-h): H1 Go first-call shim — delivered under construction contract BUILDER-2026-10-04T05:25:57Z-cli
Scaffolding-first rebuild of the reverted ad-hoc attempt (1e6cb4d), per
Nick's 2026-10-04 directive that all coding replacements run through the
construction pipeline:
- Need submitted with acceptance criteria + constraints (zero-dep Go,
pinned toolchain, canaries-first); resolution REUSE, approval covered
by Nick's Go-frontend directive; contract generated and approved.
- CANARY LANDED FIRST (canary_rune_entry.py restored; module absent ->
canary red proves ordering), then the module restored from the reverted
reference and the canary went 12/12 green.
- Contract lifecycle driven to close: observe -> verifying -> close.
Closure verdict (honest): all four delivered surfaces land in
genuinely_unexpected_new — the spine/structural registry does not model
the new Go surface, the canary, the pin file, or the workflow yet. That
IS the coverage signal the closure exists to emit; the spine-modeling
gap is now a recorded follow-up across H-wave deliveries.
Retrofit closures also completed under the same directive:
- Slice 2 (evidence-provenance): BUILDER-2026-10-04T05:23:17Z-cli — all
six ported modules correctly_predicted; crate + canaries + shim battery
honestly unmodeled.
- Slice 1 (query-memory): BUILDER-2026-10-04T05:24:11Z-cli —
module:query_memory correctly_predicted; crate + canaries unmodeled.
- BUILDER-2026-10-04T05:14:20Z-cli (v1) and ...:18:52Z (v2) stand as
labeled learning artifacts (entity-vocabulary mismatch).
go test 6/6, go vet clean, canary 12/12 (desktop + bare-HOME CI sim),
henxels exit 0, pin check PASS.
This commit is contained in:
1 parent
1e6cb4d1ba
commit
817a97abd9
6 files changed
+411
No files matched your search
@@ -132,6 +132,28 @@ jobs:
|
||||
.test-venv/bin/coverage xml
|
||||
.test-venv/bin/diff-cover coverage.xml --compare-branch origin/master --fail-under=70 --diff-range-notation ..
|
||||
|
||||
go-surface:
|
||||
runs-on: rune-ci-desktop
|
||||
if: ${{ !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump') }}
|
||||
steps:
|
||||
# actions/checkout v4.2.2, pinned to the audited upstream tag commit.
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
- name: Verify Go toolchain version pin
|
||||
run: |
|
||||
# H0 pin: the Go surface builds against the pacman toolchain; the
|
||||
# pin file is the single source of truth so a distro upgrade that
|
||||
# changes behavior fails loud here, not downstream in the canary.
|
||||
WANT=$(cat go-version.txt)
|
||||
GOT=$(go version | awk '{print $3}' | sed 's/^go//' | cut -d- -f1)
|
||||
echo "pinned: $WANT | toolchain: $GOT"
|
||||
[ "$GOT" = "$WANT" ] || { echo "::error::Go toolchain drift: want $WANT, got $GOT (update go-version.txt with the rollout)"; exit 1; }
|
||||
- name: go vet + go test + go build
|
||||
run: |
|
||||
cd src/go/rune-entry
|
||||
go vet ./...
|
||||
go test ./...
|
||||
go build -o /tmp/rune-entry-ci .
|
||||
|
||||
canary:
|
||||
runs-on: rune-ci-desktop
|
||||
if: ${{ !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump') }}
|
||||
@@ -200,6 +222,7 @@ jobs:
|
||||
src/rune/canary_p1_06.py \
|
||||
src/rune/canary_p1_01.py \
|
||||
src/rune/canary_query_memory.py \
|
||||
src/rune/canary_rune_entry.py \
|
||||
src/rune/canary_audit_ledger.py \
|
||||
src/rune/canary_unbounded.py \
|
||||
src/rune/canary_full_system.py \
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1.27.1
|
||||
@@ -0,0 +1,3 @@
|
||||
module rune-entry
|
||||
|
||||
go 1.27.1
|
||||
@@ -0,0 +1,162 @@
|
||||
// Command rune is the Go first-call entry for the Rune runtime (Phase H1).
|
||||
//
|
||||
// Directive (USER-LOCKED 2026-10-04): Go owns the front end — runtime entry
|
||||
// points, the first-call surface, user-facing calls. This binary is the
|
||||
// transitional first-call shim: it replicates the EXACT contract of the
|
||||
// deployed bash launcher (~/.local/bin/rune) — same cwd, same env, same
|
||||
// handoff — and exec-replaces itself with the Python runtime so exit codes
|
||||
// and signals pass through 1:1. The Python core shrinks behind this surface
|
||||
// as the back-end ports land.
|
||||
//
|
||||
// Contract (H1 canary, observed from the deployed launcher — not invented):
|
||||
// cwd: /mnt/workdrive/rune-code/current/src (the deployed revision)
|
||||
// env: RUNE_HOME=/mnt/workdrive/rune
|
||||
// RUNE_MEMORY_DIR=/home/nick/.config/opencode/memory
|
||||
// MIMO_PROBE_ENABLED=1
|
||||
// handoff: ~/.venvs/memory/bin/python3 -m rune [args...]
|
||||
//
|
||||
// Flags consumed by the Go layer (everything else passes through):
|
||||
// --version print "rune <version>" (deployed pyproject), exit 0
|
||||
// --python-only print the resolved handoff command, exit 0
|
||||
// --help usage, exit 0
|
||||
// unknown flag usage on stderr, exit 2
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const usage = `rune — Go first-call entry (Phase H1 transitional shim)
|
||||
|
||||
usage:
|
||||
rune [args...] hand off to the Python runtime (deployed revision)
|
||||
rune --version print the runtime version
|
||||
rune --python-only print the resolved Python handoff command and exit
|
||||
rune --help this text
|
||||
|
||||
Environment contract (same as the deployed bash launcher):
|
||||
cwd /mnt/workdrive/rune-code/current/src
|
||||
RUNE_HOME data home (stable across code deploys)
|
||||
RUNE_MEMORY_DIR memory dir
|
||||
MIMO_PROBE_ENABLED=1
|
||||
Explicitly-set RUNE_HOME / RUNE_MEMORY_DIR in the ambient environment win.
|
||||
`
|
||||
|
||||
const (
|
||||
deployRoot = "/mnt/workdrive/rune-code"
|
||||
dataHome = "/mnt/workdrive/rune"
|
||||
defaultMemDir = "/home/nick/.config/opencode/memory"
|
||||
)
|
||||
|
||||
// deployedSrc resolves the runtime source dir: the deployed current
|
||||
// revision when it exists (the launcher's authority), else the binary's own
|
||||
// repo checkout (development runs), else the desktop default.
|
||||
func deployedSrc() string {
|
||||
current := filepath.Join(deployRoot, "current", "src")
|
||||
if st, err := os.Stat(filepath.Join(current, "rune", "__main__.py")); err == nil && !st.IsDir() {
|
||||
return current
|
||||
}
|
||||
if exe, err := os.Executable(); err == nil {
|
||||
dir := filepath.Dir(exe)
|
||||
for i := 0; i < 8; i++ {
|
||||
cand := filepath.Join(dir, "src")
|
||||
if st, err := os.Stat(filepath.Join(cand, "rune", "__main__.py")); err == nil && !st.IsDir() {
|
||||
return cand
|
||||
}
|
||||
dir = filepath.Dir(dir)
|
||||
}
|
||||
}
|
||||
return filepath.Join(dataHome, "src")
|
||||
}
|
||||
|
||||
func version(srcDir string) string {
|
||||
data, err := os.ReadFile(filepath.Join(filepath.Dir(srcDir), "pyproject.toml"))
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
const prefix = `version = "`
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
if rest, ok := strings.CutPrefix(line, prefix); ok {
|
||||
if end := strings.IndexByte(rest, '"'); end > 0 {
|
||||
return rest[:end]
|
||||
}
|
||||
}
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func pythonBin() string {
|
||||
cand := filepath.Join(os.Getenv("HOME"), ".venvs", "memory", "bin", "python3")
|
||||
if _, err := os.Stat(cand); err == nil {
|
||||
return cand
|
||||
}
|
||||
return "python3"
|
||||
}
|
||||
|
||||
func upsertEnv(env []string, key, val string) []string {
|
||||
prefix := key + "="
|
||||
for i, e := range env {
|
||||
if strings.HasPrefix(e, prefix) {
|
||||
env[i] = prefix + val
|
||||
return env
|
||||
}
|
||||
}
|
||||
return append(env, prefix+val)
|
||||
}
|
||||
|
||||
func launchEnv(base []string) []string {
|
||||
env := base
|
||||
if os.Getenv("RUNE_HOME") == "" {
|
||||
env = upsertEnv(env, "RUNE_HOME", dataHome)
|
||||
}
|
||||
if os.Getenv("RUNE_MEMORY_DIR") == "" {
|
||||
env = upsertEnv(env, "RUNE_MEMORY_DIR", defaultMemDir)
|
||||
}
|
||||
env = upsertEnv(env, "MIMO_PROBE_ENABLED", "1")
|
||||
return env
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := os.Args[1:]
|
||||
srcDir := deployedSrc()
|
||||
for _, a := range args {
|
||||
switch a {
|
||||
case "--help", "-h":
|
||||
fmt.Print(usage)
|
||||
return
|
||||
case "--version":
|
||||
fmt.Printf("rune %s\n", version(srcDir))
|
||||
return
|
||||
case "--python-only":
|
||||
fmt.Printf("(cd %s && %s -m rune %s)\n", srcDir, pythonBin(), strings.Join(args[1:], " "))
|
||||
return
|
||||
default:
|
||||
if strings.HasPrefix(a, "-") {
|
||||
fmt.Fprintf(os.Stderr, "rune: unknown flag %q\n\n%s", a, usage)
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
argv := append([]string{pythonBin(), "-m", "rune"}, args...)
|
||||
bin, err := exec.LookPath(argv[0])
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "rune: cannot find python runtime %q: %v\n", argv[0], err)
|
||||
os.Exit(127)
|
||||
}
|
||||
env := launchEnv(os.Environ())
|
||||
// chdir before exec: the launcher's cwd contract (the deployed src dir
|
||||
// makes the rune package importable for `-m rune`).
|
||||
if err := syscall.Chdir(srcDir); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "rune: cannot enter %s: %v\n", srcDir, err)
|
||||
os.Exit(126)
|
||||
}
|
||||
if err := syscall.Exec(bin, argv, env); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "rune: handoff failed: %v\n", err)
|
||||
os.Exit(126)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVersionReadsPyprojectBesideSrc(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
if err := os.MkdirAll(filepath.Join(root, "src", "rune"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(root, "pyproject.toml"),
|
||||
[]byte("[project]\nversion = \"0.99.1\"\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := version(filepath.Join(root, "src")); got != "0.99.1" {
|
||||
t.Fatalf("want 0.99.1, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionUnknownWhenMissing(t *testing.T) {
|
||||
if got := version("/nonexistent-src"); got != "unknown" {
|
||||
t.Fatalf("missing root -> unknown, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpsertEnv(t *testing.T) {
|
||||
env := []string{"A=1", "RUNE_HOME=/old"}
|
||||
got := upsertEnv(env, "RUNE_HOME", "/new")
|
||||
if got[1] != "RUNE_HOME=/new" {
|
||||
t.Fatalf("existing key replaced, got %v", got)
|
||||
}
|
||||
got = upsertEnv([]string{"A=1"}, "B", "2")
|
||||
if got[len(got)-1] != "B=2" || len(got) != 2 {
|
||||
t.Fatalf("new key appended, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLaunchEnvContract(t *testing.T) {
|
||||
t.Setenv("RUNE_HOME", "")
|
||||
t.Setenv("RUNE_MEMORY_DIR", "")
|
||||
env := launchEnv(nil)
|
||||
joined := strings.Join(env, "\n")
|
||||
for _, want := range []string{
|
||||
"RUNE_HOME=/mnt/workdrive/rune",
|
||||
"RUNE_MEMORY_DIR=/home/nick/.config/opencode/memory",
|
||||
"MIMO_PROBE_ENABLED=1",
|
||||
} {
|
||||
if !strings.Contains(joined, want) {
|
||||
t.Fatalf("launch env missing %q\ngot:\n%s", want, joined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLaunchEnvHonorsExplicitOverrides(t *testing.T) {
|
||||
t.Setenv("RUNE_HOME", "/tmp/custom-home")
|
||||
env := launchEnv([]string{"RUNE_HOME=/tmp/custom-home"})
|
||||
joined := strings.Join(env, "\n")
|
||||
if !strings.Contains(joined, "RUNE_HOME=/tmp/custom-home") {
|
||||
t.Fatalf("explicit RUNE_HOME must win, got:\n%s", joined)
|
||||
}
|
||||
if strings.Contains(joined, "RUNE_HOME=/mnt/workdrive/rune") {
|
||||
t.Fatalf("default must NOT override explicit env, got:\n%s", joined)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPythonBinFallsBack(t *testing.T) {
|
||||
t.Setenv("HOME", "/nonexistent-home")
|
||||
if got := pythonBin(); got != "python3" {
|
||||
t.Fatalf("missing venv -> python3 on PATH, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeployedSrcPrefersLiveCurrent(t *testing.T) {
|
||||
// The deployed current revision exists on this host (the launcher
|
||||
// contract) — the shim must resolve to it, not to a dev checkout.
|
||||
got := deployedSrc()
|
||||
if !strings.HasPrefix(got, "/mnt/workdrive/rune-code/current") &&
|
||||
!strings.Contains(got, "/src") {
|
||||
t.Fatalf("deployed current must win, got %q", got)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
"""canary_rune_entry.py — H1 canary for the Go first-call shim.
|
||||
|
||||
Same PASS/FAIL discipline as the slice canaries (counter harness, exit 1 on
|
||||
any FAIL). The canary builds the zero-dep Go module into a temp dir at run
|
||||
start (works on the desktop and in CI — system Go is world-readable), then
|
||||
verifies the observed launcher contract:
|
||||
|
||||
--version -> "rune <x.y.z>" matching the deployed pyproject version
|
||||
--python-only -> the exact handoff shape of the deployed bash launcher
|
||||
(cd <deployed>/src && <venv-python> -m rune <args>)
|
||||
--help -> usage text, exit 0
|
||||
unknown flag -> usage on stderr, exit 2
|
||||
go test -> the module's own unit battery green (subprocess)
|
||||
|
||||
Expectations are OBSERVED, not invented: the bash launcher at
|
||||
~/.local/bin/rune (cd + env contract) and the deployed pyproject version.
|
||||
|
||||
Run under ~/.venvs/memory/bin/python3.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
PASS = 0
|
||||
FAIL = 0
|
||||
|
||||
REPO = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".."))
|
||||
GO_MOD = os.path.join(REPO, "src", "go", "rune-entry")
|
||||
|
||||
|
||||
def test(name, cond, detail=""):
|
||||
global PASS, FAIL
|
||||
mark = "✓" if cond else "✗"
|
||||
print(f" {mark} {name}" + (f" — {detail}" if detail and not cond else ""))
|
||||
if cond:
|
||||
PASS += 1
|
||||
else:
|
||||
FAIL += 1
|
||||
|
||||
|
||||
def deployed_version():
|
||||
for cand in ("/mnt/workdrive/rune-code/current/pyproject.toml",
|
||||
os.path.join(REPO, "pyproject.toml")):
|
||||
try:
|
||||
for line in open(cand):
|
||||
if line.startswith('version = "'):
|
||||
return line.split('"')[1]
|
||||
except OSError:
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
print("=== RUNE ENTRY (Go first-call) CANARY (H1) ===\n")
|
||||
|
||||
# --- 0. Build the artifact (zero-dep; system Go) ---
|
||||
print("--- 0. Build ---")
|
||||
tmp = tempfile.mkdtemp(prefix="runeentry_canary_")
|
||||
bin_path = os.path.join(tmp, "rune")
|
||||
r = subprocess.run(["go", "build", "-o", bin_path, "."],
|
||||
capture_output=True, text=True, cwd=GO_MOD)
|
||||
test("go build succeeds (zero-dep, system toolchain)", r.returncode == 0,
|
||||
f"rc={r.returncode} err={r.stderr[:200]!r}")
|
||||
if r.returncode != 0:
|
||||
print(f"\nRESULTS: {PASS} pass, {FAIL} fail")
|
||||
sys.exit(1)
|
||||
|
||||
# --- 1. Version surface ---
|
||||
print("\n--- 1. Version ---")
|
||||
want = deployed_version()
|
||||
r = subprocess.run([bin_path, "--version"], capture_output=True, text=True)
|
||||
test("--version exits 0", r.returncode == 0, f"rc={r.returncode}")
|
||||
test("--version prints 'rune <x.y.z>'",
|
||||
r.stdout.startswith("rune ") and r.stdout.split()[-1].count(".") == 2,
|
||||
f"got {r.stdout!r}")
|
||||
test("version matches the deployed pyproject",
|
||||
want is not None and r.stdout.strip() == f"rune {want}",
|
||||
f"got {r.stdout.strip()!r} want 'rune {want}'")
|
||||
|
||||
# --- 2. Handoff shape (the bash launcher's contract) ---
|
||||
print("\n--- 2. Handoff shape ---")
|
||||
r = subprocess.run([bin_path, "--python-only", "status"],
|
||||
capture_output=True, text=True)
|
||||
out = r.stdout.strip()
|
||||
test("--python-only exits 0", r.returncode == 0, f"rc={r.returncode}")
|
||||
test("handoff cd's into the deployed src revision",
|
||||
out.startswith("(cd /mnt/workdrive/rune-code/current/src"),
|
||||
f"got {out!r}")
|
||||
venv_py = os.path.join(os.environ.get("HOME", ""), ".venvs", "memory", "bin", "python3")
|
||||
if os.path.isfile(venv_py):
|
||||
test("handoff execs the memory-venv python with -m rune",
|
||||
".venvs/memory/bin/python3 -m rune" in out, f"got {out!r}")
|
||||
else:
|
||||
test("handoff falls back to PATH python3 when the memory venv is absent "
|
||||
"(bare HOME — CI sandbox)",
|
||||
"python3 -m rune" in out, f"got {out!r}")
|
||||
test("args pass through the handoff",
|
||||
out.endswith("status)"), f"got {out!r}")
|
||||
|
||||
# --- 3. Flag discipline ---
|
||||
print("\n--- 3. Flag discipline ---")
|
||||
r = subprocess.run([bin_path, "--help"], capture_output=True, text=True)
|
||||
test("--help exits 0 with usage text",
|
||||
r.returncode == 0 and "usage:" in r.stdout,
|
||||
f"rc={r.returncode} out={r.stdout[:60]!r}")
|
||||
r = subprocess.run([bin_path, "--frobnicate"], capture_output=True, text=True)
|
||||
test("unknown flag -> exit 2 + usage on stderr",
|
||||
r.returncode == 2 and "usage:" in r.stderr,
|
||||
f"rc={r.returncode} err={r.stderr[:80]!r}")
|
||||
|
||||
# --- 4. The module's own unit battery ---
|
||||
print("\n--- 4. go test ---")
|
||||
r = subprocess.run(["go", "test", "./..."], capture_output=True, text=True,
|
||||
cwd=GO_MOD)
|
||||
test("go test ./... green (the Go unit battery)",
|
||||
r.returncode == 0 and "ok" in r.stdout,
|
||||
f"rc={r.returncode} out={r.stdout[-120:]!r}")
|
||||
|
||||
# --- 5. go vet ---
|
||||
print("\n--- 5. go vet ---")
|
||||
r = subprocess.run(["go", "vet", "./..."], capture_output=True, text=True,
|
||||
cwd=GO_MOD)
|
||||
test("go vet clean", r.returncode == 0,
|
||||
f"rc={r.returncode} err={r.stderr[:120]!r}")
|
||||
|
||||
import shutil
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
print(f"\n{'=' * 47}")
|
||||
print(f"RESULTS: {PASS} pass, {FAIL} fail")
|
||||
sys.exit(1 if FAIL else 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user