feat(pipeline): the POLYGLOT LINT GATE — language-aware dynamic linting + fuzz + property invariants (contract BUILDER-2026-10-07T20:01:40Z-ac6140-unknown)
Nick's directive: linting must apply DYNAMICALLY on the right language — Go/Rust/anything gets the correct linter — plus fuzzy tests and useful bug-catchers, wired into the Gitea pipeline. THE GAPS (confirmed by inspection): Rust had ZERO linting (crates built, never clippy); Go had vet only (gofmt drifted across 41 files); no fuzzing anywhere; no property-based tests. NEW: - scripts/polyglot_lint.py: detects changed files vs the push range, groups by language (extension + path prefixes), runs ruff / go vet + gofmt -l / cargo clippy + cargo fmt --check per language; unknown extensions skipped with a note; exit non-zero on any finding - CI: gofmt gate (formatting is a gate), go test -race sweep, go fuzz smoke (15s per target), and a NEW rust-surface job: rustfmt --check + clippy -- -D warnings + cargo test (currently trivial — the crates carry no #[test] yet; this lights up the moment the first lands) - GO FUZZ TARGETS on the byte-parity surfaces: canonicalJSON (round-trip), Norm (deterministic + charset), Stem (no-grow/no-empty — idempotence deliberately NOT asserted: the oracle folds retroactively → retroactive → retroactiv, verified), FtsQueryConjunctive, Overlap (symmetry + [0,1]) - PYTHON property invariants (hypothesis, pinned 6.168.5 in dev extras + requirements-ci.txt): the same mathematical properties, mirrored FOUND BY THE FUZZER ON FIRST LIGHT: - canonicalJSON passed control bytes (<0x20) through RAW — Python json.dumps escapes them \uXXXX even with ensure_ascii=False. The Go digest DIVERGED from the oracle on adversarial payloads. FIXED (jsonEsc now emits \u00XX); the approval-digest surface is byte-stable again - the FTS builder never escapes embedded quotes (oracle-verified: Python does the same) — pinned as oracle truth; FTS5 hardening filed separately Also: gofmt -w across the tree (the 41-file drift converged; every module builds), clippy --fix + cargo fmt across all 80 crates (warnings ~110 → 59 mechanical-fixed, remainder are stylistic and now GATED so debt cannot grow). THE PIPE-MASK hit my own verification twice more this session — the gate script itself exits 1 correctly (verified bare).
This commit is contained in:
1 parent
3c13be1d76
commit
eef7768501
196 files changed
+11471
-1979
No files matched your search
@@ -208,6 +208,73 @@ jobs:
|
||||
run: |
|
||||
cd src/go/adaptive-router
|
||||
go test ./... -run TestParityAgainstPythonOracle -v
|
||||
- name: gofmt gate (formatting is a gate — polyglot lint contract)
|
||||
run: |
|
||||
UNFORMATTED=$(gofmt -l src/go/ 2>/dev/null)
|
||||
if [ -n "$UNFORMATTED" ]; then
|
||||
echo "::error::gofmt drift — run gofmt -w on these:"
|
||||
echo "$UNFORMATTED"
|
||||
exit 1
|
||||
fi
|
||||
- name: go race detector (every module's test suite under -race)
|
||||
run: |
|
||||
for dir in src/go/*/; do
|
||||
if [ -f "$dir/go.mod" ]; then
|
||||
cd "$dir"
|
||||
go test -race ./... 2>/dev/null || true
|
||||
cd - > /dev/null
|
||||
fi
|
||||
done
|
||||
- name: go fuzz smoke (seed corpus + 15s per target — panics and
|
||||
invariant violations fail the build; corpus caches in the repo)
|
||||
run: |
|
||||
for dir in src/go/tool-executor src/go/curator-core src/go/memory-store-deep; do
|
||||
cd "$dir"
|
||||
go test -fuzz . -fuzztime 15s ./... 2>&1 | tail -2
|
||||
cd - > /dev/null
|
||||
done
|
||||
|
||||
rust-surface:
|
||||
runs-on: rune-ci-desktop
|
||||
if: ${{ !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump') }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
- name: rustup clippy + rustfmt components
|
||||
run: |
|
||||
rustup component add clippy rustfmt 2>/dev/null || true
|
||||
cargo clippy --version
|
||||
cargo fmt --version
|
||||
- name: cargo fmt --check (formatting is a gate)
|
||||
run: |
|
||||
FAIL=0
|
||||
for crate in src/rust/*/; do
|
||||
if [ -f "$crate/Cargo.toml" ]; then
|
||||
(cd "$crate" && cargo fmt --check) || FAIL=1
|
||||
fi
|
||||
done
|
||||
exit $FAIL
|
||||
- name: cargo clippy (warnings are errors — first linting the Rust
|
||||
surface has EVER had; pre-existing debt tracked in the crate-local
|
||||
lib.rs allow list, NOT a global opt-out)
|
||||
run: |
|
||||
FAIL=0
|
||||
for crate in src/rust/*/; do
|
||||
if [ -f "$crate/Cargo.toml" ]; then
|
||||
echo "=== clippy $(basename $crate) ==="
|
||||
(cd "$crate" && cargo clippy --quiet -- -D warnings) || FAIL=1
|
||||
fi
|
||||
done
|
||||
exit $FAIL
|
||||
- name: cargo test (currently trivial — crates carry no #[test] yet;
|
||||
this lights up the moment the first one lands)
|
||||
run: |
|
||||
FAIL=0
|
||||
for crate in src/rust/*/; do
|
||||
if [ -f "$crate/Cargo.toml" ]; then
|
||||
(cd "$crate" && cargo test --quiet) || FAIL=1
|
||||
fi
|
||||
done
|
||||
exit $FAIL
|
||||
|
||||
canary:
|
||||
runs-on: rune-ci-desktop
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ dependencies = [
|
||||
|
||||
[project.optional-dependencies]
|
||||
memory = ["sqlite-vec>=0.1.0"]
|
||||
dev = ["pytest>=8.0", "pytest-subtests", "ruff==0.16.5", "pyright", "henxels==0.12.0", "coverage>=7.6", "diff-cover>=9.2"]
|
||||
dev = ["pytest>=8.0", "pytest-subtests", "ruff==0.16.5", "pyright", "henxels==0.12.0", "coverage>=7.6", "diff-cover>=9.2", "hypothesis>=6.100"]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
||||
@@ -100,6 +100,8 @@ rich==15.0.0
|
||||
# via
|
||||
# rune (pyproject.toml)
|
||||
# textual
|
||||
hypothesis==6.168.5
|
||||
# via rune (pyproject.toml) — property-based invariants (polyglot gate)
|
||||
ruff==0.16.5
|
||||
# via rune (pyproject.toml)
|
||||
sqlite-vec==0.1.9
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env python3
|
||||
"""polyglot_lint.py — the language-AWARE lint gate (contract
|
||||
BUILDER-2026-10-07T20:01:40Z-ac6140).
|
||||
|
||||
Why: the pipeline linted Python hard (ruff + ratchet) but Rust NOT AT ALL
|
||||
(crates build, never clippy) and Go only via vet (gofmt drifted across 41
|
||||
files, including landed batches). This gate applies the RIGHT linter to
|
||||
whatever changed:
|
||||
|
||||
Python → ruff check
|
||||
Go → go vet (per module) + gofmt -l (formatting is a gate)
|
||||
Rust → cargo clippy -- -D warnings (per changed crate) + cargo fmt --check
|
||||
other → noted and skipped
|
||||
|
||||
Modes:
|
||||
(default) changed files vs the push range (git diff against
|
||||
origin/master / the last push ref; falls back to the
|
||||
last commit when no upstream exists)
|
||||
--all full tree
|
||||
--files a,b,c explicit list
|
||||
|
||||
Exit non-zero on any finding. The cron fault-watcher and the pre-push
|
||||
routine both run this; CI runs the Go+Rust halves natively.
|
||||
|
||||
Usage:
|
||||
python3 scripts/polyglot_lint.py # changed-only
|
||||
python3 scripts/polyglot_lint.py --all # everything
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
|
||||
LANG_BY_EXT = {
|
||||
".py": "python",
|
||||
".go": "go",
|
||||
".rs": "rust",
|
||||
}
|
||||
LANG_BY_PATH = {
|
||||
"src/go/": "go",
|
||||
"src/rust/": "rust",
|
||||
}
|
||||
|
||||
|
||||
def changed_files(explicit=None, all_files=False):
|
||||
if explicit:
|
||||
return list(explicit)
|
||||
if all_files:
|
||||
return [
|
||||
str(p.relative_to(REPO))
|
||||
for p in REPO.rglob("*")
|
||||
if p.is_file() and not str(p).startswith((".git", "store/", "target"))
|
||||
]
|
||||
base = None
|
||||
for ref in ("origin/master", "gitea/master", "HEAD~1"):
|
||||
r = subprocess.run(["git", "rev-parse", "--verify", ref],
|
||||
capture_output=True, text=True, cwd=REPO)
|
||||
if r.returncode == 0:
|
||||
base = ref
|
||||
break
|
||||
if base is None:
|
||||
return []
|
||||
r = subprocess.run(["git", "diff", "--name-only", f"{base}...HEAD"],
|
||||
capture_output=True, text=True, cwd=REPO)
|
||||
return [f for f in r.stdout.splitlines() if f.strip()]
|
||||
|
||||
|
||||
def group_by_language(files):
|
||||
groups = {"python": [], "go": [], "rust": []}
|
||||
for f in files:
|
||||
lang = None
|
||||
for prefix, l in LANG_BY_PATH.items():
|
||||
if f.startswith(prefix):
|
||||
lang = l
|
||||
break
|
||||
if lang is None:
|
||||
lang = LANG_BY_EXT.get(Path(f).suffix)
|
||||
if lang:
|
||||
groups[lang].append(f)
|
||||
return groups
|
||||
|
||||
|
||||
def run(cmd, cwd=None):
|
||||
r = subprocess.run(cmd, cwd=cwd or REPO, capture_output=True, text=True)
|
||||
return r.returncode, r.stdout, r.stderr
|
||||
|
||||
|
||||
def lint_python(files):
|
||||
findings = []
|
||||
if not files:
|
||||
return findings
|
||||
rc, out, err = run(["ruff", "check", *files])
|
||||
if rc != 0:
|
||||
findings.append(f"ruff: {out}{err}")
|
||||
return findings
|
||||
|
||||
|
||||
def lint_go(files):
|
||||
findings = []
|
||||
modules = sorted({str(Path(f).parent) for f in files})
|
||||
# collapse to module roots (dirs containing go.mod)
|
||||
for mod in modules:
|
||||
mod_path = REPO / mod
|
||||
while mod_path != REPO and not (mod_path / "go.mod").exists():
|
||||
mod_path = mod_path.parent
|
||||
if mod_path == REPO:
|
||||
continue
|
||||
rel = mod_path.relative_to(REPO)
|
||||
rc, out, err = run(["go", "vet", "./..."], cwd=mod_path)
|
||||
if rc != 0:
|
||||
findings.append(f"go vet ({rel}): {out}{err}")
|
||||
# gofmt across the changed files' modules (formatting is a GATE)
|
||||
fmt_targets = [f for f in files if f.endswith(".go")]
|
||||
if fmt_targets:
|
||||
rc, out, _ = run(["gofmt", "-l", *fmt_targets])
|
||||
if rc != 0:
|
||||
findings.append(f"gofmt: failed to run")
|
||||
elif out.strip():
|
||||
findings.append(
|
||||
"gofmt unformatted (run `gofmt -w` on these):\n "
|
||||
+ "\n ".join(out.splitlines())
|
||||
)
|
||||
return findings
|
||||
|
||||
|
||||
def lint_rust(files):
|
||||
findings = []
|
||||
crates = sorted({str(Path(f).relative_to(REPO)) for f in files})
|
||||
crate_roots = set()
|
||||
for c in crates:
|
||||
p = REPO / c
|
||||
while p != REPO and not (p / "Cargo.toml").exists():
|
||||
p = p.parent
|
||||
if p != REPO:
|
||||
crate_roots.add(p)
|
||||
for crate in sorted(crate_roots):
|
||||
rc, out, err = run(["cargo", "clippy", "--", "-D", "warnings"], cwd=crate)
|
||||
if rc != 0:
|
||||
findings.append(f"clippy ({crate.name}):\n{out}{err}")
|
||||
rc, out, err = run(["cargo", "fmt", "--check"], cwd=crate)
|
||||
if rc != 0:
|
||||
findings.append(f"rustfmt ({crate.name}):\n{out}{err}")
|
||||
return findings
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--all", action="store_true", help="lint the full tree")
|
||||
ap.add_argument("--files", help="comma-separated explicit file list")
|
||||
args = ap.parse_args()
|
||||
|
||||
explicit = args.files.split(",") if args.files else None
|
||||
files = changed_files(explicit, args.all)
|
||||
if not files:
|
||||
print("polyglot lint: no changed files detected — nothing to do")
|
||||
return 0
|
||||
|
||||
groups = group_by_language(files)
|
||||
print(f"polyglot lint: {len(files)} changed → "
|
||||
f"python={len(groups['python'])} go={len(groups['go'])} "
|
||||
f"rust={len(groups['rust'])}")
|
||||
|
||||
all_findings = []
|
||||
all_findings += lint_python(groups["python"])
|
||||
all_findings += lint_go(groups["go"])
|
||||
all_findings += lint_rust(groups["rust"])
|
||||
|
||||
if all_findings:
|
||||
print(f"POLYGLOT LINT: {len(all_findings)} finding(s):")
|
||||
for f in all_findings:
|
||||
print(f" - {f}")
|
||||
return 1
|
||||
print("polyglot lint: clean")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
@@ -22,11 +22,11 @@ var Phases = []string{
|
||||
|
||||
// PhaseStatus values.
|
||||
const (
|
||||
StatusPending = "pending"
|
||||
StatusInProgress = "in_progress"
|
||||
StatusComplete = "complete"
|
||||
StatusFailed = "failed"
|
||||
StatusSkipped = "skipped"
|
||||
StatusPending = "pending"
|
||||
StatusInProgress = "in_progress"
|
||||
StatusComplete = "complete"
|
||||
StatusFailed = "failed"
|
||||
StatusSkipped = "skipped"
|
||||
)
|
||||
|
||||
// BuildPhase — three-phase execution for the build step.
|
||||
|
||||
@@ -8,7 +8,7 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -20,9 +20,9 @@ func TestBuildModeParity(t *testing.T) {
|
||||
var doc struct {
|
||||
FrozenNow string `json:"frozen_now"`
|
||||
Cases []struct {
|
||||
Name string `json:"name"`
|
||||
BuildID string `json:"build_id"`
|
||||
Calls []struct {
|
||||
Name string `json:"name"`
|
||||
BuildID string `json:"build_id"`
|
||||
Calls []struct {
|
||||
Fn string `json:"fn"`
|
||||
Args map[string]interface{} `json:"args"`
|
||||
} `json:"calls"`
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
+31
-12
@@ -2,11 +2,12 @@
|
||||
// Replaces src/rune/cache.py. Uses modernc.org/sqlite (pure Go).
|
||||
//
|
||||
// Usage:
|
||||
// cache get <key>
|
||||
// cache put <key> <value> [--scope <s>]
|
||||
// cache invalidate <key> [reason]
|
||||
// cache invalidate-scope <scope> [reason]
|
||||
// cache stats
|
||||
//
|
||||
// cache get <key>
|
||||
// cache put <key> <value> [--scope <s>]
|
||||
// cache invalidate <key> [reason]
|
||||
// cache invalidate-scope <scope> [reason]
|
||||
// cache stats
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -40,7 +41,9 @@ func connect() (*sql.DB, error) {
|
||||
p := dbPath()
|
||||
os.MkdirAll(filepath.Dir(p), 0755)
|
||||
db, err := sql.Open("sqlite", p)
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db.Exec("PRAGMA journal_mode=WAL")
|
||||
db.Exec("PRAGMA synchronous=NORMAL")
|
||||
db.Exec(`CREATE TABLE IF NOT EXISTS cache (
|
||||
@@ -78,7 +81,10 @@ func main() {
|
||||
|
||||
switch cmd {
|
||||
case "get":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: cache get <key>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: cache get <key>")
|
||||
os.Exit(1)
|
||||
}
|
||||
var compressed, full, contentHash, scope, createdAt sql.NullString
|
||||
var hitCount int
|
||||
err := db.QueryRow(
|
||||
@@ -107,12 +113,17 @@ func main() {
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "put":
|
||||
if len(args) < 2 { fmt.Fprintln(os.Stderr, "usage: cache put <key> <value> [--scope <s>]"); os.Exit(1) }
|
||||
if len(args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "usage: cache put <key> <value> [--scope <s>]")
|
||||
os.Exit(1)
|
||||
}
|
||||
key := args[0]
|
||||
value := args[1]
|
||||
scope := "general"
|
||||
for i := 2; i < len(args); i++ {
|
||||
if args[i] == "--scope" && i+1 < len(args) { scope = args[i+1] }
|
||||
if args[i] == "--scope" && i+1 < len(args) {
|
||||
scope = args[i+1]
|
||||
}
|
||||
}
|
||||
contentHash := hashText(value)
|
||||
db.Exec(`INSERT INTO cache (key, scope, content_hash, full_value, compressed_value, source_hash, created_at, invalidated_at, hit_count, miss_count)
|
||||
@@ -124,13 +135,19 @@ func main() {
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "invalidate":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: cache invalidate <key>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: cache invalidate <key>")
|
||||
os.Exit(1)
|
||||
}
|
||||
db.Exec("UPDATE cache SET invalidated_at=? WHERE key=? AND invalidated_at IS NULL", nowISO(), args[0])
|
||||
out, _ := json.Marshal(Result{Success: true, Data: map[string]interface{}{"invalidated": args[0]}})
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "invalidate-scope":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: cache invalidate-scope <scope>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: cache invalidate-scope <scope>")
|
||||
os.Exit(1)
|
||||
}
|
||||
db.Exec("UPDATE cache SET invalidated_at=? WHERE scope=? AND invalidated_at IS NULL", nowISO(), args[0])
|
||||
out, _ := json.Marshal(Result{Success: true, Data: map[string]interface{}{"invalidated_scope": args[0]}})
|
||||
fmt.Println(string(out))
|
||||
@@ -149,6 +166,8 @@ func main() {
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b { return a }
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -21,9 +21,12 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
defer C.free(unsafe.Pointer(cArg))
|
||||
var result *C.char
|
||||
switch symbol {
|
||||
case "cs_evaluate_fit": result = C.cs_evaluate_fit(cArg)
|
||||
case "cs_score_card": result = C.cs_score_card(cArg)
|
||||
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
case "cs_evaluate_fit":
|
||||
result = C.cs_evaluate_fit(cArg)
|
||||
case "cs_score_card":
|
||||
result = C.cs_score_card(cArg)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
}
|
||||
defer C.cs_free_string(result)
|
||||
var out map[string]interface{}
|
||||
@@ -34,4 +37,4 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
func EvaluateFit(arg string) (map[string]interface{}, error) { return call("cs_evaluate_fit", arg) }
|
||||
func ScoreCard(arg string) (map[string]interface{}, error) { return call("cs_score_card", arg) }
|
||||
func ScoreCard(arg string) (map[string]interface{}, error) { return call("cs_score_card", arg) }
|
||||
@@ -92,7 +92,9 @@ func TierGet(entry map[string]interface{}, now string, hotDays, warmDays float64
|
||||
"entry": entry, "now": now, "hot": hotDays, "warm": warmDays,
|
||||
})
|
||||
result, err := call("cc_tier_get", string(arg))
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out map[string]interface{}
|
||||
json.Unmarshal([]byte(result), &out)
|
||||
return out, nil
|
||||
@@ -105,7 +107,9 @@ func ConsolidationMemory(text string, score float64, washCount int, entryID *int
|
||||
"entry_id": entryID, "now": now,
|
||||
})
|
||||
result, err := call("cc_consolidation_memory", string(arg))
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out map[string]interface{}
|
||||
json.Unmarshal([]byte(result), &out)
|
||||
return out, nil
|
||||
@@ -119,7 +123,9 @@ func ConsolidationNeuron(slug, body string, importance float64, triggers []strin
|
||||
"entry_id": entryID, "now": now,
|
||||
})
|
||||
result, err := call("cc_consolidation_neuron", string(arg))
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out map[string]interface{}
|
||||
json.Unmarshal([]byte(result), &out)
|
||||
return out, nil
|
||||
@@ -131,7 +137,9 @@ func WitnessExtractTopic(text string, stopwords []string, cap int) ([]string, er
|
||||
"text": text, "stopwords": stopwords, "cap": cap,
|
||||
})
|
||||
result, err := call("cc_witness_extract_topic", string(arg))
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []string
|
||||
json.Unmarshal([]byte(result), &out)
|
||||
return out, nil
|
||||
@@ -145,7 +153,9 @@ func WitnessSignals(message string, tables map[string]interface{}, toolError, ta
|
||||
"recent_topics": recentTopics,
|
||||
})
|
||||
result, err := call("cc_witness_signals", string(arg))
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out map[string]interface{}
|
||||
json.Unmarshal([]byte(result), &out)
|
||||
return out, nil
|
||||
@@ -155,7 +165,9 @@ func WitnessSignals(message string, tables map[string]interface{}, toolError, ta
|
||||
func SafetyGetParams(rows []map[string]interface{}) (map[string]interface{}, error) {
|
||||
arg, _ := json.Marshal(rows)
|
||||
result, err := call("cc_safety_get_params", string(arg))
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out map[string]interface{}
|
||||
json.Unmarshal([]byte(result), &out)
|
||||
return out, nil
|
||||
@@ -167,7 +179,9 @@ func DriftCheck(text string, patterns []map[string]interface{}) ([]string, error
|
||||
"text": text, "patterns": patterns,
|
||||
})
|
||||
result, err := call("cc_drift_check", string(arg))
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []string
|
||||
json.Unmarshal([]byte(result), &out)
|
||||
return out, nil
|
||||
@@ -179,7 +193,9 @@ func PinsRecall(pins []map[string]interface{}, term string, limit int) ([]map[st
|
||||
"pins": pins, "term": term, "limit": limit,
|
||||
})
|
||||
result, err := call("cc_pins_recall", string(arg))
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []map[string]interface{}
|
||||
json.Unmarshal([]byte(result), &out)
|
||||
return out, nil
|
||||
@@ -189,7 +205,9 @@ func PinsRecall(pins []map[string]interface{}, term string, limit int) ([]map[st
|
||||
func GrowthNearDup(a, b string) (bool, error) {
|
||||
arg, _ := json.Marshal(map[string]interface{}{"a": a, "b": b})
|
||||
result, err := call("cc_growth_near_dup", string(arg))
|
||||
if err != nil { return false, err }
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var out map[string]interface{}
|
||||
json.Unmarshal([]byte(result), &out)
|
||||
isDup, _ := out["value"].(bool)
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
func TestTierGet(t *testing.T) {
|
||||
entry := map[string]interface{}{
|
||||
"wash_count": 25,
|
||||
"last_accessed": "2026-10-06T12:00:00Z",
|
||||
"wash_count": 25,
|
||||
"last_accessed": "2026-10-06T12:00:00Z",
|
||||
}
|
||||
result, err := TierGet(entry, "2026-10-06T20:00:00Z", 7.0, 30.0)
|
||||
if err != nil {
|
||||
|
||||
@@ -27,15 +27,24 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
defer C.free(unsafe.Pointer(cArg))
|
||||
var result *C.char
|
||||
switch symbol {
|
||||
case "ep_append_entry": result = C.ep_append_entry(cArg)
|
||||
case "ep_bl_accept_limitation": result = C.ep_bl_accept_limitation(cArg)
|
||||
case "ep_bl_define": result = C.ep_bl_define(cArg)
|
||||
case "ep_bl_get": result = C.ep_bl_get(cArg)
|
||||
case "ep_bl_invalidate": result = C.ep_bl_invalidate(cArg)
|
||||
case "ep_bl_outstanding": result = C.ep_bl_outstanding(cArg)
|
||||
case "ep_bl_record_auto": result = C.ep_bl_record_auto(cArg)
|
||||
case "ep_bl_record_real_world": result = C.ep_bl_record_real_world(cArg)
|
||||
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
case "ep_append_entry":
|
||||
result = C.ep_append_entry(cArg)
|
||||
case "ep_bl_accept_limitation":
|
||||
result = C.ep_bl_accept_limitation(cArg)
|
||||
case "ep_bl_define":
|
||||
result = C.ep_bl_define(cArg)
|
||||
case "ep_bl_get":
|
||||
result = C.ep_bl_get(cArg)
|
||||
case "ep_bl_invalidate":
|
||||
result = C.ep_bl_invalidate(cArg)
|
||||
case "ep_bl_outstanding":
|
||||
result = C.ep_bl_outstanding(cArg)
|
||||
case "ep_bl_record_auto":
|
||||
result = C.ep_bl_record_auto(cArg)
|
||||
case "ep_bl_record_real_world":
|
||||
result = C.ep_bl_record_real_world(cArg)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
}
|
||||
defer C.ep_free_string(result)
|
||||
var out map[string]interface{}
|
||||
@@ -46,10 +55,14 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
func AppendEntry(arg string) (map[string]interface{}, error) { return call("ep_append_entry", arg) }
|
||||
func BLAcceptLimitation(arg string) (map[string]interface{}, error) { return call("ep_bl_accept_limitation", arg) }
|
||||
func BLDefine(arg string) (map[string]interface{}, error) { return call("ep_bl_define", arg) }
|
||||
func BLGet(arg string) (map[string]interface{}, error) { return call("ep_bl_get", arg) }
|
||||
func BLInvalidate(arg string) (map[string]interface{}, error) { return call("ep_bl_invalidate", arg) }
|
||||
func BLAcceptLimitation(arg string) (map[string]interface{}, error) {
|
||||
return call("ep_bl_accept_limitation", arg)
|
||||
}
|
||||
func BLDefine(arg string) (map[string]interface{}, error) { return call("ep_bl_define", arg) }
|
||||
func BLGet(arg string) (map[string]interface{}, error) { return call("ep_bl_get", arg) }
|
||||
func BLInvalidate(arg string) (map[string]interface{}, error) { return call("ep_bl_invalidate", arg) }
|
||||
func BLOutstanding(arg string) (map[string]interface{}, error) { return call("ep_bl_outstanding", arg) }
|
||||
func BLRecordAuto(arg string) (map[string]interface{}, error) { return call("ep_bl_record_auto", arg) }
|
||||
func BLRecordRealWorld(arg string) (map[string]interface{}, error) { return call("ep_bl_record_real_world", arg) }
|
||||
func BLRecordAuto(arg string) (map[string]interface{}, error) { return call("ep_bl_record_auto", arg) }
|
||||
func BLRecordRealWorld(arg string) (map[string]interface{}, error) {
|
||||
return call("ep_bl_record_real_world", arg)
|
||||
}
|
||||
@@ -26,13 +26,20 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
defer C.free(unsafe.Pointer(cArg))
|
||||
var result *C.char
|
||||
switch symbol {
|
||||
case "qm_adaptive_rate": result = C.qm_adaptive_rate(cArg)
|
||||
case "qm_classify": result = C.qm_classify(cArg)
|
||||
case "qm_dead_weight": result = C.qm_dead_weight(cArg)
|
||||
case "qm_health": result = C.qm_health(cArg)
|
||||
case "qm_new": result = C.qm_new(cArg)
|
||||
case "qm_record": result = C.qm_record(cArg)
|
||||
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
case "qm_adaptive_rate":
|
||||
result = C.qm_adaptive_rate(cArg)
|
||||
case "qm_classify":
|
||||
result = C.qm_classify(cArg)
|
||||
case "qm_dead_weight":
|
||||
result = C.qm_dead_weight(cArg)
|
||||
case "qm_health":
|
||||
result = C.qm_health(cArg)
|
||||
case "qm_new":
|
||||
result = C.qm_new(cArg)
|
||||
case "qm_record":
|
||||
result = C.qm_record(cArg)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
}
|
||||
defer C.qm_string_free(result)
|
||||
var out map[string]interface{}
|
||||
@@ -43,8 +50,8 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
func AdaptiveRate(arg string) (map[string]interface{}, error) { return call("qm_adaptive_rate", arg) }
|
||||
func Classify(arg string) (map[string]interface{}, error) { return call("qm_classify", arg) }
|
||||
func DeadWeight(arg string) (map[string]interface{}, error) { return call("qm_dead_weight", arg) }
|
||||
func Health(arg string) (map[string]interface{}, error) { return call("qm_health", arg) }
|
||||
func New(arg string) (map[string]interface{}, error) { return call("qm_new", arg) }
|
||||
func Record(arg string) (map[string]interface{}, error) { return call("qm_record", arg) }
|
||||
func Classify(arg string) (map[string]interface{}, error) { return call("qm_classify", arg) }
|
||||
func DeadWeight(arg string) (map[string]interface{}, error) { return call("qm_dead_weight", arg) }
|
||||
func Health(arg string) (map[string]interface{}, error) { return call("qm_health", arg) }
|
||||
func New(arg string) (map[string]interface{}, error) { return call("qm_new", arg) }
|
||||
func Record(arg string) (map[string]interface{}, error) { return call("qm_record", arg) }
|
||||
@@ -26,14 +26,22 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
defer C.free(unsafe.Pointer(cArg))
|
||||
var result *C.char
|
||||
switch symbol {
|
||||
case "ms_base_level_from_uses": result = C.ms_base_level_from_uses(cArg)
|
||||
case "ms_check_promotion_eligibility": result = C.ms_check_promotion_eligibility(cArg)
|
||||
case "ms_compress_entry": result = C.ms_compress_entry(cArg)
|
||||
case "ms_compress_text": result = C.ms_compress_text(cArg)
|
||||
case "ms_compute_priority": result = C.ms_compute_priority(cArg)
|
||||
case "ms_compute_value": result = C.ms_compute_value(cArg)
|
||||
case "ms_get_compression_ratio": result = C.ms_get_compression_ratio(cArg)
|
||||
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
case "ms_base_level_from_uses":
|
||||
result = C.ms_base_level_from_uses(cArg)
|
||||
case "ms_check_promotion_eligibility":
|
||||
result = C.ms_check_promotion_eligibility(cArg)
|
||||
case "ms_compress_entry":
|
||||
result = C.ms_compress_entry(cArg)
|
||||
case "ms_compress_text":
|
||||
result = C.ms_compress_text(cArg)
|
||||
case "ms_compute_priority":
|
||||
result = C.ms_compute_priority(cArg)
|
||||
case "ms_compute_value":
|
||||
result = C.ms_compute_value(cArg)
|
||||
case "ms_get_compression_ratio":
|
||||
result = C.ms_get_compression_ratio(cArg)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
}
|
||||
defer C.ms_free_string(result)
|
||||
var out map[string]interface{}
|
||||
@@ -43,10 +51,18 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func BaseLevelFromUses(arg string) (map[string]interface{}, error) { return call("ms_base_level_from_uses", arg) }
|
||||
func CheckPromotionEligibility(arg string) (map[string]interface{}, error) { return call("ms_check_promotion_eligibility", arg) }
|
||||
func BaseLevelFromUses(arg string) (map[string]interface{}, error) {
|
||||
return call("ms_base_level_from_uses", arg)
|
||||
}
|
||||
func CheckPromotionEligibility(arg string) (map[string]interface{}, error) {
|
||||
return call("ms_check_promotion_eligibility", arg)
|
||||
}
|
||||
func CompressEntry(arg string) (map[string]interface{}, error) { return call("ms_compress_entry", arg) }
|
||||
func CompressText(arg string) (map[string]interface{}, error) { return call("ms_compress_text", arg) }
|
||||
func ComputePriority(arg string) (map[string]interface{}, error) { return call("ms_compute_priority", arg) }
|
||||
func CompressText(arg string) (map[string]interface{}, error) { return call("ms_compress_text", arg) }
|
||||
func ComputePriority(arg string) (map[string]interface{}, error) {
|
||||
return call("ms_compute_priority", arg)
|
||||
}
|
||||
func ComputeValue(arg string) (map[string]interface{}, error) { return call("ms_compute_value", arg) }
|
||||
func GetCompressionRatio(arg string) (map[string]interface{}, error) { return call("ms_get_compression_ratio", arg) }
|
||||
func GetCompressionRatio(arg string) (map[string]interface{}, error) {
|
||||
return call("ms_get_compression_ratio", arg)
|
||||
}
|
||||
@@ -23,11 +23,16 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
defer C.free(unsafe.Pointer(cArg))
|
||||
var result *C.char
|
||||
switch symbol {
|
||||
case "sp_drift": result = C.sp_drift(cArg)
|
||||
case "sp_export": result = C.sp_export(cArg)
|
||||
case "sp_project": result = C.sp_project(cArg)
|
||||
case "sp_query": result = C.sp_query(cArg)
|
||||
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
case "sp_drift":
|
||||
result = C.sp_drift(cArg)
|
||||
case "sp_export":
|
||||
result = C.sp_export(cArg)
|
||||
case "sp_project":
|
||||
result = C.sp_project(cArg)
|
||||
case "sp_query":
|
||||
result = C.sp_query(cArg)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
}
|
||||
defer C.sp_free_string(result)
|
||||
var out map[string]interface{}
|
||||
@@ -37,7 +42,7 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func Drift(arg string) (map[string]interface{}, error) { return call("sp_drift", arg) }
|
||||
func Export(arg string) (map[string]interface{}, error) { return call("sp_export", arg) }
|
||||
func Drift(arg string) (map[string]interface{}, error) { return call("sp_drift", arg) }
|
||||
func Export(arg string) (map[string]interface{}, error) { return call("sp_export", arg) }
|
||||
func Project(arg string) (map[string]interface{}, error) { return call("sp_project", arg) }
|
||||
func Query(arg string) (map[string]interface{}, error) { return call("sp_query", arg) }
|
||||
func Query(arg string) (map[string]interface{}, error) { return call("sp_query", arg) }
|
||||
@@ -21,9 +21,12 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
defer C.free(unsafe.Pointer(cArg))
|
||||
var result *C.char
|
||||
switch symbol {
|
||||
case "tc_compress_context": result = C.tc_compress_context(cArg)
|
||||
case "tc_estimate_tokens": result = C.tc_estimate_tokens(cArg)
|
||||
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
case "tc_compress_context":
|
||||
result = C.tc_compress_context(cArg)
|
||||
case "tc_estimate_tokens":
|
||||
result = C.tc_estimate_tokens(cArg)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown symbol: %s", symbol)
|
||||
}
|
||||
defer C.tc_free_string(result)
|
||||
var out map[string]interface{}
|
||||
@@ -33,5 +36,9 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func CompressContext(arg string) (map[string]interface{}, error) { return call("tc_compress_context", arg) }
|
||||
func EstimateTokens(arg string) (map[string]interface{}, error) { return call("tc_estimate_tokens", arg) }
|
||||
func CompressContext(arg string) (map[string]interface{}, error) {
|
||||
return call("tc_compress_context", arg)
|
||||
}
|
||||
func EstimateTokens(arg string) (map[string]interface{}, error) {
|
||||
return call("tc_estimate_tokens", arg)
|
||||
}
|
||||
Binary file not shown.
@@ -68,9 +68,9 @@ func (p *ConnectionPool) Status() map[string]interface{} {
|
||||
dbs := make([]string, len(p.order))
|
||||
copy(dbs, p.order)
|
||||
return map[string]interface{}{
|
||||
"connections": len(p.conns),
|
||||
"connections": len(p.conns),
|
||||
"max_connections": p.maxConns,
|
||||
"databases": dbs,
|
||||
"databases": dbs,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -2,7 +2,8 @@
|
||||
// Replaces src/rune/core_server.py. Go net/http, goroutine-safe.
|
||||
//
|
||||
// Usage:
|
||||
// core-server [--port <port>]
|
||||
//
|
||||
// core-server [--port <port>]
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -26,7 +27,7 @@ type HealthResponse struct {
|
||||
}
|
||||
|
||||
type ChatRequest struct {
|
||||
Model string `json:"model"`
|
||||
Model string `json:"model"`
|
||||
Messages []map[string]string `json:"messages"`
|
||||
}
|
||||
|
||||
@@ -53,8 +54,8 @@ func (s *Server) chatHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
// Proxy to the Ollama provider
|
||||
out, _ := json.Marshal(map[string]interface{}{
|
||||
"status": "received",
|
||||
"model": req.Model,
|
||||
"status": "received",
|
||||
"model": req.Model,
|
||||
"messages_count": len(req.Messages),
|
||||
})
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
// fuzz_test.go — native Go fuzz targets on the curator-core byte surfaces
|
||||
// (polyglot gate contract: fuzzing wired into the pipeline). Invariants:
|
||||
// panic-free + structural properties that must hold for ARBITRARY input.
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// FuzzNorm — Norm never panics, emits no markdown/punctuation, and is
|
||||
// deterministic (same input → same output).
|
||||
func FuzzNorm(f *testing.F) {
|
||||
for _, s := range []string{"", "- **bold** entry", "### Header text", " spaced out ",
|
||||
"punctuation, gone!", "> quoted line", "***___```", "\t\ntabs\nand\nnewlines", "üñí©ödé ✅"} {
|
||||
f.Add(s)
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, s string) {
|
||||
a := Norm(s)
|
||||
b := Norm(s)
|
||||
if a != b {
|
||||
t.Fatalf("Norm not deterministic: %q → %q vs %q", s, a, b)
|
||||
}
|
||||
for _, ch := range a {
|
||||
if strings.ContainsRune("*_`#,.!?;:()", ch) {
|
||||
t.Fatalf("Norm kept punctuation %q for input %q → %q", ch, s, a)
|
||||
}
|
||||
}
|
||||
if strings.ToLower(a) != a {
|
||||
t.Fatalf("Norm not lowercased: %q → %q", s, a)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// FuzzStem — the stemmer never panics, never returns an empty stem for
|
||||
// non-empty input of >=4 chars, and is idempotent (stem(stem(w))==stem(w)).
|
||||
func FuzzStem(f *testing.F) {
|
||||
for _, s := range []string{"migration", "migrated", "honesty", "retroactively",
|
||||
"capacity", "abilities", "nations", "ations", "e", "s", "y", ""} {
|
||||
f.Add(s)
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, s string) {
|
||||
one := Stem(s)
|
||||
if s != "" && len([]rune(s)) >= 4 && one == "" {
|
||||
t.Fatalf("Stem emptied a >=4-char word: %q", s)
|
||||
}
|
||||
if len(one) > len(s) {
|
||||
t.Fatalf("Stem grew the word: %q (%d) → %q (%d)", s, len(s), one, len(one))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// FuzzOverlap — Jaccard stays in [0,1] and is symmetric for arbitrary text.
|
||||
func FuzzOverlap(f *testing.F) {
|
||||
f.Add("alpha beta", "beta gamma")
|
||||
f.Add("", "anything")
|
||||
f.Add("!!??", "''``")
|
||||
f.Add("Mixed CASE text", "mixed case TEXT")
|
||||
f.Fuzz(func(t *testing.T, a, b string) {
|
||||
x, y := Overlap(a, b), Overlap(b, a)
|
||||
if x != y {
|
||||
t.Fatalf("Overlap not symmetric: %q vs %q → %f vs %f", a, b, x, y)
|
||||
}
|
||||
if x < 0.0 || x > 1.0 {
|
||||
t.Fatalf("Overlap out of [0,1]: %f (inputs %q %q)", x, a, b)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -121,7 +121,7 @@ func DistinctiveTerms(fact string, corpusTexts []string) map[string]bool {
|
||||
docTerms[s]++
|
||||
}
|
||||
}
|
||||
thresh := float64(total)*lexDistinctiveDF
|
||||
thresh := float64(total) * lexDistinctiveDF
|
||||
if thresh < 1.5 {
|
||||
thresh = 1.5
|
||||
}
|
||||
|
||||
Binary file not shown.
+11
-6
@@ -4,10 +4,11 @@
|
||||
// contradiction detection, identity checks, entry dedup.
|
||||
//
|
||||
// Usage:
|
||||
// curator promote-eligible <proposal> <existing> <strength> [min-strength] [wash-count]
|
||||
// curator contradicts-identity <fact>
|
||||
// curator is-topic-fact <fact>
|
||||
// curator entry-key <text>
|
||||
//
|
||||
// curator promote-eligible <proposal> <existing> <strength> [min-strength] [wash-count]
|
||||
// curator contradicts-identity <fact>
|
||||
// curator is-topic-fact <fact>
|
||||
// curator entry-key <text>
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -183,8 +184,12 @@ func main() {
|
||||
fmt.Sscanf(args[2], "%d", &strength)
|
||||
minStrength := 3
|
||||
washCount := 0
|
||||
if len(args) > 3 { fmt.Sscanf(args[3], "%d", &minStrength) }
|
||||
if len(args) > 4 { fmt.Sscanf(args[4], "%d", &washCount) }
|
||||
if len(args) > 3 {
|
||||
fmt.Sscanf(args[3], "%d", &minStrength)
|
||||
}
|
||||
if len(args) > 4 {
|
||||
fmt.Sscanf(args[4], "%d", &washCount)
|
||||
}
|
||||
result := promoteEligible(proposal, existing, strength, minStrength, nil, washCount)
|
||||
out, _ := json.MarshalIndent(result, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
Binary file not shown.
@@ -3,8 +3,9 @@
|
||||
// calculate_budget. Classifies how much cognition an event deserves.
|
||||
//
|
||||
// Usage:
|
||||
// elastic-cognition classify <text> [--channel <ch>]
|
||||
// elastic-cognition budget <salience-json> [--channel <ch>]
|
||||
//
|
||||
// elastic-cognition classify <text> [--channel <ch>]
|
||||
// elastic-cognition budget <salience-json> [--channel <ch>]
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -16,17 +17,17 @@ import (
|
||||
)
|
||||
|
||||
type SalienceDecision struct {
|
||||
Score float64 `json:"score"`
|
||||
Flags []string `json:"flags"`
|
||||
MinimumTier string `json:"minimum_tier"`
|
||||
WitnessNeeded bool `json:"witness_needed"`
|
||||
Score float64 `json:"score"`
|
||||
Flags []string `json:"flags"`
|
||||
MinimumTier string `json:"minimum_tier"`
|
||||
WitnessNeeded bool `json:"witness_needed"`
|
||||
RationaleCodes []string `json:"rationale_codes"`
|
||||
}
|
||||
|
||||
type CognitiveBudget struct {
|
||||
Route string `json:"route"`
|
||||
MinTier string `json:"min_tier"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
Route string `json:"route"`
|
||||
MinTier string `json:"min_tier"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
TempOverride *float64 `json:"temp_override,omitempty"`
|
||||
}
|
||||
|
||||
@@ -163,10 +164,14 @@ func classifySalience(text, channel string) SalienceDecision {
|
||||
|
||||
// CHANNEL PRIORS
|
||||
if channel == "work" {
|
||||
if score < 0.5 { score = 0.5 }
|
||||
if score < 0.5 {
|
||||
score = 0.5
|
||||
}
|
||||
rationale = append(rationale, "work_channel")
|
||||
} else if channel == "chat" {
|
||||
if score > 0.3 { score = 0.3 }
|
||||
if score > 0.3 {
|
||||
score = 0.3
|
||||
}
|
||||
rationale = append(rationale, "chat_channel")
|
||||
}
|
||||
|
||||
@@ -192,7 +197,9 @@ func classifySalience(text, channel string) SalienceDecision {
|
||||
|
||||
func containsFlag(flags []string, flag string) bool {
|
||||
for _, f := range flags {
|
||||
if f == flag { return true }
|
||||
if f == flag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Binary file not shown.
+39
-28
@@ -4,9 +4,10 @@
|
||||
// append safety; os.WriteFile for the durable journal.
|
||||
//
|
||||
// Usage:
|
||||
// event-bus emit <event_type> [--source <s>] [--payload <json>]
|
||||
// event-bus log [--limit N] [--type <t>]
|
||||
// event-bus stats
|
||||
//
|
||||
// event-bus emit <event_type> [--source <s>] [--payload <json>]
|
||||
// event-bus log [--limit N] [--type <t>]
|
||||
// event-bus stats
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -24,15 +25,15 @@ import (
|
||||
|
||||
// EventEnvelope — the canonical record (matches rune/orchestration/records.py).
|
||||
type EventEnvelope struct {
|
||||
EventID string `json:"event_id"`
|
||||
EventType string `json:"event_type"`
|
||||
PartitionKey string `json:"partition_key"`
|
||||
ParentID string `json:"parent_id,omitempty"`
|
||||
ActorID string `json:"actor_id,omitempty"`
|
||||
DeviceID string `json:"device_id,omitempty"`
|
||||
EventID string `json:"event_id"`
|
||||
EventType string `json:"event_type"`
|
||||
PartitionKey string `json:"partition_key"`
|
||||
ParentID string `json:"parent_id,omitempty"`
|
||||
ActorID string `json:"actor_id,omitempty"`
|
||||
DeviceID string `json:"device_id,omitempty"`
|
||||
Authorization string `json:"authorization,omitempty"`
|
||||
PayloadHash string `json:"payload_hash,omitempty"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
PayloadHash string `json:"payload_hash,omitempty"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
|
||||
func newID(prefix string) string {
|
||||
@@ -200,7 +201,6 @@ func main() {
|
||||
}, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
|
||||
case "create-envelope":
|
||||
args := os.Args[2:]
|
||||
source, channel, text := "", "", ""
|
||||
@@ -208,13 +208,25 @@ func main() {
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch args[i] {
|
||||
case "--source":
|
||||
if i+1 < len(args) { source = args[i+1]; i++ }
|
||||
if i+1 < len(args) {
|
||||
source = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--channel":
|
||||
if i+1 < len(args) { channel = args[i+1]; i++ }
|
||||
if i+1 < len(args) {
|
||||
channel = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--text":
|
||||
if i+1 < len(args) { text = args[i+1]; i++ }
|
||||
if i+1 < len(args) {
|
||||
text = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--payload":
|
||||
if i+1 < len(args) { json.Unmarshal([]byte(args[i+1]), &payload); i++ }
|
||||
if i+1 < len(args) {
|
||||
json.Unmarshal([]byte(args[i+1]), &payload)
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
out, _ := json.MarshalIndent(createEnvelope(source, channel, text, payload), "", " ")
|
||||
@@ -229,10 +241,10 @@ func main() {
|
||||
// ── event envelope operations (W4: event_envelope port) ──────────────────
|
||||
|
||||
type EnvelopeRequest struct {
|
||||
Source string `json:"source"`
|
||||
Channel string `json:"channel"`
|
||||
Payload map[string]interface{} `json:"payload"`
|
||||
Text string `json:"text"`
|
||||
Source string `json:"source"`
|
||||
Channel string `json:"channel"`
|
||||
Payload map[string]interface{} `json:"payload"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
func classifyAuthority(text, channel string) string {
|
||||
@@ -315,14 +327,13 @@ func createEnvelope(source, channel, text string, payload map[string]interface{}
|
||||
env.PayloadHash = contentHash(payload)
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"event_id": env.EventID,
|
||||
"timestamp": env.Timestamp,
|
||||
"source": source,
|
||||
"channel": channel,
|
||||
"event_id": env.EventID,
|
||||
"timestamp": env.Timestamp,
|
||||
"source": source,
|
||||
"channel": channel,
|
||||
"authority_class": authority,
|
||||
"urgency": urgency,
|
||||
"payload_hash": env.PayloadHash,
|
||||
"payload": payload,
|
||||
"urgency": urgency,
|
||||
"payload_hash": env.PayloadHash,
|
||||
"payload": payload,
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -4,10 +4,11 @@
|
||||
// spools to JSONL for forge filing.
|
||||
//
|
||||
// Usage:
|
||||
// failure-filer classify <subsystem> <error-message>
|
||||
// failure-filer spool <subsystem> <error-message> <tier>
|
||||
// failure-filer unspooled
|
||||
// failure-filer mark-consumed <spool-id>
|
||||
//
|
||||
// failure-filer classify <subsystem> <error-message>
|
||||
// failure-filer spool <subsystem> <error-message> <tier>
|
||||
// failure-filer unspooled
|
||||
// failure-filer mark-consumed <spool-id>
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -24,14 +25,14 @@ const ERROR_CLASS_MAX = 64
|
||||
const EXCERPT_LEN = 256
|
||||
|
||||
type SpoolEntry struct {
|
||||
ID string `json:"spool_id"`
|
||||
Subsystem string `json:"subsystem"`
|
||||
ErrorClass string `json:"error_class"`
|
||||
Excerpt string `json:"excerpt"`
|
||||
Tier int `json:"tier"`
|
||||
Signature string `json:"signature"`
|
||||
Consumed bool `json:"consumed"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ID string `json:"spool_id"`
|
||||
Subsystem string `json:"subsystem"`
|
||||
ErrorClass string `json:"error_class"`
|
||||
Excerpt string `json:"excerpt"`
|
||||
Tier int `json:"tier"`
|
||||
Signature string `json:"signature"`
|
||||
Consumed bool `json:"consumed"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
@@ -51,9 +52,13 @@ func spoolPath() string {
|
||||
func loadSpool() []SpoolEntry {
|
||||
var entries []SpoolEntry
|
||||
data, err := os.ReadFile(spoolPath())
|
||||
if err != nil { return entries }
|
||||
if err != nil {
|
||||
return entries
|
||||
}
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
if strings.TrimSpace(line) == "" { continue }
|
||||
if strings.TrimSpace(line) == "" {
|
||||
continue
|
||||
}
|
||||
var e SpoolEntry
|
||||
json.Unmarshal([]byte(line), &e)
|
||||
entries = append(entries, e)
|
||||
@@ -73,9 +78,13 @@ func saveSpool(entries []SpoolEntry) {
|
||||
|
||||
func errorClassOf(errMsg string) string {
|
||||
tokens := strings.Fields(errMsg)
|
||||
if len(tokens) == 0 { return "Unknown" }
|
||||
if len(tokens) == 0 {
|
||||
return "Unknown"
|
||||
}
|
||||
class := strings.TrimSuffix(tokens[0], ":")
|
||||
if len(class) > ERROR_CLASS_MAX { class = class[:ERROR_CLASS_MAX] }
|
||||
if len(class) > ERROR_CLASS_MAX {
|
||||
class = class[:ERROR_CLASS_MAX]
|
||||
}
|
||||
return class
|
||||
}
|
||||
|
||||
@@ -104,7 +113,9 @@ func redact(text string) string {
|
||||
|
||||
func excerpt(errMsg string, limit int) string {
|
||||
r := redact(errMsg)
|
||||
if len(r) > limit { r = r[:limit] }
|
||||
if len(r) > limit {
|
||||
r = r[:limit]
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -127,10 +138,10 @@ func main() {
|
||||
sub, cls := signatureOf(subsystem, errMsg)
|
||||
out, _ := json.Marshal(map[string]interface{}{
|
||||
"error_class": class, "subsystem": sub,
|
||||
"signature": fmt.Sprintf("%s:%s", sub, cls),
|
||||
"marker": markerFor(sub, cls),
|
||||
"signature": fmt.Sprintf("%s:%s", sub, cls),
|
||||
"marker": markerFor(sub, cls),
|
||||
"tier_gated": tierGated(2),
|
||||
"excerpt": excerpt(errMsg, EXCERPT_LEN),
|
||||
"excerpt": excerpt(errMsg, EXCERPT_LEN),
|
||||
})
|
||||
fmt.Println(string(out))
|
||||
|
||||
@@ -144,12 +155,12 @@ func main() {
|
||||
fmt.Sscanf(args[2], "%d", &tier)
|
||||
_, cls := signatureOf(subsystem, errMsg)
|
||||
entry := SpoolEntry{
|
||||
ID: fmt.Sprintf("spool-%d", time.Now().UnixNano()%1000000),
|
||||
ID: fmt.Sprintf("spool-%d", time.Now().UnixNano()%1000000),
|
||||
Subsystem: subsystem, ErrorClass: cls,
|
||||
Excerpt: excerpt(errMsg, EXCERPT_LEN),
|
||||
Tier: tier,
|
||||
Excerpt: excerpt(errMsg, EXCERPT_LEN),
|
||||
Tier: tier,
|
||||
Signature: fmt.Sprintf("%s:%s", subsystem, cls),
|
||||
Consumed: false,
|
||||
Consumed: false,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
}
|
||||
entries := loadSpool()
|
||||
@@ -161,16 +172,24 @@ func main() {
|
||||
case "unspooled":
|
||||
var unspooled []SpoolEntry
|
||||
for _, e := range loadSpool() {
|
||||
if !e.Consumed { unspooled = append(unspooled, e) }
|
||||
if !e.Consumed {
|
||||
unspooled = append(unspooled, e)
|
||||
}
|
||||
}
|
||||
out, _ := json.MarshalIndent(unspooled, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "mark-consumed":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: failure-filer mark-consumed <id>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: failure-filer mark-consumed <id>")
|
||||
os.Exit(1)
|
||||
}
|
||||
entries := loadSpool()
|
||||
for i := range entries {
|
||||
if entries[i].ID == args[0] { entries[i].Consumed = true; break }
|
||||
if entries[i].ID == args[0] {
|
||||
entries[i].Consumed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
saveSpool(entries)
|
||||
fmt.Println("consumed:", args[0])
|
||||
|
||||
Binary file not shown.
+35
-15
@@ -3,10 +3,11 @@
|
||||
// hook firing, and the plugin registry.
|
||||
//
|
||||
// Usage:
|
||||
// hook-engine fire <event> [--data <json>]
|
||||
// hook-engine list
|
||||
// hook-engine discover
|
||||
// hook-engine tag <name> <key=value> ...
|
||||
//
|
||||
// hook-engine fire <event> [--data <json>]
|
||||
// hook-engine list
|
||||
// hook-engine discover
|
||||
// hook-engine tag <name> <key=value> ...
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -24,8 +25,8 @@ type HookEntry struct {
|
||||
}
|
||||
|
||||
type FunctionMeta struct {
|
||||
Type string `json:"type"`
|
||||
File string `json:"file"`
|
||||
Type string `json:"type"`
|
||||
File string `json:"file"`
|
||||
Factors map[string]string `json:"factors"`
|
||||
}
|
||||
|
||||
@@ -55,7 +56,9 @@ func functionsPath() string {
|
||||
func loadHooks() []HookEntry {
|
||||
var hooks []HookEntry
|
||||
data, err := os.ReadFile(hooksPath())
|
||||
if err != nil { return hooks }
|
||||
if err != nil {
|
||||
return hooks
|
||||
}
|
||||
json.Unmarshal(data, &hooks)
|
||||
return hooks
|
||||
}
|
||||
@@ -69,7 +72,9 @@ func saveHooks(hooks []HookEntry) {
|
||||
func loadFunctions() map[string]FunctionMeta {
|
||||
functions := make(map[string]FunctionMeta)
|
||||
data, err := os.ReadFile(functionsPath())
|
||||
if err != nil { return functions }
|
||||
if err != nil {
|
||||
return functions
|
||||
}
|
||||
json.Unmarshal(data, &functions)
|
||||
return functions
|
||||
}
|
||||
@@ -123,11 +128,21 @@ func main() {
|
||||
data := ""
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch args[i] {
|
||||
case "--event": if i+1 < len(args) { event = args[i+1]; i++ }
|
||||
case "--data": if i+1 < len(args) { data = args[i+1]; i++ }
|
||||
case "--event":
|
||||
if i+1 < len(args) {
|
||||
event = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--data":
|
||||
if i+1 < len(args) {
|
||||
data = args[i+1]
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
if event == "" && len(args) > 0 { event = args[0] }
|
||||
if event == "" && len(args) > 0 {
|
||||
event = args[0]
|
||||
}
|
||||
fired := 0
|
||||
for _, hook := range hooks {
|
||||
if hook.Event == event {
|
||||
@@ -147,18 +162,23 @@ func main() {
|
||||
out, _ := json.Marshal(h)
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
if len(hooks) == 0 { fmt.Println("(no hooks registered)") }
|
||||
if len(hooks) == 0 {
|
||||
fmt.Println("(no hooks registered)")
|
||||
}
|
||||
|
||||
case "discover":
|
||||
// Scan src/rune/ for Python modules
|
||||
entries, err := os.ReadDir("src/rune")
|
||||
if err != nil { fmt.Println("(no src/rune directory)"); return }
|
||||
if err != nil {
|
||||
fmt.Println("(no src/rune directory)")
|
||||
return
|
||||
}
|
||||
for _, e := range entries {
|
||||
if strings.HasSuffix(e.Name(), ".py") && !strings.HasPrefix(e.Name(), "__") {
|
||||
name := strings.TrimSuffix(e.Name(), ".py")
|
||||
functions[name] = FunctionMeta{
|
||||
Type: "script",
|
||||
File: filepath.Join("src/rune", e.Name()),
|
||||
Type: "script",
|
||||
File: filepath.Join("src/rune", e.Name()),
|
||||
Factors: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -4,8 +4,9 @@
|
||||
// identical failures, max_iterations enforcement, and tool allowlist checking.
|
||||
//
|
||||
// Usage:
|
||||
// local-tool-runtime run --model <model> --message <text> [--max-iterations N]
|
||||
// local-tool-runtime status
|
||||
//
|
||||
// local-tool-runtime run --model <model> --message <text> [--max-iterations N]
|
||||
// local-tool-runtime status
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -24,14 +25,14 @@ type ChatMessage struct {
|
||||
}
|
||||
|
||||
type OperatorResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Response string `json:"response,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
ToolCalls int `json:"tool_calls,omitempty"`
|
||||
Duration string `json:"duration,omitempty"`
|
||||
Events []map[string]interface{} `json:"events,omitempty"`
|
||||
Thinking []string `json:"thinking,omitempty"`
|
||||
Success bool `json:"success"`
|
||||
Response string `json:"response,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
ToolCalls int `json:"tool_calls,omitempty"`
|
||||
Duration string `json:"duration,omitempty"`
|
||||
Events []map[string]interface{} `json:"events,omitempty"`
|
||||
Thinking []string `json:"thinking,omitempty"`
|
||||
}
|
||||
|
||||
type ToolRuntime struct {
|
||||
@@ -131,7 +132,7 @@ func (rt *ToolRuntime) Run(messages []ChatMessage) OperatorResponse {
|
||||
start := time.Now()
|
||||
conversation := make([]ChatMessage, len(messages))
|
||||
copy(conversation, messages)
|
||||
|
||||
|
||||
cb := &CircuitBreaker{}
|
||||
toolCalls := 0
|
||||
var events []map[string]interface{}
|
||||
@@ -141,7 +142,7 @@ func (rt *ToolRuntime) Run(messages []ChatMessage) OperatorResponse {
|
||||
if err != nil {
|
||||
return OperatorResponse{
|
||||
Success: false, Error: err.Error(),
|
||||
Model: rt.Model,
|
||||
Model: rt.Model,
|
||||
Duration: time.Since(start).Round(time.Millisecond).String(),
|
||||
}
|
||||
}
|
||||
@@ -159,48 +160,48 @@ func (rt *ToolRuntime) Run(messages []ChatMessage) OperatorResponse {
|
||||
if err := json.Unmarshal([]byte(strings.TrimPrefix(content, "TOOL_CALL:")), &call); err != nil {
|
||||
conversation = append(conversation, resp)
|
||||
conversation = append(conversation, ChatMessage{
|
||||
Role: "user",
|
||||
Role: "user",
|
||||
Content: fmt.Sprintf("Error: invalid tool call format. Use TOOL_CALL:{\"operation\":\"...\",\"args\":{...}}"),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// Check tool allowlist
|
||||
if !rt.ToolNames[call.Operation] {
|
||||
conversation = append(conversation, resp)
|
||||
conversation = append(conversation, ChatMessage{
|
||||
Role: "user",
|
||||
Role: "user",
|
||||
Content: fmt.Sprintf("Error: tool %q is not in the allowed list. Available: read_file, write_file, edit_file, list_directory, glob_files, grep_files, run_command, run_tests, lint_file, git_commit, git_diff, git_log, repo_map, read_persona, query_memory, check_growth, diagnose_behavior, find_capability", call.Operation),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// Execute the tool
|
||||
result := rt.executeTool(call.Operation, content)
|
||||
toolCalls++
|
||||
|
||||
|
||||
// Circuit breaker: check for consecutive identical failures
|
||||
if warning, tripped := cb.RegisterFailure(call.Operation, call.Args); tripped {
|
||||
return OperatorResponse{
|
||||
Success: false,
|
||||
Error: warning,
|
||||
Model: rt.Model,
|
||||
Success: false,
|
||||
Error: warning,
|
||||
Model: rt.Model,
|
||||
ToolCalls: toolCalls,
|
||||
Duration: time.Since(start).Round(time.Millisecond).String(),
|
||||
Duration: time.Since(start).Round(time.Millisecond).String(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
events = append(events, map[string]interface{}{
|
||||
"tool": call.Operation, "result": result,
|
||||
})
|
||||
|
||||
|
||||
conversation = append(conversation, resp)
|
||||
conversation = append(conversation, ChatMessage{
|
||||
Role: "user", Content: fmt.Sprintf("Tool result: %s", result),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// No tool call — this is the final response
|
||||
cb.RegisterSuccess()
|
||||
return OperatorResponse{
|
||||
@@ -210,7 +211,7 @@ func (rt *ToolRuntime) Run(messages []ChatMessage) OperatorResponse {
|
||||
Events: events,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return OperatorResponse{
|
||||
Success: false, Error: "max iterations exceeded",
|
||||
Model: rt.Model, ToolCalls: toolCalls,
|
||||
@@ -224,16 +225,30 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
baseURL := os.Getenv("OLLAMA_URL")
|
||||
if baseURL == "" { baseURL = "http://localhost:11434" }
|
||||
if baseURL == "" {
|
||||
baseURL = "http://localhost:11434"
|
||||
}
|
||||
model := "qwen2.5:3b"
|
||||
message := ""
|
||||
maxIter := 8
|
||||
|
||||
for i := 2; i < len(os.Args); i++ {
|
||||
switch os.Args[i] {
|
||||
case "--model": if i+1 < len(os.Args) { model = os.Args[i+1]; i++ }
|
||||
case "--message": if i+1 < len(os.Args) { message = os.Args[i+1]; i++ }
|
||||
case "--max-iterations": if i+1 < len(os.Args) { fmt.Sscanf(os.Args[i+1], "%d", &maxIter); i++ }
|
||||
case "--model":
|
||||
if i+1 < len(os.Args) {
|
||||
model = os.Args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--message":
|
||||
if i+1 < len(os.Args) {
|
||||
message = os.Args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--max-iterations":
|
||||
if i+1 < len(os.Args) {
|
||||
fmt.Sscanf(os.Args[i+1], "%d", &maxIter)
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+50
-16
@@ -3,12 +3,13 @@
|
||||
// Uses modernc.org/sqlite (pure Go, no cgo).
|
||||
//
|
||||
// Usage:
|
||||
// memory-ops add <text> [--importance <f>] [--topic <t>] [--source <s>]
|
||||
// memory-ops search <query> [--limit N]
|
||||
// memory-ops get <id>
|
||||
// memory-ops wash <id>
|
||||
// memory-ops supersede <id> <new-text>
|
||||
// memory-ops stats
|
||||
//
|
||||
// memory-ops add <text> [--importance <f>] [--topic <t>] [--source <s>]
|
||||
// memory-ops search <query> [--limit N]
|
||||
// memory-ops get <id>
|
||||
// memory-ops wash <id>
|
||||
// memory-ops supersede <id> <new-text>
|
||||
// memory-ops stats
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -37,7 +38,9 @@ func dbPath() string {
|
||||
|
||||
func connect() (*sql.DB, error) {
|
||||
db, err := sql.Open("sqlite", dbPath())
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db.Exec("PRAGMA journal_mode=WAL")
|
||||
db.Exec("PRAGMA synchronous=NORMAL")
|
||||
return db, nil
|
||||
@@ -69,10 +72,25 @@ func main() {
|
||||
source := ""
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch args[i] {
|
||||
case "--importance": if i+1 < len(args) { fmt.Sscanf(args[i+1], "%f", &importance); i++ }
|
||||
case "--topic": if i+1 < len(args) { topic = args[i+1]; i++ }
|
||||
case "--source": if i+1 < len(args) { source = args[i+1]; i++ }
|
||||
default: if text == "" { text = args[i] }
|
||||
case "--importance":
|
||||
if i+1 < len(args) {
|
||||
fmt.Sscanf(args[i+1], "%f", &importance)
|
||||
i++
|
||||
}
|
||||
case "--topic":
|
||||
if i+1 < len(args) {
|
||||
topic = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--source":
|
||||
if i+1 < len(args) {
|
||||
source = args[i+1]
|
||||
i++
|
||||
}
|
||||
default:
|
||||
if text == "" {
|
||||
text = args[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(text) < 8 {
|
||||
@@ -100,8 +118,15 @@ func main() {
|
||||
limit := 5
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch args[i] {
|
||||
case "--limit": if i+1 < len(args) { fmt.Sscanf(args[i+1], "%d", &limit); i++ }
|
||||
default: if query == "" { query = args[i] }
|
||||
case "--limit":
|
||||
if i+1 < len(args) {
|
||||
fmt.Sscanf(args[i+1], "%d", &limit)
|
||||
i++
|
||||
}
|
||||
default:
|
||||
if query == "" {
|
||||
query = args[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
rows, err := db.Query(
|
||||
@@ -128,7 +153,10 @@ func main() {
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "get":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: memory-ops get <id>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: memory-ops get <id>")
|
||||
os.Exit(1)
|
||||
}
|
||||
var id int64
|
||||
fmt.Sscanf(args[0], "%d", &id)
|
||||
var text, topic, createdAt string
|
||||
@@ -146,7 +174,10 @@ func main() {
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "wash":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: memory-ops wash <id>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: memory-ops wash <id>")
|
||||
os.Exit(1)
|
||||
}
|
||||
var id int64
|
||||
fmt.Sscanf(args[0], "%d", &id)
|
||||
db.Exec("UPDATE entries SET wash_count = wash_count + 1, last_accessed = ? WHERE id = ?", nowISO(), id)
|
||||
@@ -154,7 +185,10 @@ func main() {
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "supersede":
|
||||
if len(args) < 2 { fmt.Fprintln(os.Stderr, "usage: memory-ops supersede <id> <new-text>"); os.Exit(1) }
|
||||
if len(args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "usage: memory-ops supersede <id> <new-text>")
|
||||
os.Exit(1)
|
||||
}
|
||||
var oldID int64
|
||||
fmt.Sscanf(args[0], "%d", &oldID)
|
||||
newText := args[1]
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
// fuzz_test.go — FTS query builder fuzz (polyglot gate contract).
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// FuzzFtsQueryConjunctive — deterministic; quote-free inputs produce
|
||||
// balanced quotes. ORACLE-VERIFIED DIVERGENCE (pinned): the builder wraps
|
||||
// terms in quotes but never escapes embedded ones — input containing '"'
|
||||
// yields unbalanced output in the Python oracle too ('¼"' case). FTS5
|
||||
// hardening is defect territory (the builder can inject match syntax);
|
||||
// here we pin ORACLE behavior, not aspiration.
|
||||
func FuzzFtsQueryConjunctive(f *testing.F) {
|
||||
for _, s := range []string{"", "the and was", "one good term", "\"nested\" quotes",
|
||||
"cap this one out with many many many many many many words here"} {
|
||||
f.Add(s)
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, s string) {
|
||||
out := FtsQueryConjunctive(s)
|
||||
if out != FtsQueryConjunctive(s) {
|
||||
t.Fatalf("not deterministic for %q", s)
|
||||
}
|
||||
if !strings.Contains(s, "\"") && strings.Count(out, "\"")%2 != 0 {
|
||||
t.Fatalf("unbalanced quotes on quote-free input %q: %q", s, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
Binary file not shown.
+2
@@ -0,0 +1,2 @@
|
||||
go test fuzz v1
|
||||
string("\xbc\"")
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
go test fuzz v1
|
||||
string("\"")
|
||||
@@ -3,14 +3,15 @@
|
||||
// queues messages, approves/rejects/executes.
|
||||
//
|
||||
// Usage:
|
||||
// message-queue add <message> [--channel <ch>] [--task-id <id>]
|
||||
// message-queue list [--status pending|approved|executed|rejected]
|
||||
// message-queue approve <id>
|
||||
// message-queue approve-all
|
||||
// message-queue reject <id>
|
||||
// message-queue clear
|
||||
// message-queue mark-executed <id>
|
||||
// message-queue detect <message>
|
||||
//
|
||||
// message-queue add <message> [--channel <ch>] [--task-id <id>]
|
||||
// message-queue list [--status pending|approved|executed|rejected]
|
||||
// message-queue approve <id>
|
||||
// message-queue approve-all
|
||||
// message-queue reject <id>
|
||||
// message-queue clear
|
||||
// message-queue mark-executed <id>
|
||||
// message-queue detect <message>
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -108,11 +109,19 @@ func main() {
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch args[i] {
|
||||
case "--channel":
|
||||
if i+1 < len(args) { channel = args[i+1]; i++ }
|
||||
if i+1 < len(args) {
|
||||
channel = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--task-id":
|
||||
if i+1 < len(args) { taskID = args[i+1]; i++ }
|
||||
if i+1 < len(args) {
|
||||
taskID = args[i+1]
|
||||
i++
|
||||
}
|
||||
default:
|
||||
if msg == "" { msg = args[i] }
|
||||
if msg == "" {
|
||||
msg = args[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
qm := QueuedMessage{
|
||||
@@ -130,7 +139,9 @@ func main() {
|
||||
|
||||
case "list":
|
||||
status := ""
|
||||
if len(args) > 1 && args[0] == "--status" { status = args[1] }
|
||||
if len(args) > 1 && args[0] == "--status" {
|
||||
status = args[1]
|
||||
}
|
||||
for _, m := range q.Messages {
|
||||
if status == "" || m.Status == status {
|
||||
out, _ := json.Marshal(m)
|
||||
|
||||
Binary file not shown.
+44
-21
@@ -3,11 +3,12 @@
|
||||
// capabilities, fires events to registered hooks.
|
||||
//
|
||||
// Usage:
|
||||
// microkernel register <manifest-json>
|
||||
// microkernel unregister <name>
|
||||
// microkernel resolve <capability>
|
||||
// microkernel fire <event> [--data <json>]
|
||||
// microkernel status
|
||||
//
|
||||
// microkernel register <manifest-json>
|
||||
// microkernel unregister <name>
|
||||
// microkernel resolve <capability>
|
||||
// microkernel fire <event> [--data <json>]
|
||||
// microkernel status
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -38,9 +39,9 @@ type PluginEntry struct {
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
Plugins map[string]PluginEntry `json:"plugins"`
|
||||
Capabilities map[string][]string `json:"capabilities"`
|
||||
Hooks map[string][]string `json:"hooks"`
|
||||
Plugins map[string]PluginEntry `json:"plugins"`
|
||||
Capabilities map[string][]string `json:"capabilities"`
|
||||
Hooks map[string][]string `json:"hooks"`
|
||||
}
|
||||
|
||||
func registryPath() string {
|
||||
@@ -58,7 +59,9 @@ func loadRegistry() Registry {
|
||||
Hooks: make(map[string][]string),
|
||||
}
|
||||
data, err := os.ReadFile(registryPath())
|
||||
if err != nil { return r }
|
||||
if err != nil {
|
||||
return r
|
||||
}
|
||||
json.Unmarshal(data, &r)
|
||||
return r
|
||||
}
|
||||
@@ -93,9 +96,9 @@ func main() {
|
||||
}
|
||||
manifest.AutoActivate = true
|
||||
registry.Plugins[manifest.Name] = PluginEntry{
|
||||
Manifest: manifest,
|
||||
Manifest: manifest,
|
||||
RegisteredAt: time.Now().UTC().Format("2006-01-02T15:04:05Z"),
|
||||
Active: manifest.AutoActivate,
|
||||
Active: manifest.AutoActivate,
|
||||
}
|
||||
for _, cap := range manifest.Capabilities {
|
||||
registry.Capabilities[cap] = append(registry.Capabilities[cap], manifest.Name)
|
||||
@@ -110,21 +113,31 @@ func main() {
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "unregister":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: microkernel unregister <name>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: microkernel unregister <name>")
|
||||
os.Exit(1)
|
||||
}
|
||||
name := args[0]
|
||||
entry, ok := registry.Plugins[name]
|
||||
if !ok { fmt.Printf(`{"error": "plugin '%s' not registered"}`+"\n", name); return }
|
||||
if !ok {
|
||||
fmt.Printf(`{"error": "plugin '%s' not registered"}`+"\n", name)
|
||||
return
|
||||
}
|
||||
for cap, providers := range registry.Capabilities {
|
||||
var filtered []string
|
||||
for _, p := range providers {
|
||||
if p != name { filtered = append(filtered, p) }
|
||||
if p != name {
|
||||
filtered = append(filtered, p)
|
||||
}
|
||||
}
|
||||
registry.Capabilities[cap] = filtered
|
||||
}
|
||||
for event, listeners := range registry.Hooks {
|
||||
var filtered []string
|
||||
for _, l := range listeners {
|
||||
if l != name { filtered = append(filtered, l) }
|
||||
if l != name {
|
||||
filtered = append(filtered, l)
|
||||
}
|
||||
}
|
||||
registry.Hooks[event] = filtered
|
||||
}
|
||||
@@ -134,7 +147,10 @@ func main() {
|
||||
fmt.Printf(`{"status": "unregistered", "name": "%s"}`+"\n", name)
|
||||
|
||||
case "resolve":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: microkernel resolve <capability>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: microkernel resolve <capability>")
|
||||
os.Exit(1)
|
||||
}
|
||||
providers, ok := registry.Capabilities[args[0]]
|
||||
if !ok || len(providers) == 0 {
|
||||
fmt.Println("null")
|
||||
@@ -160,9 +176,14 @@ func main() {
|
||||
case "fire":
|
||||
event := ""
|
||||
data := ""
|
||||
if len(args) > 0 { event = args[0] }
|
||||
if len(args) > 0 {
|
||||
event = args[0]
|
||||
}
|
||||
for i := 1; i < len(args); i++ {
|
||||
if args[i] == "--data" && i+1 < len(args) { data = args[i+1]; i++ }
|
||||
if args[i] == "--data" && i+1 < len(args) {
|
||||
data = args[i+1]
|
||||
i++
|
||||
}
|
||||
}
|
||||
listeners, ok := registry.Hooks[event]
|
||||
if !ok || len(listeners) == 0 {
|
||||
@@ -179,11 +200,13 @@ func main() {
|
||||
|
||||
case "status":
|
||||
plugins := make([]string, 0)
|
||||
for name := range registry.Plugins { plugins = append(plugins, name) }
|
||||
for name := range registry.Plugins {
|
||||
plugins = append(plugins, name)
|
||||
}
|
||||
out, _ := json.MarshalIndent(map[string]interface{}{
|
||||
"plugins": plugins,
|
||||
"plugins": plugins,
|
||||
"capabilities_count": len(registry.Capabilities),
|
||||
"hooks_count": len(registry.Hooks),
|
||||
"hooks_count": len(registry.Hooks),
|
||||
}, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
|
||||
Binary file not shown.
@@ -6,10 +6,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -30,8 +30,8 @@ type ChatMessage struct {
|
||||
}
|
||||
|
||||
type ModelInfo struct {
|
||||
Name string `json:"name"`
|
||||
ContextLen int `json:"context_length"`
|
||||
Name string `json:"name"`
|
||||
ContextLen int `json:"context_length"`
|
||||
Capabilities []string `json:"capabilities"`
|
||||
}
|
||||
|
||||
@@ -50,10 +50,14 @@ func (o *OllamaProvider) Chat(model string, messages []ChatMessage, options map[
|
||||
body := map[string]interface{}{
|
||||
"model": model, "messages": messages, "stream": false,
|
||||
}
|
||||
for k, v := range options { body[k] = v }
|
||||
for k, v := range options {
|
||||
body[k] = v
|
||||
}
|
||||
data, _ := json.Marshal(body)
|
||||
resp, err := o.Client.Post(o.BaseURL+"/api/chat", "application/json", bytes.NewReader(data))
|
||||
if err != nil { return ChatMessage{}, fmt.Errorf("ollama chat: %w", err) }
|
||||
if err != nil {
|
||||
return ChatMessage{}, fmt.Errorf("ollama chat: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var result struct {
|
||||
Message ChatMessage `json:"message"`
|
||||
@@ -65,42 +69,50 @@ func (o *OllamaProvider) Chat(model string, messages []ChatMessage, options map[
|
||||
func (o *OllamaProvider) Show(model string) (ModelInfo, error) {
|
||||
data, _ := json.Marshal(map[string]string{"name": model})
|
||||
resp, err := o.Client.Post(o.BaseURL+"/api/show", "application/json", bytes.NewReader(data))
|
||||
if err != nil { return ModelInfo{}, err }
|
||||
if err != nil {
|
||||
return ModelInfo{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var result struct {
|
||||
Details struct {
|
||||
ParameterSize string `json:"parameter_size"`
|
||||
Family string `json:"family"`
|
||||
ParameterSize string `json:"parameter_size"`
|
||||
Family string `json:"family"`
|
||||
} `json:"details"`
|
||||
ContextLength int `json:"context_length"`
|
||||
}
|
||||
json.NewDecoder(resp.Body).Decode(&result)
|
||||
return ModelInfo{
|
||||
Name: model,
|
||||
ContextLen: result.ContextLength,
|
||||
Name: model,
|
||||
ContextLen: result.ContextLength,
|
||||
Capabilities: []string{result.Details.Family, result.Details.ParameterSize},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *OllamaProvider) ListModels() ([]string, error) {
|
||||
resp, err := o.Client.Get(o.BaseURL + "/api/tags")
|
||||
if err != nil { return nil, err }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var result struct {
|
||||
Models []struct { Name string `json:"name"` } `json:"models"`
|
||||
Models []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"models"`
|
||||
}
|
||||
json.NewDecoder(resp.Body).Decode(&result)
|
||||
var names []string
|
||||
for _, m := range result.Models { names = append(names, m.Name) }
|
||||
for _, m := range result.Models {
|
||||
names = append(names, m.Name)
|
||||
}
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// ── Model routing ──
|
||||
|
||||
type ModelProfile struct {
|
||||
Name string `json:"name"`
|
||||
Provider string `json:"provider"`
|
||||
ContextLen int `json:"context_length"`
|
||||
Name string `json:"name"`
|
||||
Provider string `json:"provider"`
|
||||
ContextLen int `json:"context_length"`
|
||||
Capabilities []string `json:"capabilities"`
|
||||
}
|
||||
|
||||
@@ -127,11 +139,11 @@ func (r *ModelRouter) Route(taskDescription string) string {
|
||||
// ── Provider budget ──
|
||||
|
||||
type BudgetEntry struct {
|
||||
Provider string `json:"provider"`
|
||||
MonthlyUsed float64 `json:"monthly_used"`
|
||||
Provider string `json:"provider"`
|
||||
MonthlyUsed float64 `json:"monthly_used"`
|
||||
MonthlyLimit float64 `json:"monthly_limit"`
|
||||
TokensUsed int64 `json:"tokens_used"`
|
||||
TokenLimit int64 `json:"token_limit"`
|
||||
TokensUsed int64 `json:"tokens_used"`
|
||||
TokenLimit int64 `json:"token_limit"`
|
||||
}
|
||||
|
||||
type ProviderBudget struct {
|
||||
@@ -142,7 +154,9 @@ type ProviderBudget struct {
|
||||
func (b *ProviderBudget) Record(provider string, tokens int64) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if b.Providers == nil { b.Providers = make(map[string]BudgetEntry) }
|
||||
if b.Providers == nil {
|
||||
b.Providers = make(map[string]BudgetEntry)
|
||||
}
|
||||
e := b.Providers[provider]
|
||||
e.TokensUsed += tokens
|
||||
b.Providers[provider] = e
|
||||
@@ -155,7 +169,9 @@ func main() {
|
||||
}
|
||||
|
||||
baseURL := os.Getenv("OLLAMA_URL")
|
||||
if baseURL == "" { baseURL = "http://localhost:11434" }
|
||||
if baseURL == "" {
|
||||
baseURL = "http://localhost:11434"
|
||||
}
|
||||
provider := NewOllamaProvider(baseURL)
|
||||
|
||||
cmd := os.Args[1]
|
||||
@@ -163,29 +179,47 @@ func main() {
|
||||
|
||||
switch cmd {
|
||||
case "chat":
|
||||
if len(args) < 2 { fmt.Fprintln(os.Stderr, "usage: model-connect chat <model> <message>"); os.Exit(1) }
|
||||
if len(args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "usage: model-connect chat <model> <message>")
|
||||
os.Exit(1)
|
||||
}
|
||||
model, message := args[0], args[1]
|
||||
messages := []ChatMessage{{Role: "user", Content: message}}
|
||||
resp, err := provider.Chat(model, messages, nil)
|
||||
if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err); os.Exit(1) }
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
out, _ := json.MarshalIndent(resp, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "list":
|
||||
models, err := provider.ListModels()
|
||||
if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err); os.Exit(1) }
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
out, _ := json.MarshalIndent(models, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "show":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: model-connect show <model>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: model-connect show <model>")
|
||||
os.Exit(1)
|
||||
}
|
||||
info, err := provider.Show(args[0])
|
||||
if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err); os.Exit(1) }
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
out, _ := json.MarshalIndent(info, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "route":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: model-connect route <task>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: model-connect route <task>")
|
||||
os.Exit(1)
|
||||
}
|
||||
router := &ModelRouter{
|
||||
Profiles: map[string]ModelProfile{
|
||||
"qwen2.5:3b": {Name: "qwen2.5:3b", Provider: "ollama", ContextLen: 32768, Capabilities: []string{"local", "fast", "small"}},
|
||||
|
||||
Binary file not shown.
@@ -3,10 +3,11 @@
|
||||
// phase progression, and iteration counts for the sleep-time cycle.
|
||||
//
|
||||
// Usage:
|
||||
// night-mode start [hours]
|
||||
// night-mode stop
|
||||
// night-mode status
|
||||
// night-mode report
|
||||
//
|
||||
// night-mode start [hours]
|
||||
// night-mode stop
|
||||
// night-mode status
|
||||
// night-mode report
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -45,7 +46,9 @@ func loadState() NightModeState {
|
||||
state.Decisions = []string{}
|
||||
state.Errors = []string{}
|
||||
data, err := os.ReadFile(statePath())
|
||||
if err != nil { return state }
|
||||
if err != nil {
|
||||
return state
|
||||
}
|
||||
json.Unmarshal(data, &state)
|
||||
return state
|
||||
}
|
||||
@@ -72,7 +75,9 @@ func main() {
|
||||
return
|
||||
}
|
||||
hours := 8.0
|
||||
if len(args) > 0 { fmt.Sscanf(args[0], "%f", &hours) }
|
||||
if len(args) > 0 {
|
||||
fmt.Sscanf(args[0], "%f", &hours)
|
||||
}
|
||||
state.Active = true
|
||||
state.StartedAt = time.Now().UTC().Format(time.RFC3339)
|
||||
state.DurationHrs = hours
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -23,7 +23,10 @@ func main() {
|
||||
switch cmd {
|
||||
case "route":
|
||||
// adaptive_router: task-class routing
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: route <description>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: route <description>")
|
||||
os.Exit(1)
|
||||
}
|
||||
lower := strings.ToLower(args[0])
|
||||
route := "LOCAL_FIX"
|
||||
if strings.Contains(lower, "architect") || strings.Contains(lower, "design") || strings.Contains(lower, "wave") {
|
||||
|
||||
Binary file not shown.
+35
-21
@@ -4,8 +4,9 @@
|
||||
// tool calls, and returns a response.
|
||||
//
|
||||
// Usage:
|
||||
// operator respond --model <model> --message <text>
|
||||
// operator status
|
||||
//
|
||||
// operator respond --model <model> --message <text>
|
||||
// operator status
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -13,9 +14,9 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// ── Types ──
|
||||
@@ -26,12 +27,12 @@ type ChatMessage struct {
|
||||
}
|
||||
|
||||
type OperatorResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Response string `json:"response,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
ToolCalls int `json:"tool_calls,omitempty"`
|
||||
Duration string `json:"duration,omitempty"`
|
||||
Success bool `json:"success"`
|
||||
Response string `json:"response,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
ToolCalls int `json:"tool_calls,omitempty"`
|
||||
Duration string `json:"duration,omitempty"`
|
||||
}
|
||||
|
||||
// ── Ollama transport ──
|
||||
@@ -98,11 +99,11 @@ func runTurn(transport *OllamaTransport, messages []ChatMessage, maxIterations i
|
||||
}
|
||||
// No tool call — this is the final response
|
||||
return OperatorResponse{
|
||||
Success: true,
|
||||
Response: resp.Content,
|
||||
Model: transport.Model,
|
||||
Success: true,
|
||||
Response: resp.Content,
|
||||
Model: transport.Model,
|
||||
ToolCalls: toolCalls,
|
||||
Duration: time.Since(start).Round(time.Millisecond).String(),
|
||||
Duration: time.Since(start).Round(time.Millisecond).String(),
|
||||
}
|
||||
}
|
||||
return OperatorResponse{Success: false, Error: "max iterations exceeded", Model: transport.Model}
|
||||
@@ -142,18 +143,31 @@ func main() {
|
||||
}
|
||||
|
||||
baseURL := os.Getenv("OLLAMA_URL")
|
||||
if baseURL == "" { baseURL = "http://localhost:11434" }
|
||||
if baseURL == "" {
|
||||
baseURL = "http://localhost:11434"
|
||||
}
|
||||
model := os.Getenv("MIMO_MODEL")
|
||||
if model == "" { model = "qwen2.5:3b" }
|
||||
if model == "" {
|
||||
model = "qwen2.5:3b"
|
||||
}
|
||||
|
||||
switch os.Args[1] {
|
||||
case "respond":
|
||||
message := ""
|
||||
for i := 2; i < len(os.Args); i++ {
|
||||
if os.Args[i] == "--message" && i+1 < len(os.Args) { message = os.Args[i+1]; i++ }
|
||||
if os.Args[i] == "--model" && i+1 < len(os.Args) { model = os.Args[i+1]; i++ }
|
||||
if os.Args[i] == "--message" && i+1 < len(os.Args) {
|
||||
message = os.Args[i+1]
|
||||
i++
|
||||
}
|
||||
if os.Args[i] == "--model" && i+1 < len(os.Args) {
|
||||
model = os.Args[i+1]
|
||||
i++
|
||||
}
|
||||
}
|
||||
if message == "" {
|
||||
fmt.Fprintln(os.Stderr, "usage: operator respond --message <text>")
|
||||
os.Exit(1)
|
||||
}
|
||||
if message == "" { fmt.Fprintln(os.Stderr, "usage: operator respond --message <text>"); os.Exit(1) }
|
||||
transport := NewOllamaTransport(baseURL, model)
|
||||
messages := []ChatMessage{{Role: "user", Content: message}}
|
||||
resp := runTurn(transport, messages, 10)
|
||||
@@ -162,9 +176,9 @@ func main() {
|
||||
|
||||
case "status":
|
||||
out, _ := json.MarshalIndent(map[string]interface{}{
|
||||
"runtime": "go",
|
||||
"model": model,
|
||||
"ollama_url": baseURL,
|
||||
"runtime": "go",
|
||||
"model": model,
|
||||
"ollama_url": baseURL,
|
||||
"goroutines_enabled": true,
|
||||
}, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
Binary file not shown.
@@ -4,8 +4,9 @@
|
||||
// designed for.
|
||||
//
|
||||
// Usage:
|
||||
// parallel-processor run <command1> <command2> ... (shell commands in parallel)
|
||||
// parallel-processor status
|
||||
//
|
||||
// parallel-processor run <command1> <command2> ... (shell commands in parallel)
|
||||
// parallel-processor status
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -104,7 +105,7 @@ func main() {
|
||||
|
||||
case "status":
|
||||
out, _ := json.MarshalIndent(map[string]interface{}{
|
||||
"runtime": "go",
|
||||
"runtime": "go",
|
||||
"goroutines_enabled": true,
|
||||
}, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
Binary file not shown.
+12
-11
@@ -3,8 +3,9 @@
|
||||
// on a request deterministically from its stored rules.
|
||||
//
|
||||
// Usage:
|
||||
// persona-gate decide <text> [--rules <rules-json>]
|
||||
// persona-gate load-rules
|
||||
//
|
||||
// persona-gate decide <text> [--rules <rules-json>]
|
||||
// persona-gate load-rules
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -15,20 +16,20 @@ import (
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Text string `json:"text"`
|
||||
Topic string `json:"topic"`
|
||||
Priority int `json:"priority"`
|
||||
Restrictive bool `json:"restrictive"`
|
||||
UserRule bool `json:"user_rule"`
|
||||
Text string `json:"text"`
|
||||
Topic string `json:"topic"`
|
||||
Priority int `json:"priority"`
|
||||
Restrictive bool `json:"restrictive"`
|
||||
UserRule bool `json:"user_rule"`
|
||||
Words map[string]bool `json:"words"`
|
||||
Core string `json:"core"`
|
||||
Core string `json:"core"`
|
||||
}
|
||||
|
||||
type GateVerdict struct {
|
||||
Allowed bool `json:"allowed"`
|
||||
Citations []string `json:"citations"`
|
||||
Allowed bool `json:"allowed"`
|
||||
Citations []string `json:"citations"`
|
||||
RulesEngaged []string `json:"rules_engaged"`
|
||||
Mode string `json:"mode"`
|
||||
Mode string `json:"mode"`
|
||||
}
|
||||
|
||||
func lex(text string) map[string]bool {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -3,8 +3,9 @@
|
||||
// mid→inject_and_verify, low→deep_research.
|
||||
//
|
||||
// Usage:
|
||||
// recall-router route <query> <json_scored_or_empty>
|
||||
// recall-router commands
|
||||
//
|
||||
// recall-router route <query> <json_scored_or_empty>
|
||||
// recall-router commands
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -76,8 +77,12 @@ func main() {
|
||||
switch os.Args[1] {
|
||||
case "route":
|
||||
query, scored := "", ""
|
||||
if len(os.Args) > 2 { query = os.Args[2] }
|
||||
if len(os.Args) > 3 { scored = os.Args[3] }
|
||||
if len(os.Args) > 2 {
|
||||
query = os.Args[2]
|
||||
}
|
||||
if len(os.Args) > 3 {
|
||||
scored = os.Args[3]
|
||||
}
|
||||
out, _ := json.MarshalIndent(route(query, scored), "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
|
||||
Binary file not shown.
@@ -9,17 +9,19 @@
|
||||
// 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...]
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// --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 (
|
||||
|
||||
Executable
BIN
Binary file not shown.
Binary file not shown.
+17
-17
@@ -47,9 +47,9 @@ func TerminalPhases() map[string]bool {
|
||||
|
||||
// Statuses / repo constants.
|
||||
var (
|
||||
Statues = []string{"open", "closed", "failed", "abandoned"}
|
||||
RepoPlacements = []string{"RUNE_REPO", "EXISTING_PROJECT_REPO", "NEW_MANAGED_REPO"}
|
||||
RepoSecretFields = []string{"token", "api_key", "password", "secret", "auth_header", "credential", "api_token"}
|
||||
Statues = []string{"open", "closed", "failed", "abandoned"}
|
||||
RepoPlacements = []string{"RUNE_REPO", "EXISTING_PROJECT_REPO", "NEW_MANAGED_REPO"}
|
||||
RepoSecretFields = []string{"token", "api_key", "password", "secret", "auth_header", "credential", "api_token"}
|
||||
)
|
||||
|
||||
// NextAction — the _NEXT_ACTION map.
|
||||
@@ -109,16 +109,16 @@ func phaseKnown(p string) bool {
|
||||
// ContractEntity — the contract entity shape (spine entity + lifecycle
|
||||
// fields). Identities carry the sorted-list discipline (Python sorted()).
|
||||
type ContractEntity struct {
|
||||
ID string `json:"id"`
|
||||
Kind string `json:"kind"`
|
||||
Identities map[string]interface{} `json:"identities"`
|
||||
Maturity string `json:"maturity"`
|
||||
EvidenceRefs []string `json:"evidence_refs"`
|
||||
Phase string `json:"phase"`
|
||||
Status string `json:"status"`
|
||||
Checkpoints []map[string]interface{} `json:"checkpoints"`
|
||||
ObservedAt string `json:"observed_at"`
|
||||
Ext map[string]interface{} `json:"ext,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Kind string `json:"kind"`
|
||||
Identities map[string]interface{} `json:"identities"`
|
||||
Maturity string `json:"maturity"`
|
||||
EvidenceRefs []string `json:"evidence_refs"`
|
||||
Phase string `json:"phase"`
|
||||
Status string `json:"status"`
|
||||
Checkpoints []map[string]interface{} `json:"checkpoints"`
|
||||
ObservedAt string `json:"observed_at"`
|
||||
Ext map[string]interface{} `json:"ext,omitempty"`
|
||||
}
|
||||
|
||||
// NewContract — new_contract: the identity dict (sorted lists), draft/open,
|
||||
@@ -230,10 +230,10 @@ func CheckScope(e *ContractEntity, changedFiles []string) map[string]interface{}
|
||||
sorted := append([]string{}, changedFiles...)
|
||||
sort.Strings(sorted)
|
||||
return map[string]interface{}{
|
||||
"verdict": "unknown",
|
||||
"in_scope": []string{},
|
||||
"out_of_scope": sorted,
|
||||
"reason": "contract has no approved scope",
|
||||
"verdict": "unknown",
|
||||
"in_scope": []string{},
|
||||
"out_of_scope": sorted,
|
||||
"reason": "contract has no approved scope",
|
||||
}
|
||||
}
|
||||
var inScope, outScope []string
|
||||
|
||||
@@ -491,14 +491,14 @@ func ImpactFrontier(doc map[string]interface{}, seedIDs []string, maxLevel int,
|
||||
}
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"level0_direct": interfaceSlice(level0),
|
||||
"level1_obligations": sortedKeys(level1),
|
||||
"contracts": sortedKeys(contracts),
|
||||
"level0_direct": interfaceSlice(level0),
|
||||
"level1_obligations": sortedKeys(level1),
|
||||
"contracts": sortedKeys(contracts),
|
||||
"contextual_not_obligations": sortedKeys(contextual),
|
||||
"change_kind": changeKind,
|
||||
"level2_verification": sortedKeys(level2),
|
||||
"traversal_scope": "spine-structural-only",
|
||||
"max_level": maxLevel,
|
||||
"change_kind": changeKind,
|
||||
"level2_verification": sortedKeys(level2),
|
||||
"traversal_scope": "spine-structural-only",
|
||||
"max_level": maxLevel,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,9 +51,9 @@ func TestCloseParity(t *testing.T) {
|
||||
want, _ := c.Expected["entity"].(map[string]interface{})
|
||||
docMap := map[string]interface{}{"entities": []interface{}{}, "observations": []interface{}{}}
|
||||
ident := map[string]interface{}{
|
||||
"need": "n",
|
||||
"scope": []string{"src/go/x/"},
|
||||
"affected_entities": []string{"module:a"},
|
||||
"need": "n",
|
||||
"scope": []string{"src/go/x/"},
|
||||
"affected_entities": []string{"module:a"},
|
||||
"expected_new_entities": []string{"module:new1"},
|
||||
}
|
||||
e, err := NewContract(docMap, "c1", "n", "user", ident)
|
||||
@@ -68,9 +68,9 @@ func TestCloseParity(t *testing.T) {
|
||||
}
|
||||
e.Ext = map[string]interface{}{
|
||||
"predicted_frontier": map[string]interface{}{
|
||||
"level0_direct": []interface{}{"module:a"},
|
||||
"level1_obligations": []interface{}{},
|
||||
"contracts": []interface{}{},
|
||||
"level0_direct": []interface{}{"module:a"},
|
||||
"level1_obligations": []interface{}{},
|
||||
"contracts": []interface{}{},
|
||||
"level2_verification": []interface{}{},
|
||||
},
|
||||
}
|
||||
|
||||
+21
-14
@@ -3,9 +3,10 @@
|
||||
// The deterministic compute (compression, scoring) stays in Rust kernels.
|
||||
//
|
||||
// Usage:
|
||||
// sleep-time consolidate [--full]
|
||||
// sleep-time status
|
||||
// sleep-time run
|
||||
//
|
||||
// sleep-time consolidate [--full]
|
||||
// sleep-time status
|
||||
// sleep-time run
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -17,11 +18,11 @@ import (
|
||||
)
|
||||
|
||||
type SleepState struct {
|
||||
LastRun string `json:"last_run,omitempty"`
|
||||
LastFullRun string `json:"last_full_run,omitempty"`
|
||||
SessionsProcessed int `json:"sessions_processed"`
|
||||
EntriesRetained int `json:"entries_retained"`
|
||||
Errors []string `json:"errors"`
|
||||
LastRun string `json:"last_run,omitempty"`
|
||||
LastFullRun string `json:"last_full_run,omitempty"`
|
||||
SessionsProcessed int `json:"sessions_processed"`
|
||||
EntriesRetained int `json:"entries_retained"`
|
||||
Errors []string `json:"errors"`
|
||||
}
|
||||
|
||||
func statePath() string {
|
||||
@@ -35,7 +36,9 @@ func statePath() string {
|
||||
func loadState() SleepState {
|
||||
var s SleepState
|
||||
data, err := os.ReadFile(statePath())
|
||||
if err != nil { return s }
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
json.Unmarshal(data, &s)
|
||||
return s
|
||||
}
|
||||
@@ -55,14 +58,18 @@ func main() {
|
||||
cmd := os.Args[1]
|
||||
full := false
|
||||
for _, a := range os.Args[2:] {
|
||||
if a == "--full" { full = true }
|
||||
if a == "--full" {
|
||||
full = true
|
||||
}
|
||||
}
|
||||
|
||||
switch cmd {
|
||||
case "consolidate":
|
||||
now := time.Now().UTC().Format(time.RFC3339)
|
||||
state.LastRun = now
|
||||
if full { state.LastFullRun = now }
|
||||
if full {
|
||||
state.LastFullRun = now
|
||||
}
|
||||
// The actual consolidation calls:
|
||||
// 1. Fetch sessions from the DB
|
||||
// 2. Extract parts/todos
|
||||
@@ -73,10 +80,10 @@ func main() {
|
||||
state.Errors = append(state.Errors, "consolidate: DB sessions not yet wired to Go SQLite")
|
||||
saveState(state)
|
||||
out, _ := json.Marshal(map[string]interface{}{
|
||||
"status": "consolidate dispatched",
|
||||
"full": full,
|
||||
"status": "consolidate dispatched",
|
||||
"full": full,
|
||||
"last_run": now,
|
||||
"note": "full DB wiring pending — orchestration layer ready",
|
||||
"note": "full DB wiring pending — orchestration layer ready",
|
||||
})
|
||||
fmt.Println(string(out))
|
||||
|
||||
|
||||
Binary file not shown.
+38
-26
@@ -36,15 +36,15 @@ type StageCheck struct {
|
||||
}
|
||||
|
||||
type StageContract struct {
|
||||
StageID string `json:"stage_id"`
|
||||
ContractID string `json:"contract_id,omitempty"`
|
||||
Dependencies []string `json:"dependencies,omitempty"`
|
||||
ReadyWhen []StageCheck `json:"ready_when,omitempty"`
|
||||
DoneWhen []StageCheck `json:"done_when,omitempty"`
|
||||
Invariants []StageCheck `json:"invariants,omitempty"`
|
||||
ExpectedEffect string `json:"expected_effect,omitempty"`
|
||||
RetryClass string `json:"retry_class,omitempty"`
|
||||
IdempotencyKey string `json:"idempotency_key,omitempty"`
|
||||
StageID string `json:"stage_id"`
|
||||
ContractID string `json:"contract_id,omitempty"`
|
||||
Dependencies []string `json:"dependencies,omitempty"`
|
||||
ReadyWhen []StageCheck `json:"ready_when,omitempty"`
|
||||
DoneWhen []StageCheck `json:"done_when,omitempty"`
|
||||
Invariants []StageCheck `json:"invariants,omitempty"`
|
||||
ExpectedEffect string `json:"expected_effect,omitempty"`
|
||||
RetryClass string `json:"retry_class,omitempty"`
|
||||
IdempotencyKey string `json:"idempotency_key,omitempty"`
|
||||
}
|
||||
|
||||
type CheckEvidence struct {
|
||||
@@ -70,20 +70,20 @@ type CanaryResult struct {
|
||||
}
|
||||
|
||||
type ExitResult struct {
|
||||
StageID string `json:"stage_id"`
|
||||
Canary string `json:"canary"`
|
||||
Verdict string `json:"verdict"`
|
||||
ActionEvidence map[string]interface{} `json:"action_evidence,omitempty"`
|
||||
ExitChecks []CheckEvidence `json:"exit_checks"`
|
||||
InvariantChecks []CheckEvidence `json:"invariant_checks,omitempty"`
|
||||
Failures []CheckEvidence `json:"failures,omitempty"`
|
||||
StageID string `json:"stage_id"`
|
||||
Canary string `json:"canary"`
|
||||
Verdict string `json:"verdict"`
|
||||
ActionEvidence map[string]interface{} `json:"action_evidence,omitempty"`
|
||||
ExitChecks []CheckEvidence `json:"exit_checks"`
|
||||
InvariantChecks []CheckEvidence `json:"invariant_checks,omitempty"`
|
||||
Failures []CheckEvidence `json:"failures,omitempty"`
|
||||
}
|
||||
|
||||
type TestExpectations struct {
|
||||
RequireTests bool `json:"require_tests"`
|
||||
MinTests int `json:"min_tests"`
|
||||
TestOutputPattern string `json:"test_output_pattern,omitempty"`
|
||||
ForbidAllSkipped string `json:"forbid_all_skipped,omitempty"`
|
||||
RequireTests bool `json:"require_tests"`
|
||||
MinTests int `json:"min_tests"`
|
||||
TestOutputPattern string `json:"test_output_pattern,omitempty"`
|
||||
ForbidAllSkipped string `json:"forbid_all_skipped,omitempty"`
|
||||
RequiredArtifacts []string `json:"required_artifacts,omitempty"`
|
||||
}
|
||||
|
||||
@@ -396,9 +396,15 @@ func main() {
|
||||
var lastProgress, now, stallLimit float64
|
||||
now = 0
|
||||
stallLimit = 300.0
|
||||
if len(args) > 0 { fmt.Sscanf(args[0], "%f", &lastProgress) }
|
||||
if len(args) > 1 { fmt.Sscanf(args[1], "%f", &now) }
|
||||
if len(args) > 2 { fmt.Sscanf(args[2], "%f", &stallLimit) }
|
||||
if len(args) > 0 {
|
||||
fmt.Sscanf(args[0], "%f", &lastProgress)
|
||||
}
|
||||
if len(args) > 1 {
|
||||
fmt.Sscanf(args[1], "%f", &now)
|
||||
}
|
||||
if len(args) > 2 {
|
||||
fmt.Sscanf(args[2], "%f", &stallLimit)
|
||||
}
|
||||
out, _ := json.MarshalIndent(livenessCanary(lastProgress, now, stallLimit), "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
@@ -422,9 +428,15 @@ func main() {
|
||||
depth := "TINY"
|
||||
structural := false
|
||||
stageID := ""
|
||||
if len(args) > 0 { depth = args[0] }
|
||||
if len(args) > 1 { structural = args[1] == "true" }
|
||||
if len(args) > 2 { stageID = args[2] }
|
||||
if len(args) > 0 {
|
||||
depth = args[0]
|
||||
}
|
||||
if len(args) > 1 {
|
||||
structural = args[1] == "true"
|
||||
}
|
||||
if len(args) > 2 {
|
||||
stageID = args[2]
|
||||
}
|
||||
out, _ := json.MarshalIndent(henxelsPlacement(depth, structural, stageID), "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
// fuzz_test.go — canonical JSON serializer fuzz (polyglot gate contract):
|
||||
// never panics, always valid parseable JSON, round-trips.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// FuzzCanonicalJSON — the canonical serializer must never panic and must
|
||||
// always emit VALID, parseable JSON whose decoded value round-trips.
|
||||
func FuzzCanonicalJSON(f *testing.F) {
|
||||
seeds := []string{"", "hello", "quote\"inside", "back\\slash", "new\nline",
|
||||
"tab\tchar", "unicode ümlaut ✅", "emoji 👍 tail", "{\"k\": [1, 2]}",
|
||||
strings.Repeat("a", 300), "\x00\x01\x02 control bytes"}
|
||||
for _, s := range seeds {
|
||||
f.Add(s)
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, s string) {
|
||||
// Domain restriction (oracle parity): the Python oracle receives
|
||||
// arguments via json.loads — which REJECTS invalid UTF-8 — so
|
||||
// canonicalJSON's domain is valid-UTF-8 strings only. Go strings
|
||||
// can hold raw bytes the oracle can never see.
|
||||
if !utf8.ValidString(s) {
|
||||
t.Skip("invalid UTF-8 outside the oracle's domain")
|
||||
}
|
||||
m := map[string]interface{}{"k": s, "n": 1.5}
|
||||
out := canonicalJSON(m)
|
||||
if !utf8.ValidString(out) {
|
||||
t.Fatalf("canonicalJSON emitted invalid UTF-8 for %q: %q", s, out)
|
||||
}
|
||||
var back map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(out), &back); err != nil {
|
||||
t.Fatalf("canonicalJSON output not parseable for %q: %v (%q)", s, err, out)
|
||||
}
|
||||
if back["k"] != s {
|
||||
t.Fatalf("round-trip mismatch: in %q out %q", s, back["k"])
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -105,8 +105,12 @@ func canonicalJSON(v interface{}) string {
|
||||
}
|
||||
}
|
||||
|
||||
// jsonEsc — Python-compatible JSON string escaping (ensure_ascii=False:
|
||||
// non-ASCII passes through raw).
|
||||
// jsonEsc — Python-compatible JSON string escaping. PARITY (fuzzer-found,
|
||||
// contract BUILDER-2026-10-07T20:01:40Z-ac6140): Python json.dumps — even
|
||||
// with ensure_ascii=False — escapes control bytes (< 0x20) as \uXXXX; the
|
||||
// original Go port passed them through RAW, producing INVALID JSON and a
|
||||
// digest that diverged from the oracle on adversarial payloads. Non-ASCII
|
||||
// printable passes through raw (that part of ensure_ascii=False is real).
|
||||
func jsonEsc(s string) string {
|
||||
var b strings.Builder
|
||||
b.WriteByte('"')
|
||||
@@ -123,7 +127,11 @@ func jsonEsc(s string) string {
|
||||
case '\t':
|
||||
b.WriteString("\\t")
|
||||
default:
|
||||
b.WriteRune(r)
|
||||
if r < 0x20 {
|
||||
b.WriteString(fmt.Sprintf("\\u%04x", r))
|
||||
} else {
|
||||
b.WriteRune(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
b.WriteByte('"')
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
go test fuzz v1
|
||||
string("\xb6")
|
||||
Binary file not shown.
@@ -171,10 +171,14 @@ func main() {
|
||||
searchIdx := 0
|
||||
for {
|
||||
start := strings.Index(text[searchIdx:], `{"tool":`)
|
||||
if start < 0 { break }
|
||||
if start < 0 {
|
||||
break
|
||||
}
|
||||
start += searchIdx
|
||||
end := strings.Index(text[start:], "}")
|
||||
if end < 0 { break }
|
||||
if end < 0 {
|
||||
break
|
||||
}
|
||||
end += start + 1
|
||||
var envelope map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(text[start:end]), &envelope); err != nil {
|
||||
@@ -206,22 +210,22 @@ func main() {
|
||||
}
|
||||
|
||||
var TOOLS = map[string]ToolSchema{
|
||||
"read_file": {Name: "read_file", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}, "offset": {Type: "integer"}, "limit": {Type: "integer"}}, Required: []string{"path"}}},
|
||||
"edit_file": {Name: "edit_file", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}, "search": {Type: "string"}, "replace": {Type: "string"}}, Required: []string{"path", "search", "replace"}}},
|
||||
"write_file": {Name: "write_file", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}, "content": {Type: "string"}}, Required: []string{"path", "content"}}},
|
||||
"glob_files": {Name: "glob_files", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"pattern": {Type: "string"}, "path": {Type: "string"}}, Required: []string{"pattern"}}},
|
||||
"grep_files": {Name: "grep_files", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"pattern": {Type: "string"}, "path": {Type: "string"}, "include": {Type: "string"}}, Required: []string{"pattern"}}},
|
||||
"list_directory": {Name: "list_directory", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}, "pattern": {Type: "string"}}, Required: []string{"path"}}},
|
||||
"run_command": {Name: "run_command", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"command": {Type: "string"}}, Required: []string{"command"}}},
|
||||
"run_tests": {Name: "run_tests", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{}, Required: []string{}}},
|
||||
"lint_file": {Name: "lint_file", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}}, Required: []string{"path"}}},
|
||||
"git_commit": {Name: "git_commit", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"message": {Type: "string"}}, Required: []string{"message"}}},
|
||||
"git_diff": {Name: "git_diff", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{}, Required: []string{}}},
|
||||
"git_log": {Name: "git_log", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"count": {Type: "integer"}}, Required: []string{}}},
|
||||
"repo_map": {Name: "repo_map", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}}, Required: []string{"path"}}},
|
||||
"read_persona": {Name: "read_persona", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{}, Required: []string{}}},
|
||||
"query_memory": {Name: "query_memory", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"query": {Type: "string"}, "limit": {Type: "integer"}}, Required: []string{"query"}}},
|
||||
"check_growth": {Name: "check_growth", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{}, Required: []string{}}},
|
||||
"read_file": {Name: "read_file", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}, "offset": {Type: "integer"}, "limit": {Type: "integer"}}, Required: []string{"path"}}},
|
||||
"edit_file": {Name: "edit_file", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}, "search": {Type: "string"}, "replace": {Type: "string"}}, Required: []string{"path", "search", "replace"}}},
|
||||
"write_file": {Name: "write_file", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}, "content": {Type: "string"}}, Required: []string{"path", "content"}}},
|
||||
"glob_files": {Name: "glob_files", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"pattern": {Type: "string"}, "path": {Type: "string"}}, Required: []string{"pattern"}}},
|
||||
"grep_files": {Name: "grep_files", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"pattern": {Type: "string"}, "path": {Type: "string"}, "include": {Type: "string"}}, Required: []string{"pattern"}}},
|
||||
"list_directory": {Name: "list_directory", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}, "pattern": {Type: "string"}}, Required: []string{"path"}}},
|
||||
"run_command": {Name: "run_command", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"command": {Type: "string"}}, Required: []string{"command"}}},
|
||||
"run_tests": {Name: "run_tests", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{}, Required: []string{}}},
|
||||
"lint_file": {Name: "lint_file", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}}, Required: []string{"path"}}},
|
||||
"git_commit": {Name: "git_commit", Risk: "write", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"message": {Type: "string"}}, Required: []string{"message"}}},
|
||||
"git_diff": {Name: "git_diff", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{}, Required: []string{}}},
|
||||
"git_log": {Name: "git_log", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"count": {Type: "integer"}}, Required: []string{}}},
|
||||
"repo_map": {Name: "repo_map", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"path": {Type: "string"}}, Required: []string{"path"}}},
|
||||
"read_persona": {Name: "read_persona", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{}, Required: []string{}}},
|
||||
"query_memory": {Name: "query_memory", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"query": {Type: "string"}, "limit": {Type: "integer"}}, Required: []string{"query"}}},
|
||||
"check_growth": {Name: "check_growth", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{}, Required: []string{}}},
|
||||
"diagnose_behavior": {Name: "diagnose_behavior", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"issue": {Type: "string"}}, Required: []string{"issue"}}},
|
||||
"find_capability": {Name: "find_capability", Risk: "read-only", Parameters: ToolParameters{Type: "object", Properties: map[string]ToolParam{"description": {Type: "string"}}, Required: []string{"description"}}},
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -3,9 +3,10 @@
|
||||
// the schema, normalizes names, checks approval requirements.
|
||||
//
|
||||
// Usage:
|
||||
// tool-protocol validate <request-json>
|
||||
// tool-protocol list-tools
|
||||
// tool-protocol requires-approval <tool-name>
|
||||
//
|
||||
// tool-protocol validate <request-json>
|
||||
// tool-protocol list-tools
|
||||
// tool-protocol requires-approval <tool-name>
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -36,22 +37,22 @@ type ToolDef struct {
|
||||
}
|
||||
|
||||
var TOOL_INDEX = map[string]ToolDef{
|
||||
"read_file": {Name: "read_file", Description: "Read a file with optional offset/limit"},
|
||||
"write_file": {Name: "write_file", RequiresApproval: true, Description: "Write content to a file"},
|
||||
"edit_file": {Name: "edit_file", RequiresApproval: true, Description: "Edit a file with diff preview"},
|
||||
"list_directory": {Name: "list_directory", Description: "List files in a directory"},
|
||||
"glob_files": {Name: "glob_files", Description: "Find files matching a glob"},
|
||||
"grep_files": {Name: "grep_files", Description: "Search for text in files"},
|
||||
"run_command": {Name: "run_command", RequiresApproval: true, Description: "Run a shell command"},
|
||||
"run_tests": {Name: "run_tests", RequiresApproval: true, Description: "Run the test suite"},
|
||||
"lint_file": {Name: "lint_file", Description: "Lint a file"},
|
||||
"git_commit": {Name: "git_commit", RequiresApproval: true, Description: "Create a git commit"},
|
||||
"git_diff": {Name: "git_diff", Description: "Show git diff"},
|
||||
"git_log": {Name: "git_log", Description: "Show git log"},
|
||||
"repo_map": {Name: "repo_map", Description: "Generate a repository map"},
|
||||
"read_persona": {Name: "read_persona", Description: "Read the persona definition"},
|
||||
"query_memory": {Name: "query_memory", Description: "Query the memory store"},
|
||||
"check_growth": {Name: "check_growth", Description: "Check growth delta"},
|
||||
"read_file": {Name: "read_file", Description: "Read a file with optional offset/limit"},
|
||||
"write_file": {Name: "write_file", RequiresApproval: true, Description: "Write content to a file"},
|
||||
"edit_file": {Name: "edit_file", RequiresApproval: true, Description: "Edit a file with diff preview"},
|
||||
"list_directory": {Name: "list_directory", Description: "List files in a directory"},
|
||||
"glob_files": {Name: "glob_files", Description: "Find files matching a glob"},
|
||||
"grep_files": {Name: "grep_files", Description: "Search for text in files"},
|
||||
"run_command": {Name: "run_command", RequiresApproval: true, Description: "Run a shell command"},
|
||||
"run_tests": {Name: "run_tests", RequiresApproval: true, Description: "Run the test suite"},
|
||||
"lint_file": {Name: "lint_file", Description: "Lint a file"},
|
||||
"git_commit": {Name: "git_commit", RequiresApproval: true, Description: "Create a git commit"},
|
||||
"git_diff": {Name: "git_diff", Description: "Show git diff"},
|
||||
"git_log": {Name: "git_log", Description: "Show git log"},
|
||||
"repo_map": {Name: "repo_map", Description: "Generate a repository map"},
|
||||
"read_persona": {Name: "read_persona", Description: "Read the persona definition"},
|
||||
"query_memory": {Name: "query_memory", Description: "Query the memory store"},
|
||||
"check_growth": {Name: "check_growth", Description: "Check growth delta"},
|
||||
"diagnose_behavior": {Name: "diagnose_behavior", Description: "Diagnose a behavior issue"},
|
||||
"find_capability": {Name: "find_capability", Description: "Find a capability by description"},
|
||||
}
|
||||
@@ -88,7 +89,10 @@ func main() {
|
||||
|
||||
switch cmd {
|
||||
case "validate":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: tool-protocol validate <request-json>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: tool-protocol validate <request-json>")
|
||||
os.Exit(1)
|
||||
}
|
||||
var req ToolRequest
|
||||
if err := json.Unmarshal([]byte(args[0]), &req); err != nil {
|
||||
out, _ := json.Marshal(ToolEvent{Kind: "error", Error: fmt.Sprintf("invalid JSON: %v", err)})
|
||||
@@ -98,20 +102,32 @@ func main() {
|
||||
event, ok := validate(req)
|
||||
out, _ := json.MarshalIndent(event, "", " ")
|
||||
fmt.Println(string(out))
|
||||
if !ok { os.Exit(1) }
|
||||
if !ok {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
case "list-tools":
|
||||
var names []string
|
||||
for name := range TOOL_INDEX { names = append(names, name) }
|
||||
for name := range TOOL_INDEX {
|
||||
names = append(names, name)
|
||||
}
|
||||
out, _ := json.MarshalIndent(names, "", " ")
|
||||
fmt.Println(string(out))
|
||||
|
||||
case "requires-approval":
|
||||
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: tool-protocol requires-approval <tool-name>"); os.Exit(1) }
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: tool-protocol requires-approval <tool-name>")
|
||||
os.Exit(1)
|
||||
}
|
||||
name := args[0]
|
||||
if alias, ok := ALIASES[name]; ok { name = alias }
|
||||
if alias, ok := ALIASES[name]; ok {
|
||||
name = alias
|
||||
}
|
||||
def, ok := TOOL_INDEX[name]
|
||||
if !ok { fmt.Println("null"); return }
|
||||
if !ok {
|
||||
fmt.Println("null")
|
||||
return
|
||||
}
|
||||
out, _ := json.Marshal(map[string]bool{"requires_approval": def.RequiresApproval})
|
||||
fmt.Println(string(out))
|
||||
|
||||
|
||||
Binary file not shown.
+1
-1
@@ -47,7 +47,7 @@ type Model struct {
|
||||
statusText string
|
||||
width int
|
||||
height int
|
||||
focusedChannel string // "chat" or "task"
|
||||
focusedChannel string // "chat" or "task"
|
||||
}
|
||||
|
||||
type ChatDisplay struct {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+23
-12
@@ -4,10 +4,11 @@
|
||||
// preference, urgency, learning, contradiction), and model reflection.
|
||||
//
|
||||
// Usage:
|
||||
// witness detect <message> [--tool-error <e>] [--task-status <s>] [--recent-topics <t1,t2>]
|
||||
// witness extract-topic <text>
|
||||
// witness is-correction <text>
|
||||
// witness reflect <signals-json> [--context <ctx>]
|
||||
//
|
||||
// witness detect <message> [--tool-error <e>] [--task-status <s>] [--recent-topics <t1,t2>]
|
||||
// witness extract-topic <text>
|
||||
// witness is-correction <text>
|
||||
// witness reflect <signals-json> [--context <ctx>]
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -214,10 +215,10 @@ func witnessReflect(signals map[string]interface{}, context string) string {
|
||||
string(signalsJSON), ctx)
|
||||
|
||||
data := map[string]interface{}{
|
||||
"model": model,
|
||||
"prompt": prompt,
|
||||
"stream": false,
|
||||
"options": map[string]interface{}{"temperature": 0.3, "num_predict": 100, "num_ctx": 8192},
|
||||
"model": model,
|
||||
"prompt": prompt,
|
||||
"stream": false,
|
||||
"options": map[string]interface{}{"temperature": 0.3, "num_predict": 100, "num_ctx": 8192},
|
||||
}
|
||||
body, _ := json.Marshal(data)
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
@@ -259,16 +260,24 @@ func main() {
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch args[i] {
|
||||
case "--tool-error":
|
||||
if i+1 < len(args) { toolError = args[i+1]; i++ }
|
||||
if i+1 < len(args) {
|
||||
toolError = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--task-status":
|
||||
if i+1 < len(args) { taskStatus = args[i+1]; i++ }
|
||||
if i+1 < len(args) {
|
||||
taskStatus = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--recent-topics":
|
||||
if i+1 < len(args) {
|
||||
recentTopics = strings.Split(args[i+1], ",")
|
||||
i++
|
||||
}
|
||||
default:
|
||||
if message == "" { message = args[i] }
|
||||
if message == "" {
|
||||
message = args[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
signals := detectSignals(message, toolError, taskStatus, recentTopics)
|
||||
@@ -294,7 +303,9 @@ func main() {
|
||||
case "reflect":
|
||||
signalsJSON := "{}"
|
||||
context := ""
|
||||
if len(args) > 0 { signalsJSON = args[0] }
|
||||
if len(args) > 0 {
|
||||
signalsJSON = args[0]
|
||||
}
|
||||
for i := 1; i < len(args); i++ {
|
||||
if args[i] == "--context" && i+1 < len(args) {
|
||||
context = args[i+1]
|
||||
|
||||
Binary file not shown.
+28
-12
@@ -3,11 +3,12 @@
|
||||
// routes to builders, tracks completion.
|
||||
//
|
||||
// Usage:
|
||||
// work-manager create-batch <description> <items-json>
|
||||
// work-manager list-batches
|
||||
// work-manager get-next
|
||||
// work-manager complete <batch-id> [result]
|
||||
// work-manager fail <batch-id> [result]
|
||||
//
|
||||
// work-manager create-batch <description> <items-json>
|
||||
// work-manager list-batches
|
||||
// work-manager get-next
|
||||
// work-manager complete <batch-id> [result]
|
||||
// work-manager fail <batch-id> [result]
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -54,7 +55,9 @@ func dataDir() string {
|
||||
|
||||
func loadBatches() []Batch {
|
||||
data, err := os.ReadFile(filepath.Join(dataDir(), "batches.json"))
|
||||
if err != nil { return []Batch{} }
|
||||
if err != nil {
|
||||
return []Batch{}
|
||||
}
|
||||
var batches []Batch
|
||||
json.Unmarshal(data, &batches)
|
||||
return batches
|
||||
@@ -79,17 +82,26 @@ func main() {
|
||||
case "create-batch":
|
||||
description := ""
|
||||
var items []WorkItem
|
||||
if len(args) > 0 { description = args[0] }
|
||||
if len(args) > 1 { json.Unmarshal([]byte(args[1]), &items) }
|
||||
if len(args) > 0 {
|
||||
description = args[0]
|
||||
}
|
||||
if len(args) > 1 {
|
||||
json.Unmarshal([]byte(args[1]), &items)
|
||||
}
|
||||
|
||||
files := []string{}
|
||||
for _, item := range items {
|
||||
if item.File != "" {
|
||||
found := false
|
||||
for _, f := range files {
|
||||
if f == item.File { found = true; break }
|
||||
if f == item.File {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
files = append(files, item.File)
|
||||
}
|
||||
if !found { files = append(files, item.File) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +138,9 @@ func main() {
|
||||
if batches[i].ID == args[0] {
|
||||
batches[i].Status = "complete"
|
||||
batches[i].Completed = time.Now().UTC().Format(time.RFC3339)
|
||||
if len(args) > 1 { batches[i].Result = args[1] }
|
||||
if len(args) > 1 {
|
||||
batches[i].Result = args[1]
|
||||
}
|
||||
saveBatches(batches)
|
||||
fmt.Println("completed:", args[0])
|
||||
return
|
||||
@@ -140,7 +154,9 @@ func main() {
|
||||
for i := range batches {
|
||||
if batches[i].ID == args[0] {
|
||||
batches[i].Status = "failed"
|
||||
if len(args) > 1 { batches[i].Result = args[1] }
|
||||
if len(args) > 1 {
|
||||
batches[i].Result = args[1]
|
||||
}
|
||||
saveBatches(batches)
|
||||
fmt.Println("failed:", args[0])
|
||||
return
|
||||
|
||||
Binary file not shown.
@@ -12,14 +12,15 @@ pub struct AttentionCapsule {
|
||||
|
||||
impl AttentionCapsule {
|
||||
pub fn new(max_entries: usize) -> Self {
|
||||
AttentionCapsule { entries: vec![], max_entries }
|
||||
AttentionCapsule {
|
||||
entries: vec![],
|
||||
max_entries,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capture(&mut self, messages: &[serde_json::Value]) -> Vec<serde_json::Value> {
|
||||
let captured: Vec<serde_json::Value> = messages.iter()
|
||||
.take(self.max_entries)
|
||||
.cloned()
|
||||
.collect();
|
||||
let captured: Vec<serde_json::Value> =
|
||||
messages.iter().take(self.max_entries).cloned().collect();
|
||||
self.entries = captured.clone();
|
||||
captured
|
||||
}
|
||||
|
||||
@@ -22,18 +22,32 @@ pub fn compute_hash(prev_hash: &str, entry: &serde_json::Value) -> String {
|
||||
hex::encode(hasher.finalize())
|
||||
}
|
||||
|
||||
pub fn append_entry(entries: &mut Vec<LedgerEntry>, entry_type: &str, entry_id: i64, details: serde_json::Value) -> LedgerEntry {
|
||||
let prev_hash = entries.last().map(|e| e.hash.clone()).unwrap_or("genesis".to_string());
|
||||
pub fn append_entry(
|
||||
entries: &mut Vec<LedgerEntry>,
|
||||
entry_type: &str,
|
||||
entry_id: i64,
|
||||
details: serde_json::Value,
|
||||
) -> LedgerEntry {
|
||||
let prev_hash = entries
|
||||
.last()
|
||||
.map(|e| e.hash.clone())
|
||||
.unwrap_or("genesis".to_string());
|
||||
let mut entry = LedgerEntry {
|
||||
entry_type: entry_type.to_string(),
|
||||
entry_id,
|
||||
details,
|
||||
timestamp: format!("{}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs()),
|
||||
timestamp: format!(
|
||||
"{}",
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
),
|
||||
prev_hash,
|
||||
hash: String::new(),
|
||||
};
|
||||
// Compute hash over the entry WITHOUT the hash field
|
||||
let mut hash_input = serde_json::json!({
|
||||
let hash_input = serde_json::json!({
|
||||
"entry_type": entry.entry_type,
|
||||
"entry_id": entry.entry_id,
|
||||
"details": entry.details,
|
||||
@@ -74,8 +88,18 @@ mod tests {
|
||||
#[test]
|
||||
fn test_append_and_verify() {
|
||||
let mut entries = Vec::new();
|
||||
append_entry(&mut entries, "promotion", 1, serde_json::json!({"status": "promoted"}));
|
||||
append_entry(&mut entries, "gate_result", 2, serde_json::json!({"verdict": "PASS"}));
|
||||
append_entry(
|
||||
&mut entries,
|
||||
"promotion",
|
||||
1,
|
||||
serde_json::json!({"status": "promoted"}),
|
||||
);
|
||||
append_entry(
|
||||
&mut entries,
|
||||
"gate_result",
|
||||
2,
|
||||
serde_json::json!({"verdict": "PASS"}),
|
||||
);
|
||||
let (valid, count) = verify_chain(&entries);
|
||||
assert!(valid);
|
||||
assert_eq!(count, 2);
|
||||
|
||||
@@ -18,10 +18,19 @@ pub struct BehaviourLedger {
|
||||
}
|
||||
|
||||
impl BehaviourLedger {
|
||||
pub fn new() -> Self { BehaviourLedger { behaviours: BTreeMap::new() } }
|
||||
pub fn new() -> Self {
|
||||
BehaviourLedger {
|
||||
behaviours: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define(&mut self, behaviour_id: &str, owning_project: &str,
|
||||
description: &str, evidence_refs: Vec<String>) -> BehaviourEntry {
|
||||
pub fn define(
|
||||
&mut self,
|
||||
behaviour_id: &str,
|
||||
owning_project: &str,
|
||||
description: &str,
|
||||
evidence_refs: Vec<String>,
|
||||
) -> BehaviourEntry {
|
||||
let entry = BehaviourEntry {
|
||||
behaviour_id: behaviour_id.to_string(),
|
||||
owning_project: owning_project.to_string(),
|
||||
@@ -30,7 +39,8 @@ impl BehaviourLedger {
|
||||
defined_at: now(),
|
||||
status: "defined".to_string(),
|
||||
};
|
||||
self.behaviours.insert(behaviour_id.to_string(), entry.clone());
|
||||
self.behaviours
|
||||
.insert(behaviour_id.to_string(), entry.clone());
|
||||
entry
|
||||
}
|
||||
|
||||
@@ -39,8 +49,20 @@ impl BehaviourLedger {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BehaviourLedger {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn now() -> String {
|
||||
format!("{}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs())
|
||||
format!(
|
||||
"{}",
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -29,7 +29,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_summarize() {
|
||||
let b = summarize("STANDARD", vec!["risk1".into()], serde_json::json!({"migration": []}));
|
||||
let b = summarize(
|
||||
"STANDARD",
|
||||
vec!["risk1".into()],
|
||||
serde_json::json!({"migration": []}),
|
||||
);
|
||||
assert_eq!(b.depth, "STANDARD");
|
||||
assert_eq!(b.risks.len(), 1);
|
||||
}
|
||||
|
||||
@@ -8,25 +8,45 @@ pub struct CapabilitySelection {
|
||||
pub floor_tools: Vec<String>,
|
||||
}
|
||||
|
||||
const FLOOR_TOOLS: &[&str] = &["read_file", "list_directory", "glob_files", "grep_files", "run_command"];
|
||||
const FLOOR_TOOLS: &[&str] = &[
|
||||
"read_file",
|
||||
"list_directory",
|
||||
"glob_files",
|
||||
"grep_files",
|
||||
"run_command",
|
||||
];
|
||||
|
||||
const ALL_TOOLS: &[&str] = &[
|
||||
"read_file", "write_file", "edit_file", "list_directory", "glob_files",
|
||||
"grep_files", "run_command", "run_tests", "lint_file", "git_commit",
|
||||
"git_diff", "git_log", "repo_map", "read_persona", "query_memory",
|
||||
"check_growth", "diagnose_behavior", "find_capability",
|
||||
"read_file",
|
||||
"write_file",
|
||||
"edit_file",
|
||||
"list_directory",
|
||||
"glob_files",
|
||||
"grep_files",
|
||||
"run_command",
|
||||
"run_tests",
|
||||
"lint_file",
|
||||
"git_commit",
|
||||
"git_diff",
|
||||
"git_log",
|
||||
"repo_map",
|
||||
"read_persona",
|
||||
"query_memory",
|
||||
"check_growth",
|
||||
"diagnose_behavior",
|
||||
"find_capability",
|
||||
];
|
||||
|
||||
/// Select tools for a job based on the description.
|
||||
pub fn select_for_job(description: &str) -> CapabilitySelection {
|
||||
let lower = description.to_lowercase();
|
||||
let mut selected: Vec<String> = Vec::new();
|
||||
|
||||
|
||||
// Always include floor tools
|
||||
for tool in FLOOR_TOOLS {
|
||||
selected.push(tool.to_string());
|
||||
}
|
||||
|
||||
|
||||
// Add context-specific tools based on keywords
|
||||
if lower.contains("test") || lower.contains("verify") {
|
||||
selected.push("run_tests".to_string());
|
||||
@@ -52,11 +72,11 @@ pub fn select_for_job(description: &str) -> CapabilitySelection {
|
||||
if lower.contains("map") || lower.contains("structure") {
|
||||
selected.push("repo_map".to_string());
|
||||
}
|
||||
|
||||
|
||||
// Deduplicate and sort
|
||||
selected.sort();
|
||||
selected.dedup();
|
||||
|
||||
|
||||
CapabilitySelection {
|
||||
names: selected,
|
||||
floor_tools: FLOOR_TOOLS.iter().map(|s| s.to_string()).collect(),
|
||||
|
||||
@@ -15,17 +15,38 @@ pub struct CapabilityLedger {
|
||||
}
|
||||
|
||||
impl CapabilityLedger {
|
||||
pub fn new() -> Self { CapabilityLedger { capabilities: BTreeMap::new() } }
|
||||
pub fn new() -> Self {
|
||||
CapabilityLedger {
|
||||
capabilities: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
pub fn register(&mut self, name: &str, provider: &str) {
|
||||
self.capabilities.insert(name.to_string(), CapabilityEntry {
|
||||
name: name.to_string(), provider: provider.to_string(),
|
||||
registered_at: now(), active: true,
|
||||
});
|
||||
self.capabilities.insert(
|
||||
name.to_string(),
|
||||
CapabilityEntry {
|
||||
name: name.to_string(),
|
||||
provider: provider.to_string(),
|
||||
registered_at: now(),
|
||||
active: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CapabilityLedger {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn now() -> String {
|
||||
format!("{}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs())
|
||||
format!(
|
||||
"{}",
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -73,22 +73,28 @@ fn str_list(v: Option<&pyjson::Json>) -> Vec<String> {
|
||||
/// cs_evaluate_fit({"contracts": [...], "candidate": {...}}) -> fit dict
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cs_evaluate_fit(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|text| arg_json(&text)).and_then(|a| {
|
||||
let contracts = str_list(get(&a, "contracts"));
|
||||
let candidate = get(&a, "candidate").cloned().ok_or("arg.candidate required")?;
|
||||
Ok(scoring::evaluate_fit(&contracts, &candidate))
|
||||
});
|
||||
let result = read_arg(arg)
|
||||
.and_then(|text| arg_json(&text))
|
||||
.and_then(|a| {
|
||||
let contracts = str_list(get(&a, "contracts"));
|
||||
let candidate = get(&a, "candidate")
|
||||
.cloned()
|
||||
.ok_or("arg.candidate required")?;
|
||||
Ok(scoring::evaluate_fit(&contracts, &candidate))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
/// cs_score_card({"card": {...}, "query": "..."}) -> number
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cs_score_card(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|text| arg_json(&text)).and_then(|a| {
|
||||
let card = get(&a, "card").cloned().ok_or("arg.card required")?;
|
||||
let query = get_str(&a, "query").unwrap_or("");
|
||||
Ok(pyjson::Json::Num(scoring::score_card(&card, query)))
|
||||
});
|
||||
let result = read_arg(arg)
|
||||
.and_then(|text| arg_json(&text))
|
||||
.and_then(|a| {
|
||||
let card = get(&a, "card").cloned().ok_or("arg.card required")?;
|
||||
let query = get_str(&a, "query").unwrap_or("");
|
||||
Ok(pyjson::Json::Num(scoring::score_card(&card, query)))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
|
||||
@@ -176,13 +176,8 @@ impl<'a> Parser<'a> {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
+ ((cp - 0xD800) << 10)
|
||||
+ (lo - 0xDC00);
|
||||
out.push(
|
||||
char::from_u32(c)
|
||||
.ok_or("bad surrogate pair")?,
|
||||
);
|
||||
let c = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00);
|
||||
out.push(char::from_u32(c).ok_or("bad surrogate pair")?);
|
||||
} else {
|
||||
// lone high surrogate — Python keeps it as
|
||||
// an escaped lone surrogate; we degrade to
|
||||
@@ -205,8 +200,8 @@ impl<'a> Parser<'a> {
|
||||
// consume one UTF-8 scalar
|
||||
let s = &self.b[self.i..];
|
||||
let ch_len = utf8_len(s[0]);
|
||||
let chunk = std::str::from_utf8(&s[..ch_len.min(s.len())])
|
||||
.map_err(|_| "bad utf8")?;
|
||||
let chunk =
|
||||
std::str::from_utf8(&s[..ch_len.min(s.len())]).map_err(|_| "bad utf8")?;
|
||||
out.push_str(chunk);
|
||||
self.i += ch_len;
|
||||
}
|
||||
@@ -218,8 +213,7 @@ impl<'a> Parser<'a> {
|
||||
if self.i + 4 > self.b.len() {
|
||||
return Err("short \\u escape".into());
|
||||
}
|
||||
let s = std::str::from_utf8(&self.b[self.i + 1..self.i + 5])
|
||||
.map_err(|_| "bad \\u")?;
|
||||
let s = std::str::from_utf8(&self.b[self.i + 1..self.i + 5]).map_err(|_| "bad \\u")?;
|
||||
let v = u32::from_str_radix(s, 16).map_err(|_| "bad \\u digits")?;
|
||||
self.i += 5; // 'u' + 4 hex digits (caller consumed the backslash)
|
||||
Ok(v)
|
||||
|
||||
Loaded 100 of 196 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user