Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3497d2b7a9 | ||
|
|
60a21dc7da |
No files matched your search
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: land
|
||||
description: Review and land one small Rune change through the governed PR workflow.
|
||||
disable-model-invocation: true
|
||||
metadata:
|
||||
delta-action: land
|
||||
---
|
||||
|
||||
# Land one small diff
|
||||
|
||||
1. Read applicable `AGENTS.md` rules and the repo's PR/merge workflow.
|
||||
2. Confirm the issue, exact diff, target branch, and permission to publish and land.
|
||||
3. Keep one small, reversible change; preserve unrelated work.
|
||||
4. For bugs, follow `docs/bugfix-contract.md`: red test first, root cause, discharge.
|
||||
5. Run required tests, static analysis, canaries, and henxels; record results.
|
||||
6. Get independent `/review` per `docs/adversarial-review.md`; clear blockers.
|
||||
7. Inspect remotes; publish the PR to the approved forge, never `local`.
|
||||
8. Require human approval and green required CI on the exact PR head; recheck changed heads.
|
||||
9. Load `report-landed`; use the repo's merge workflow. Stop on conflicts; never force-push or bypass hooks.
|
||||
10. Verify the target commit and CI, then report the actual landing result and remaining blockers.
|
||||
@@ -18,4 +18,4 @@ jobs:
|
||||
python3 -m unittest -v tests.test_gitea_backup
|
||||
python3 src/rune/canary_gitea_automation.py
|
||||
- name: Create consistent off-disk Gitea backup
|
||||
run: sudo /usr/local/bin/gitea-backup-pc.sh
|
||||
run: sudo /usr/local/sbin/rune-gitea-backup
|
||||
@@ -7,20 +7,47 @@ on:
|
||||
types: [opened, edited]
|
||||
|
||||
jobs:
|
||||
# SINGLE-PASS FILING (2026-10-07, Nick's first-time-correct directive):
|
||||
# the old design ran TWO jobs on submission — priority-gate (which saw
|
||||
# no P-label and posted the ⚠️ warning) and auto-label (which inferred
|
||||
# and applied the P-label). The gate ran BEFORE the inference that
|
||||
# would have made the warning unnecessary: every keyword-inferrable
|
||||
# submission ate a spurious warning, a flag add/remove cycle, and a
|
||||
# wasted workflow run. The fix is ORDER: infer → apply → THEN gate.
|
||||
# A submission whose priority is inferable gets its P-label in this
|
||||
# same run; the warning fires only when inference genuinely produced
|
||||
# nothing (a true filing gap, not a race the robot loses to itself).
|
||||
# PRIORITY GATE (2026-09-04): every issue must carry exactly one of
|
||||
# P0/P1/P2/P3. An issue that lands without one gets 'unprioritized' +
|
||||
# a demand comment — filing is not complete until prioritized.
|
||||
priority-gate:
|
||||
if: github.event_name == 'issues' && github.event.action != 'labeled' && github.event.issue.state == 'open'
|
||||
runs-on: rune-ci-desktop
|
||||
steps:
|
||||
- name: Enforce priority label
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const issue = context.payload.issue;
|
||||
if (!issue) return;
|
||||
const labels = (issue.labels || []).map(l => l.name);
|
||||
const priorities = ['P0 — critical', 'P1 — high', 'P2 — medium', 'P3 — low'];
|
||||
const has = labels.filter(l => priorities.includes(l));
|
||||
if (has.length === 1) {
|
||||
// Prioritized — clear the flag if it was set.
|
||||
if (labels.includes('unprioritized')) {
|
||||
await github.request('DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{id}', {
|
||||
owner: context.repo.owner, repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
id: issue.labels.find(l => l.name === 'unprioritized').id,
|
||||
}).catch(e => { if (e.status !== 404) throw e; });
|
||||
}
|
||||
return;
|
||||
}
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner, repo: context.repo.repo,
|
||||
issue_number: issue.number, labels: ['unprioritized'],
|
||||
});
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner, repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
body: `⚠️ **Priority gate:** this issue has no priority. Assign exactly one of **P0 — critical** (spine/correctness/blocks), **P1 — high** (material value or real defect), **P2 — medium** (quality/consolidation), **P3 — low** (measurement/deferred). An issue without a priority is not filed.`,
|
||||
});
|
||||
|
||||
auto-label:
|
||||
runs-on: rune-ci-desktop
|
||||
steps:
|
||||
- name: Infer, apply, then gate-check (one pass)
|
||||
- name: Analyze and label
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
@@ -38,7 +65,6 @@ jobs:
|
||||
return;
|
||||
}
|
||||
const action = context.payload.action;
|
||||
const isIssue = context.payload.issue !== undefined;
|
||||
const title = context.payload.issue?.title || context.payload.pull_request?.title || '';
|
||||
const body = context.payload.issue?.body || context.payload.pull_request?.body || '';
|
||||
const text = (title + ' ' + body).toLowerCase();
|
||||
@@ -117,7 +143,7 @@ jobs:
|
||||
// normalization). Assignment from the TITLE prefix first
|
||||
// ([P1]/P1:/priority=...), then keyword inference using the
|
||||
// gate's own rule set (the scale lives in ONE place — the
|
||||
// gate check at the bottom of THIS job).
|
||||
// priority-gate job above).
|
||||
const pMatch = title.match(/\bP([0-3])\b/);
|
||||
const priorityLabelNames = ['P0 — critical', 'P1 — high', 'P2 — medium', 'P3 — low'];
|
||||
if (pMatch) {
|
||||
@@ -180,16 +206,9 @@ jobs:
|
||||
labels: missingDesired,
|
||||
});
|
||||
}
|
||||
|
||||
// ---- PRIORITY GATE (runs LAST — after inference and
|
||||
// reconciliation, so the verdict reflects the labels THIS run
|
||||
// just applied, not a pre-inference snapshot). Issue-scoped:
|
||||
// the filing contract governs issues; PRs get inferred labels
|
||||
// but are not filing units.
|
||||
if (!isIssue) {
|
||||
console.log(`PR #${issueNumber}: labels applied, gate skipped (gate is issue-scoped).`);
|
||||
return;
|
||||
}
|
||||
// The priority gate can flag a duplicate before this job
|
||||
// reconciles it. Clear the flag only AFTER verifying exactly one
|
||||
// surviving P-label against Gitea's current state.
|
||||
const reconciled = await github.rest.issues.listLabelsOnIssue({
|
||||
owner: context.repo.owner, repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
@@ -197,33 +216,11 @@ jobs:
|
||||
const actual = reconciled.data;
|
||||
const activePriority = actual.filter(l => priorityLabelNames.includes(l.name));
|
||||
const flag = actual.find(l => l.name === 'unprioritized');
|
||||
if (activePriority.length === 1) {
|
||||
// Prioritized (by human or by this run's inference). Clear
|
||||
// any stale flag — no warning is ever posted on this path.
|
||||
if (flag) {
|
||||
await github.request('DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{id}', {
|
||||
owner: context.repo.owner, repo: context.repo.repo,
|
||||
issue_number: issueNumber, id: flag.id,
|
||||
});
|
||||
}
|
||||
console.log(`Priority gate: satisfied (${activePriority[0].name}).`);
|
||||
return;
|
||||
}
|
||||
// Genuinely unprioritized: inference produced nothing AND the
|
||||
// caller set nothing. Flag + demand comment — the filing gap
|
||||
// is real, not a race artifact.
|
||||
const reason = activePriority.length === 0
|
||||
? 'no priority'
|
||||
: `${activePriority.length} priority labels (exactly one required)`;
|
||||
if (!flag) {
|
||||
await github.rest.issues.addLabels({
|
||||
if (activePriority.length === 1 && flag) {
|
||||
await github.request('DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{id}', {
|
||||
owner: context.repo.owner, repo: context.repo.repo,
|
||||
issue_number: issueNumber, labels: ['unprioritized'],
|
||||
issue_number: issueNumber, id: flag.id,
|
||||
});
|
||||
}
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner, repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
body: `⚠️ **Priority gate:** this issue has ${reason}. Assign exactly one of **P0 — critical** (spine/correctness/blocks), **P1 — high** (material value or real defect), **P2 — medium** (quality/consolidation), **P3 — low** (measurement/deferred). An issue without a priority is not filed.`,
|
||||
});
|
||||
console.log(`Priority gate: flagged — ${reason}.`);
|
||||
console.log(`Removed managed labels: ${staleManaged.join(', ') || 'none'}`);
|
||||
console.log(`Added managed labels: ${missingDesired.join(', ') || 'none'}`);
|
||||
+222
-160
@@ -1,172 +1,234 @@
|
||||
name: Auto-version and Release
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
branches:
|
||||
- master
|
||||
types: [closed]
|
||||
branches: [master]
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
branches: [master]
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: rune-ci-desktop
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Skip if PR is not merged (direct pushes continue to convergence)
|
||||
run: "MERGED=\"${{ gitea.event.pull_request.merged }}\"\nEVENT=\"${{ gitea.event_name\
|
||||
\ }}\"\nif [ \"$EVENT\" = \"pull_request\" ] && [ \"$MERGED\" != \"true\"\
|
||||
\ ]; then\n echo \"PR not merged \u2014 skipping release\"\n exit 0\nfi\n\
|
||||
echo \"event=$EVENT \u2014 continuing\"\n"
|
||||
- name: Read reviewed semantic version
|
||||
run: 'VERSION=$(python3 -c ''import re; text=open("src/rune/__init__.py").read();
|
||||
print(re.search(r"__version__ = \"([0-9]+\.[0-9]+\.[0-9]+)\"", text).group(1))'')
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
echo "RELEASE_VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||
- name: Skip if PR is not merged (direct pushes continue to convergence)
|
||||
run: |
|
||||
MERGED="${{ gitea.event.pull_request.merged }}"
|
||||
EVENT="${{ gitea.event_name }}"
|
||||
if [ "$EVENT" = "pull_request" ] && [ "$MERGED" != "true" ]; then
|
||||
echo "PR not merged — skipping release"
|
||||
exit 0
|
||||
fi
|
||||
echo "event=$EVENT — continuing"
|
||||
|
||||
echo "Release version: $VERSION"
|
||||
- name: Read reviewed semantic version
|
||||
run: |
|
||||
VERSION=$(python3 -c 'import re; text=open("src/rune/__init__.py").read(); print(re.search(r"__version__ = \"([0-9]+\.[0-9]+\.[0-9]+)\"", text).group(1))')
|
||||
echo "RELEASE_VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||
echo "Release version: $VERSION"
|
||||
|
||||
'
|
||||
- name: Auto-bump if the PR did not carry a version bump
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
RELEASE_SERVER_URL: ${{ gitea.server_url }}
|
||||
RELEASE_REPO: ${{ gitea.repository }}
|
||||
PR_TITLE: ${{ gitea.event.pull_request.title }}
|
||||
PR_BODY: ${{ gitea.event.pull_request.body }}
|
||||
PR_NUMBER: ${{ gitea.event.pull_request.number }}
|
||||
run: "LATEST=$(git tag --sort=-v:refname | head -1 | sed 's/^v//')\nif [ -z\
|
||||
\ \"$LATEST\" ]; then\n echo \"No previous tags \u2014 releasing first version\
|
||||
\ $RELEASE_VERSION\"\n exit 0\nfi\nif [ \"$LATEST\" != \"$RELEASE_VERSION\"\
|
||||
\ ]; then\n if [ \"$(printf '%s\\n%s\\n' \"$LATEST\" \"$RELEASE_VERSION\"\
|
||||
\ | sort -V | head -1)\" = \"$RELEASE_VERSION\" ]; then\n echo \"::warning::VERSION-BEHIND-TAG\
|
||||
\ ANOMALY (#192): master=$RELEASE_VERSION < latest tag v$LATEST \u2014 bumping\
|
||||
\ from master version; reconcile the tag lineage\"\n else\n echo \"Version\
|
||||
\ $RELEASE_VERSION > last tag v$LATEST \u2014 bump rode the PR\"\n exit\
|
||||
\ 0\n fi\nfi\n# semver level: PR title on pull_request events; on push events\n\
|
||||
# (direct master pushes bypass PR merges \u2014 observed 2026-09-10,\n# version\
|
||||
\ stuck at 0.66.0 through ~15 substantive commits), the\n# warranted bump\
|
||||
\ comes from scripts/version_convergence.py over\n# commits since the last\
|
||||
\ tag. chore(release) commits never\n# warrant a bump \u2192 the bump commit\
|
||||
\ cannot recurse.\nif [ -z \"$PR_TITLE\" ] || [ \"$PR_TITLE\" = \"null\" ];\
|
||||
\ then\n # Recursive-loop guard: HEAD being a bump commit means THIS\n #\
|
||||
\ push already applied the bump \u2014 do not re-bump. The decision\n # lives\
|
||||
\ in version_convergence (--is-release-subject), one\n # source of truth\
|
||||
\ shared with the regression test.\n HEAD_SUBJECT=$(git log -1 --format=%s)\n\
|
||||
\ if python3 scripts/version_convergence.py --is-release-subject \"$HEAD_SUBJECT\"\
|
||||
; then\n echo \"HEAD is a release bump \u2014 loop guard, no re-bump\"\n\
|
||||
\ exit 0\n fi\n CONVERGENCE=$(python3 scripts/version_convergence.py)\n\
|
||||
\ WARRANTED=$(echo \"$CONVERGENCE\" | python3 -c \"import json,sys; d=json.load(sys.stdin);\
|
||||
\ print(d.get('warranted_bump') or '')\")\n CONVERGED=$(echo \"$CONVERGENCE\"\
|
||||
\ | python3 -c \"import json,sys; print(json.load(sys.stdin).get('converged',\
|
||||
\ 'true'))\")\n if [ \"$CONVERGED\" = \"True\" ]; then\n echo \"Already\
|
||||
\ converged \u2014 no bump needed\"\n exit 0\n fi\n echo \"push convergence:\
|
||||
\ warranted_bump=$WARRANTED\"\n if [ -z \"$WARRANTED\" ]; then\n echo\
|
||||
\ \"No substantive commits since last tag \u2014 no bump needed\"\n exit\
|
||||
\ 0\n fi\n PR_TITLE=\"$WARRANTED: converged release (push-to-master bump)\"\
|
||||
\nfi\nNEW=$(python3 scripts/semver_bump.py \"$RELEASE_VERSION\" \"$PR_TITLE\"\
|
||||
)\nexport NEW_VERSION=\"$NEW\"\necho \"Auto-bump: $RELEASE_VERSION -> $NEW\
|
||||
\ (direct commit to master \u2014 bump PRs retired, Nick policy 2026-09-08)\"\
|
||||
\npython3 - <<'PYBUMP'\nimport base64, json, os, sys, urllib.request\n\nTOKEN\
|
||||
\ = os.environ[\"GITEA_TOKEN\"]\nBASE = os.environ[\"RELEASE_SERVER_URL\"\
|
||||
] + \"/api/v1/repos/\" + os.environ[\"RELEASE_REPO\"]\nVERSION = os.environ[\"\
|
||||
RELEASE_VERSION\"]\nNEW = os.environ[\"NEW_VERSION\"]\nPR_TITLE = os.environ.get(\"\
|
||||
PR_TITLE\", \"\")\nPR_NUMBER = os.environ.get(\"PR_NUMBER\", \"\")\nSERVER\
|
||||
\ = os.environ[\"RELEASE_SERVER_URL\"].rstrip(\"/\")\npromoting_url = f\"\
|
||||
{SERVER}/{os.environ['RELEASE_REPO']}/pulls/{PR_NUMBER}\" if PR_NUMBER else\
|
||||
\ \"(unknown)\"\n\ndef api(path, method=\"GET\", data=None, ok=(200, 201)):\n\
|
||||
\ req = urllib.request.Request(\n BASE + path,\n data=json.dumps(data).encode()\
|
||||
\ if data is not None else None,\n headers={\"Authorization\": \"token\
|
||||
\ \" + TOKEN, \"Content-Type\": \"application/json\"},\n method=method,\n\
|
||||
\ )\n try:\n with urllib.request.urlopen(req, timeout=30) as\
|
||||
\ r:\n body, status = r.read(), r.status\n except urllib.error.HTTPError\
|
||||
\ as e:\n body, status = e.read(), e.code\n try:\n return\
|
||||
\ status, (json.loads(body) if body else {})\n except json.JSONDecodeError:\n\
|
||||
\ return status, {\"_raw\": body.decode(\"utf-8\", \"replace\")[:200]}\n\
|
||||
\n# Version surfaces: the TUI footer renders rune.__version__ AT CALL TIME\n\
|
||||
# (rune_tui.py VersionLabel), so __init__.py IS the displayed version.\n#\
|
||||
\ rune_tui.py header is the drift-guard that must stay in sync.\nsurfaces\
|
||||
\ = {\n \"src/rune/__init__.py\": [(f'__version__ = \"{VERSION}\"', f'__version__\
|
||||
\ = \"{NEW}\"')],\n \"src/rune/rune_tui.py\": [\n (f\"Version: v{VERSION}\"\
|
||||
, f\"Version: v{NEW}\"),\n (f\"Rune v{VERSION} |\", f\"Rune v{NEW}\
|
||||
\ |\"),\n ],\n \"src/rune/canary_gitea_automation.py\": [(f'\"{VERSION}\"\
|
||||
', f'\"{NEW}\"')],\n \"README.md\": [(f\"v{VERSION}\", f\"v{NEW}\")],\n\
|
||||
\ \"pyproject.toml\": [(f'version = \"{VERSION}\"', f'version = \"{NEW}\"\
|
||||
')],\n}\n\n# Fetch current master content, apply replacements, VERIFY all\
|
||||
\ six\n# surface patterns (five files + the TUI footer) agree on NEW before\n\
|
||||
# committing anything (TUI gate). The footer check was added after\n# the\
|
||||
\ 0.89.0 half-bump: a stale RELEASE_VERSION made both replace\n# pairs no-op;\
|
||||
\ the gate's RECOVER regex fixed the header only and\n# the footer silently\
|
||||
\ stayed 0.88.4, failing the banner test.\nedited = {}\nfor path, pairs in\
|
||||
\ surfaces.items():\n status, cur = api(f\"/contents/{path}?ref=master\"\
|
||||
)\n if status != 200:\n print(f\" skip {path} ({status})\"); continue\n\
|
||||
\ text = base64.b64decode(cur[\"content\"]).decode(\"utf-8\")\n changed\
|
||||
\ = text\n for old, newv in pairs:\n changed = changed.replace(old,\
|
||||
\ newv)\n if changed != text:\n edited[path] = (changed, cur[\"\
|
||||
sha\"])\n\n# In-memory gate: all five surfaces must now carry NEW\nimport\
|
||||
\ re\nVER = r\"\\d+\\.\\d+\\.\\d+\"\nchecks = [\n (\"src/rune/__init__.py\"\
|
||||
, rf'__version__ = \"({VER})\"'),\n (\"src/rune/rune_tui.py\", rf\"Version:\
|
||||
\ v({VER})\"),\n (\"src/rune/rune_tui.py\", rf\"Rune v({VER}) \\|\"),\n\
|
||||
\ (\"src/rune/canary_gitea_automation.py\", rf\"'__version__ = \\\"({VER})\\\
|
||||
\"'\"),\n (\"pyproject.toml\", rf'version = \"({VER})\"'),\n (\"README.md\"\
|
||||
, rf\"v({VER})\"),\n]\ndrifts = []\nfor rel, pat in checks:\n if rel not\
|
||||
\ in edited:\n # unchanged surface: must ALREADY carry NEW \u2014 if\
|
||||
\ it carries a\n # DIFFERENT version (base drift, e.g. pyproject at\
|
||||
\ 0.49.0 while\n # master is 0.54.1), RECOVER by force-editing to NEW.\
|
||||
\ The gate\n # stays: nothing commits unless every surface carries\
|
||||
\ NEW.\n status, cur = api(f\"/contents/{rel}?ref=master\")\n \
|
||||
\ if status != 200:\n drifts.append(f\"{rel}: unreadable ({status})\"\
|
||||
)\n continue\n text = base64.b64decode(cur.get(\"content\"\
|
||||
, \"\")).decode(\"utf-8\", \"replace\")\n hits = re.findall(pat, text)\n\
|
||||
\ if NEW not in hits:\n fixed = re.sub(pat, lambda m: m.group(0).replace(m.group(1),\
|
||||
\ NEW), text, count=1)\n if fixed != text:\n edited[rel]\
|
||||
\ = (fixed, cur[\"sha\"])\n print(f\" RECOVERED {rel}: base\
|
||||
\ drift {sorted(set(hits))} -> {NEW}\")\n else:\n \
|
||||
\ drifts.append(f\"{rel}: pattern present but unfixable (found {sorted(set(hits))})\"\
|
||||
)\n else:\n hits = re.findall(pat, edited[rel][0])\n if NEW\
|
||||
\ not in hits:\n drifts.append(f\"{rel}: edited content does not\
|
||||
\ carry {NEW}\")\nif drifts:\n print(\"VERSION-SURFACE DRIFT \u2014 bump\
|
||||
\ aborted, nothing committed:\")\n for d in drifts:\n print(f\"\
|
||||
\ - {d}\")\n sys.exit(1)\n\n# Commit ALL surfaces as ONE commit via ChangeFiles\n\
|
||||
# (POST /contents with a files[] array). The per-file contents PUT\n# created\
|
||||
\ one commit per version surface \u2014 five same-version \"bump\n# commits\"\
|
||||
\ per release (the phantom duplicate-bump cascade,\n# misdiagnosed as queue\
|
||||
\ drain since 0.66.2; root-caused T15 Part F\n# 2026-09-11). Git-data blob/tree\
|
||||
\ creation is 404 on this Gitea\n# build; ChangeFiles is the supported single-commit\
|
||||
\ primitive.\nmsg = f\"chore(release): auto-bump version to {NEW} \u2014 earned\
|
||||
\ by #{PR_NUMBER} ({PR_TITLE[:80]})\\n\\nPromotion record: {promoting_url}\"\
|
||||
\nops = [{\n \"operation\": \"update\",\n \"path\": path,\n \"content\"\
|
||||
: base64.b64encode(content.encode()).decode(), # ChangeFileOperation.content\
|
||||
\ is ContentBase64\n} for path, (content, _old_sha) in edited.items()]\nstatus,\
|
||||
\ r = api(\"/contents\", \"POST\", {\n \"branch\": \"master\",\n \"\
|
||||
message\": msg,\n \"files\": ops,\n})\nif status not in (200, 201):\n \
|
||||
\ print(f\"change-files failed ({status}): {str(r)[:300]}\"); sys.exit(1)\n\
|
||||
commit_sha = (r.get(\"commit\") or {}).get(\"sha\", \"?\") if isinstance(r,\
|
||||
\ dict) else \"?\"\nprint(f\" committed {len(ops)} surfaces as ONE commit\
|
||||
\ {str(commit_sha)[:7]}\")\n\nprint(f\"AUTO_BUMPED=true \u2014 version {NEW}\
|
||||
\ live on master; TUI footer will render v{NEW}\")\nwith open(os.environ[\"\
|
||||
GITHUB_ENV\"], \"a\") as env:\n env.write(f\"RELEASE_VERSION={NEW}\\n\"\
|
||||
)\n env.write(\"AUTO_BUMPED=true\\n\")\nPYBUMP\n"
|
||||
- name: Create evidence-derived release (SCAFFOLD-TRANCHE-009B)
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
RELEASE_SERVER_URL: ${{ gitea.server_url }}
|
||||
RELEASE_REPO: ${{ gitea.repository }}
|
||||
run: "# ONE note-generation authority: the tested release_notes module.\n# The\
|
||||
\ old PR-title/body paste path (which produced empty '##'\n# bodies on direct-push\
|
||||
\ releases) is REMOVED \u2014 governed evidence\n# from the scaffold store\
|
||||
\ is the source, not PR prose.\n# EXIT-NOTE TEMPLATE (Nick 2026-10-08): plain-English\
|
||||
\ summary of\n# what was worked on and submitted \u2014 the version-history\
|
||||
\ reader's\n# counterpart of the issue-entry template. Appended to the\n#\
|
||||
\ evidence-derived body so governed facts AND human narrative\n# both appear.\n\
|
||||
LAST_TAG=$(git tag --sort=-v:refname | head -1)\nEXIT_NOTE=$(python3 scripts/release_exit_note.py\
|
||||
\ --since \"$LAST_TAG\" --to HEAD) || EXIT_NOTE=\"\"\npython3 scripts/release_history_cli.py\
|
||||
\ init \\\n --version \"$RELEASE_VERSION\" \\\n --server \"$RELEASE_SERVER_URL\"\
|
||||
\ --repo \"$RELEASE_REPO\" \\\n --store store/scaffold/current.json \\\n\
|
||||
\ ${EXIT_NOTE:+--exit-note \"$EXIT_NOTE\"}"
|
||||
concurrency:
|
||||
group: auto-version-and-release-${ github.ref }
|
||||
cancel-in-progress: true
|
||||
- name: Auto-bump if the PR did not carry a version bump
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
RELEASE_SERVER_URL: ${{ gitea.server_url }}
|
||||
RELEASE_REPO: ${{ gitea.repository }}
|
||||
PR_TITLE: ${{ gitea.event.pull_request.title }}
|
||||
PR_BODY: ${{ gitea.event.pull_request.body }}
|
||||
PR_NUMBER: ${{ gitea.event.pull_request.number }}
|
||||
run: |
|
||||
LATEST=$(git tag --sort=-v:refname | head -1 | sed 's/^v//')
|
||||
if [ -z "$LATEST" ]; then
|
||||
echo "No previous tags — releasing first version $RELEASE_VERSION"
|
||||
exit 0
|
||||
fi
|
||||
if [ "$LATEST" != "$RELEASE_VERSION" ]; then
|
||||
if [ "$(printf '%s\n%s\n' "$LATEST" "$RELEASE_VERSION" | sort -V | head -1)" = "$RELEASE_VERSION" ]; then
|
||||
echo "::warning::VERSION-BEHIND-TAG ANOMALY (#192): master=$RELEASE_VERSION < latest tag v$LATEST — bumping from master version; reconcile the tag lineage"
|
||||
else
|
||||
echo "Version $RELEASE_VERSION > last tag v$LATEST — bump rode the PR"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
# semver level: PR title on pull_request events; on push events
|
||||
# (direct master pushes bypass PR merges — observed 2026-09-10,
|
||||
# version stuck at 0.66.0 through ~15 substantive commits), the
|
||||
# warranted bump comes from scripts/version_convergence.py over
|
||||
# commits since the last tag. chore(release) commits never
|
||||
# warrant a bump → the bump commit cannot recurse.
|
||||
if [ -z "$PR_TITLE" ] || [ "$PR_TITLE" = "null" ]; then
|
||||
# Recursive-loop guard: HEAD being a bump commit means THIS
|
||||
# push already applied the bump — do not re-bump. The decision
|
||||
# lives in version_convergence (--is-release-subject), one
|
||||
# source of truth shared with the regression test.
|
||||
HEAD_SUBJECT=$(git log -1 --format=%s)
|
||||
if python3 scripts/version_convergence.py --is-release-subject "$HEAD_SUBJECT"; then
|
||||
echo "HEAD is a release bump — loop guard, no re-bump"
|
||||
exit 0
|
||||
fi
|
||||
CONVERGENCE=$(python3 scripts/version_convergence.py)
|
||||
WARRANTED=$(echo "$CONVERGENCE" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('warranted_bump') or '')")
|
||||
CONVERGED=$(echo "$CONVERGENCE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('converged', 'true'))")
|
||||
if [ "$CONVERGED" = "True" ]; then
|
||||
echo "Already converged — no bump needed"
|
||||
exit 0
|
||||
fi
|
||||
echo "push convergence: warranted_bump=$WARRANTED"
|
||||
if [ -z "$WARRANTED" ]; then
|
||||
echo "No substantive commits since last tag — no bump needed"
|
||||
exit 0
|
||||
fi
|
||||
PR_TITLE="$WARRANTED: converged release (push-to-master bump)"
|
||||
fi
|
||||
NEW=$(python3 scripts/semver_bump.py "$RELEASE_VERSION" "$PR_TITLE")
|
||||
export NEW_VERSION="$NEW"
|
||||
echo "Auto-bump: $RELEASE_VERSION -> $NEW (direct commit to master — bump PRs retired, Nick policy 2026-09-08)"
|
||||
python3 - <<'PYBUMP'
|
||||
import base64, json, os, sys, urllib.request
|
||||
|
||||
TOKEN = os.environ["GITEA_TOKEN"]
|
||||
BASE = os.environ["RELEASE_SERVER_URL"] + "/api/v1/repos/" + os.environ["RELEASE_REPO"]
|
||||
VERSION = os.environ["RELEASE_VERSION"]
|
||||
NEW = os.environ["NEW_VERSION"]
|
||||
PR_TITLE = os.environ.get("PR_TITLE", "")
|
||||
PR_NUMBER = os.environ.get("PR_NUMBER", "")
|
||||
SERVER = os.environ["RELEASE_SERVER_URL"].rstrip("/")
|
||||
promoting_url = f"{SERVER}/{os.environ['RELEASE_REPO']}/pulls/{PR_NUMBER}" if PR_NUMBER else "(unknown)"
|
||||
|
||||
def api(path, method="GET", data=None, ok=(200, 201)):
|
||||
req = urllib.request.Request(
|
||||
BASE + path,
|
||||
data=json.dumps(data).encode() if data is not None else None,
|
||||
headers={"Authorization": "token " + TOKEN, "Content-Type": "application/json"},
|
||||
method=method,
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=30) as r:
|
||||
body, status = r.read(), r.status
|
||||
except urllib.error.HTTPError as e:
|
||||
body, status = e.read(), e.code
|
||||
try:
|
||||
return status, (json.loads(body) if body else {})
|
||||
except json.JSONDecodeError:
|
||||
return status, {"_raw": body.decode("utf-8", "replace")[:200]}
|
||||
|
||||
# Version surfaces: the TUI footer renders rune.__version__ AT CALL TIME
|
||||
# (rune_tui.py VersionLabel), so __init__.py IS the displayed version.
|
||||
# rune_tui.py header is the drift-guard that must stay in sync.
|
||||
surfaces = {
|
||||
"src/rune/__init__.py": [(f'__version__ = "{VERSION}"', f'__version__ = "{NEW}"')],
|
||||
"src/rune/rune_tui.py": [
|
||||
(f"Version: v{VERSION}", f"Version: v{NEW}"),
|
||||
(f"Rune v{VERSION} |", f"Rune v{NEW} |"),
|
||||
],
|
||||
"src/rune/canary_gitea_automation.py": [(f'"{VERSION}"', f'"{NEW}"')],
|
||||
"README.md": [(f"v{VERSION}", f"v{NEW}")],
|
||||
"pyproject.toml": [(f'version = "{VERSION}"', f'version = "{NEW}"')],
|
||||
}
|
||||
|
||||
# Fetch current master content, apply replacements, VERIFY all six
|
||||
# surface patterns (five files + the TUI footer) agree on NEW before
|
||||
# committing anything (TUI gate). The footer check was added after
|
||||
# the 0.89.0 half-bump: a stale RELEASE_VERSION made both replace
|
||||
# pairs no-op; the gate's RECOVER regex fixed the header only and
|
||||
# the footer silently stayed 0.88.4, failing the banner test.
|
||||
edited = {}
|
||||
for path, pairs in surfaces.items():
|
||||
status, cur = api(f"/contents/{path}?ref=master")
|
||||
if status != 200:
|
||||
print(f" skip {path} ({status})"); continue
|
||||
text = base64.b64decode(cur["content"]).decode("utf-8")
|
||||
changed = text
|
||||
for old, newv in pairs:
|
||||
changed = changed.replace(old, newv)
|
||||
if changed != text:
|
||||
edited[path] = (changed, cur["sha"])
|
||||
|
||||
# In-memory gate: all five surfaces must now carry NEW
|
||||
import re
|
||||
VER = r"\d+\.\d+\.\d+"
|
||||
checks = [
|
||||
("src/rune/__init__.py", rf'__version__ = "({VER})"'),
|
||||
("src/rune/rune_tui.py", rf"Version: v({VER})"),
|
||||
("src/rune/rune_tui.py", rf"Rune v({VER}) \|"),
|
||||
("src/rune/canary_gitea_automation.py", rf"'__version__ = \"({VER})\"'"),
|
||||
("pyproject.toml", rf'version = "({VER})"'),
|
||||
("README.md", rf"v({VER})"),
|
||||
]
|
||||
drifts = []
|
||||
for rel, pat in checks:
|
||||
if rel not in edited:
|
||||
# unchanged surface: must ALREADY carry NEW — if it carries a
|
||||
# DIFFERENT version (base drift, e.g. pyproject at 0.49.0 while
|
||||
# master is 0.54.1), RECOVER by force-editing to NEW. The gate
|
||||
# stays: nothing commits unless every surface carries NEW.
|
||||
status, cur = api(f"/contents/{rel}?ref=master")
|
||||
if status != 200:
|
||||
drifts.append(f"{rel}: unreadable ({status})")
|
||||
continue
|
||||
text = base64.b64decode(cur.get("content", "")).decode("utf-8", "replace")
|
||||
hits = re.findall(pat, text)
|
||||
if NEW not in hits:
|
||||
fixed = re.sub(pat, lambda m: m.group(0).replace(m.group(1), NEW), text, count=1)
|
||||
if fixed != text:
|
||||
edited[rel] = (fixed, cur["sha"])
|
||||
print(f" RECOVERED {rel}: base drift {sorted(set(hits))} -> {NEW}")
|
||||
else:
|
||||
drifts.append(f"{rel}: pattern present but unfixable (found {sorted(set(hits))})")
|
||||
else:
|
||||
hits = re.findall(pat, edited[rel][0])
|
||||
if NEW not in hits:
|
||||
drifts.append(f"{rel}: edited content does not carry {NEW}")
|
||||
if drifts:
|
||||
print("VERSION-SURFACE DRIFT — bump aborted, nothing committed:")
|
||||
for d in drifts:
|
||||
print(f" - {d}")
|
||||
sys.exit(1)
|
||||
|
||||
# Commit ALL surfaces as ONE commit via ChangeFiles
|
||||
# (POST /contents with a files[] array). The per-file contents PUT
|
||||
# created one commit per version surface — five same-version "bump
|
||||
# commits" per release (the phantom duplicate-bump cascade,
|
||||
# misdiagnosed as queue drain since 0.66.2; root-caused T15 Part F
|
||||
# 2026-09-11). Git-data blob/tree creation is 404 on this Gitea
|
||||
# build; ChangeFiles is the supported single-commit primitive.
|
||||
msg = f"chore(release): auto-bump version to {NEW} — earned by #{PR_NUMBER} ({PR_TITLE[:80]})\n\nPromotion record: {promoting_url}"
|
||||
ops = [{
|
||||
"operation": "update",
|
||||
"path": path,
|
||||
"content": base64.b64encode(content.encode()).decode(), # ChangeFileOperation.content is ContentBase64
|
||||
} for path, (content, _old_sha) in edited.items()]
|
||||
status, r = api("/contents", "POST", {
|
||||
"branch": "master",
|
||||
"message": msg,
|
||||
"files": ops,
|
||||
})
|
||||
if status not in (200, 201):
|
||||
print(f"change-files failed ({status}): {str(r)[:300]}"); sys.exit(1)
|
||||
commit_sha = (r.get("commit") or {}).get("sha", "?") if isinstance(r, dict) else "?"
|
||||
print(f" committed {len(ops)} surfaces as ONE commit {str(commit_sha)[:7]}")
|
||||
|
||||
print(f"AUTO_BUMPED=true — version {NEW} live on master; TUI footer will render v{NEW}")
|
||||
with open(os.environ["GITHUB_ENV"], "a") as env:
|
||||
env.write(f"RELEASE_VERSION={NEW}\n")
|
||||
env.write("AUTO_BUMPED=true\n")
|
||||
PYBUMP
|
||||
- name: Create evidence-derived release (SCAFFOLD-TRANCHE-009B)
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
RELEASE_SERVER_URL: ${{ gitea.server_url }}
|
||||
RELEASE_REPO: ${{ gitea.repository }}
|
||||
run: |
|
||||
# ONE note-generation authority: the tested release_notes module.
|
||||
# The old PR-title/body paste path (which produced empty '##'
|
||||
# bodies on direct-push releases) is REMOVED — governed evidence
|
||||
# from the scaffold store is the source, not PR prose.
|
||||
python3 scripts/release_history_cli.py init \
|
||||
--version "$RELEASE_VERSION" \
|
||||
--server "$RELEASE_SERVER_URL" --repo "$RELEASE_REPO" \
|
||||
--store store/scaffold/current.json
|
||||
+5
-288
@@ -6,13 +6,6 @@ on:
|
||||
branches: [master]
|
||||
workflow_dispatch: # benchmark: run representative CI without manufacturing commits
|
||||
|
||||
# SRE fix (2026-10-10): cancel superseded runs — the pipeline was draining
|
||||
# 62k queued tasks on STALE SHAs while newest pushes waited. This makes the
|
||||
# queue test HEAD, not history.
|
||||
concurrency:
|
||||
group: rune-ci-master
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: rune-ci-desktop
|
||||
@@ -70,13 +63,6 @@ jobs:
|
||||
- name: Structural contract (henxels)
|
||||
run: |
|
||||
.ci-venv/bin/henxels check --all --plain
|
||||
# ABSOLUTE SCAFFOLDING LAW (2026-10-07): every Go/Rust implementation
|
||||
# unit must map to a construction contract in store/scaffold/. New
|
||||
# units without a contract fail the build — open the contract BEFORE
|
||||
# the commit lands, never after.
|
||||
- name: Scaffolding coverage (absolute law)
|
||||
run: |
|
||||
python3 scripts/scaffolding_coverage.py
|
||||
|
||||
unit-tests:
|
||||
runs-on: rune-ci-desktop
|
||||
@@ -95,7 +81,6 @@ jobs:
|
||||
SC_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libscaffold_core.so
|
||||
MEMS_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libmemory_storage.so
|
||||
MR_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libmemory_retrieval.so
|
||||
CC_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libcognition_core.so
|
||||
steps:
|
||||
# actions/checkout v4.2.2, pinned to the audited upstream tag commit.
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
@@ -150,8 +135,6 @@ jobs:
|
||||
cargo build --release --manifest-path src/rust/scaffold_core/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/memory_storage/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/memory_retrieval/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/cognition_core/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/query_memory/Cargo.toml
|
||||
- name: Test with coverage (global floor + changed-lines ratchet)
|
||||
run: |
|
||||
# #149 coverage ratchet — both floors live in .coveragerc; raise,
|
||||
@@ -178,262 +161,12 @@ jobs:
|
||||
GOT=$(go version | awk '{print $3}' | sed 's/^go//' | cut -d- -f1)
|
||||
echo "pinned: $WANT | toolchain: $GOT"
|
||||
[ "$GOT" = "$WANT" ] || { echo "::error::Go toolchain drift: want $WANT, got $GOT (update go-version.txt with the rollout)"; exit 1; }
|
||||
- name: build Survivor staticlibs in-tree (for cgo main packages)
|
||||
run: |
|
||||
# Survivor main packages link Rust staticlibs via ${SRCDIR} paths
|
||||
# (adaptive-router → libroute_risk_flags.a). Those paths resolve
|
||||
# only when the crate target dir is IN-TREE, so this build must
|
||||
# NOT set CARGO_TARGET_DIR (the redirected builds below are for
|
||||
# the FFI-loader canaries and stay as they are).
|
||||
# Every Survivor-linked crate must have its .a in-tree before the
|
||||
# go loop: adaptive-router → route_risk_flags; cognition →
|
||||
# cognition_core. Add crates here as Survivor packages grow.
|
||||
cargo build --release --manifest-path src/rust/route_risk_flags/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/cognition_core/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/query_memory/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/construction_interface/Cargo.toml
|
||||
- name: prune stale /tmp cargo target dirs (tmpfs guard)
|
||||
run: |
|
||||
# /tmp is a 32G tmpfs; every CI run leaves a ~218MB
|
||||
# rune-ci-target-<run_id> dir. Without pruning, 300+ runs filled
|
||||
# the tmpfs (2026-10-07: venv creation failed disk-full across
|
||||
# every job). Keep the 3 newest; drop the rest.
|
||||
cd /tmp && ls -dt rune-ci-target-* 2>/dev/null | tail -n +4 | xargs -r rm -rf
|
||||
# deploy-test cache: rust targets accumulate ~15G (every crate's
|
||||
# release dir). The staged source survives; targets rebuild.
|
||||
find /tmp/rune-deploy-test/src/rust -maxdepth 2 -name target -type d 2>/dev/null | xargs -r rm -rf
|
||||
- name: go vet + go test + go build
|
||||
run: |
|
||||
for dir in src/go/*/; do
|
||||
if [ -f "$dir/go.mod" ] && [ -z "$(find "$dir" -maxdepth 1 -name 'bins' -type d 2>/dev/null)" ]; then
|
||||
echo "=== Building $dir ==="
|
||||
cd "$dir"
|
||||
go vet ./...
|
||||
go test ./... -v || { echo "::error::go test failed in $dir"; exit 1; }
|
||||
OUT_DIR="/tmp/go-bins-${{ gitea.run_id }}"
|
||||
mkdir -p "$OUT_DIR"
|
||||
go build -o "$OUT_DIR/go-$(basename "$dir")" .
|
||||
cd - > /dev/null
|
||||
fi
|
||||
done
|
||||
- name: golangci-lint (server-side Go analysis — catches what go vet misses)
|
||||
run: |
|
||||
which golangci-lint 2>/dev/null || echo '::warning::golangci-lint not installed — skipping'
|
||||
golangci-lint --version 2>/dev/null || true
|
||||
|
||||
- name: adaptive-router parity gate (HARD — oracle replay, not swallowable)
|
||||
run: |
|
||||
cd src/go/adaptive-router
|
||||
go test ./... -run TestParityAgainstPythonOracle -v
|
||||
- name: operator-deep evidence-kernel parity gate (HARD — #2479 batch: #30 kernels)
|
||||
run: |
|
||||
cd src/go/operator-deep && go build -o /tmp/operator-deep-${{ gitea.run_id }} . && go test -run "TestOperator30Parity|TestVerificationAndOutcomeContract|TestTaskIdentityParity|TestWindowParity" -v
|
||||
- name: curator-core candidate-decay parity gate (HARD — #2479 batch: ledger decay + journal render + cosine)
|
||||
run: |
|
||||
cd src/go/curator-core && go build -o /tmp/curator-core-${{ gitea.run_id }} . && /tmp/curator-core-${{ gitea.run_id }} replay truth_candidate_decay.json && go test -run TestCandidateDecayParity -v
|
||||
- name: cron-engine parity gate (HARD — #2479 batches 1+126: parser + lifecycle)
|
||||
run: |
|
||||
cd src/go/cron-engine && go build -o /tmp/cron-engine-${{ gitea.run_id }} . && /tmp/cron-engine-${{ gitea.run_id }} replay truth.json && go test -run TestLifecycleParity -v
|
||||
- name: goal-engine parity gate (HARD — #2479 batches 2+129: verifier + lifecycle)
|
||||
run: |
|
||||
cd src/go/goal-engine && go build -o /tmp/goal-engine-${{ gitea.run_id }} . && /tmp/goal-engine-${{ gitea.run_id }} replay truth.json && go test -run TestLifecycleParity -v
|
||||
- name: provider-budget parity gate (HARD — #2479 batches 3+146: budget + ties/headers/rpm)
|
||||
run: |
|
||||
cd src/go/provider-budget && go build -o /tmp/provider-budget-${{ gitea.run_id }} .
|
||||
/tmp/provider-budget-${{ gitea.run_id }} replay truth.json
|
||||
- name: event-wait parity gate (HARD — #2479 batch 4, oracle replay)
|
||||
run: |
|
||||
cd src/go/event-wait && go build -o /tmp/event-wait-${{ gitea.run_id }} .
|
||||
/tmp/event-wait-${{ gitea.run_id }} replay truth.json
|
||||
- name: memory-consolidation parity gate (HARD — #2479 batches 5+131: scoring + constructors)
|
||||
run: |
|
||||
cd src/go/memory-consolidation && go build -o /tmp/memory-consolidation-${{ gitea.run_id }} . && /tmp/memory-consolidation-${{ gitea.run_id }} replay truth.json && go test -run TestConstructorParity -v
|
||||
- name: release-notes parity gate (HARD — #2479 batches 6+135: render + parser edges)
|
||||
run: |
|
||||
cd src/go/release-notes && go build -o /tmp/release-notes-${{ gitea.run_id }} .
|
||||
/tmp/release-notes-${{ gitea.run_id }} replay truth.json
|
||||
- name: model-profiles parity gate (HARD — #2479 batches 7+145: detection + edge pins)
|
||||
run: |
|
||||
cd src/go/model-profiles && go build -o /tmp/model-profiles-${{ gitea.run_id }} .
|
||||
/tmp/model-profiles-${{ gitea.run_id }} replay truth.json
|
||||
- name: model-routing parity gate (HARD — #2479 batches 8+136: rank + cost-override)
|
||||
run: |
|
||||
cd src/go/model-routing && go build -o /tmp/model-routing-${{ gitea.run_id }} .
|
||||
/tmp/model-routing-${{ gitea.run_id }} replay truth.json
|
||||
- name: work-manager parity gate (HARD — #2479 batches 9+137+156: batching + lifecycle)
|
||||
run: |
|
||||
cd src/go/work-manager && go build -o /tmp/work-manager-${{ gitea.run_id }} . && /tmp/work-manager-${{ gitea.run_id }} replay truth.json && go test -run TestLifecycleParity -v
|
||||
- name: core-server parity gate (HARD — #2479 batches 10+138: envelopes + extraction/identity)
|
||||
run: |
|
||||
cd src/go/core-server && go build -o /tmp/core-server-${{ gitea.run_id }} .
|
||||
/tmp/core-server-${{ gitea.run_id }} replay truth.json
|
||||
- name: builder-bridge parity + improvement gate (HARD — #2479 batches 11+139: render/LRU + TTL/refresh/key)
|
||||
run: |
|
||||
cd src/go/builder-bridge && go build -o /tmp/builder-bridge-${{ gitea.run_id }} .
|
||||
/tmp/builder-bridge-${{ gitea.run_id }} replay truth.json
|
||||
- name: voicebox parity + improvement gate (HARD — #2479 batches 12+140: hook + full manifest)
|
||||
run: |
|
||||
cd src/go/voicebox && go build -o /tmp/voicebox-${{ gitea.run_id }} .
|
||||
/tmp/voicebox-${{ gitea.run_id }} replay truth.json
|
||||
- name: voice-sync parity gate (HARD — #2479 batches 35+143: extract + unicode/generate)
|
||||
run: |
|
||||
cd src/go/voice-sync && go build -o /tmp/voice-sync-${{ gitea.run_id }} .
|
||||
/tmp/voice-sync-${{ gitea.run_id }} replay truth.json
|
||||
- name: progressive-escalation parity gate (HARD — #2479 batches 44+147: full truth table)
|
||||
run: |
|
||||
cd src/go/progressive-escalation && go build -o /tmp/progressive-escalation-${{ gitea.run_id }} .
|
||||
/tmp/progressive-escalation-${{ gitea.run_id }} replay truth.json
|
||||
- name: message-queue parity gate (HARD — #2479 batches 61+148: full pattern table)
|
||||
run: |
|
||||
cd src/go/message-queue && go build -o /tmp/message-queue-${{ gitea.run_id }} .
|
||||
/tmp/message-queue-${{ gitea.run_id }} replay truth.json
|
||||
- name: outcome-ledger parity gate (HARD — #2479 batches 49+151: stats + live fixture)
|
||||
run: |
|
||||
cd src/go/outcome-ledger && go build -o /tmp/outcome-ledger-${{ gitea.run_id }} .
|
||||
/tmp/outcome-ledger-${{ gitea.run_id }} replay truth.json
|
||||
- name: auto-context parity gate (HARD — #2479 batches 50+157: oracle-exact keywords)
|
||||
run: |
|
||||
cd src/go/auto-context && go build -o /tmp/auto-context-${{ gitea.run_id }} .
|
||||
/tmp/auto-context-${{ gitea.run_id }} replay truth.json
|
||||
- name: night-mode parity gate (HARD — #2479 batches 60+167: state-machine cores)
|
||||
run: |
|
||||
cd src/go/night-mode && go build -o /tmp/night-mode-${{ gitea.run_id }} . && go test -run TestLifecycleParity -v
|
||||
- name: sleep-time parity gate (HARD — #2479 batches 11+168: transcript kernels)
|
||||
run: |
|
||||
cd src/go/sleep-time && go build -o /tmp/sleep-time-${{ gitea.run_id }} . && go test -run TestTranscriptKernels -v
|
||||
- name: response-adapter parity gate (HARD — #2479 batches 109+170: parsers + provenance)
|
||||
run: |
|
||||
cd src/go/response-adapter && go build -o /tmp/response-adapter-${{ gitea.run_id }} .
|
||||
/tmp/response-adapter-${{ gitea.run_id }} replay truth.json
|
||||
- name: standardized-providers parity gate (HARD — #2479 batches 62+171: registry + connect gate)
|
||||
run: |
|
||||
cd src/go/standardized-providers && go build -o /tmp/standardized-providers-${{ gitea.run_id }} . && /tmp/standardized-providers-${{ gitea.run_id }} replay truth.json && go test -run TestConnectDecisionParity -v
|
||||
- name: recall-uplift parity gate (HARD — #2479 batches 78+172: full expansion table)
|
||||
run: |
|
||||
cd src/go/recall-uplift && go build -o /tmp/recall-uplift-${{ gitea.run_id }} .
|
||||
/tmp/recall-uplift-${{ gitea.run_id }} replay truth.json
|
||||
- name: forge-core parity + improvement gate (HARD — #2479 batches 13+106+141: resolvers + lattice restore)
|
||||
run: |
|
||||
cd src/go/forge-core && go build -o /tmp/forge-core-${{ gitea.run_id }} .
|
||||
/tmp/forge-core-${{ gitea.run_id }} replay truth.json
|
||||
- name: forge-client parity gate (HARD — #2479 batch 133, oracle replay)
|
||||
run: |
|
||||
cd src/go/forge-client && go build -o /tmp/forge-client-${{ gitea.run_id }} .
|
||||
/tmp/forge-client-${{ gitea.run_id }} replay truth.json
|
||||
- name: elastic-cognition parity + improvement gate (HARD — #2479 batches 14+117: +budget/parse kernels)
|
||||
run: |
|
||||
cd src/go/elastic-cognition && go build -o /tmp/elastic-cognition-${{ gitea.run_id }} .
|
||||
/tmp/elastic-cognition-${{ gitea.run_id }} replay truth.json
|
||||
/tmp/elastic-cognition-${{ gitea.run_id }} replay truth_budget_parse.json
|
||||
- name: auto-tasks parity + improvement gate (HARD — #2479 batches 15+144: adjacency + action/seq/gates)
|
||||
run: |
|
||||
cd src/go/auto-tasks && go build -o /tmp/auto-tasks-${{ gitea.run_id }} .
|
||||
/tmp/auto-tasks-${{ gitea.run_id }} replay truth.json
|
||||
- name: model-connect parity + improvement gate (HARD — #2479 batches 16+113: clean-name parser + edge top-up)
|
||||
run: |
|
||||
cd src/go/model-connect && go build -o /tmp/model-connect-${{ gitea.run_id }} .
|
||||
/tmp/model-connect-${{ gitea.run_id }} replay truth.json
|
||||
- name: yamllint (all workflow files — would have caught the parser bugs)
|
||||
run: |
|
||||
# The runner's system python3 has NO PyYAML (PEP 668 blocks the
|
||||
# pip install; || true swallowed it — this step failed on its first
|
||||
# ever execution, run 23342). Self-contained venv, same shape as
|
||||
# the lint job's environment step.
|
||||
python3 -m venv .yaml-venv
|
||||
.yaml-venv/bin/pip install --disable-pip-version-check -q pyyaml
|
||||
for f in .gitea/workflows/*.yml; do
|
||||
.yaml-venv/bin/python -c "import yaml; yaml.safe_load(open('$f'))" || { echo "YAML INVALID: $f"; exit 1; }
|
||||
done
|
||||
echo "All workflow YAML files valid"
|
||||
|
||||
- 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: memory-store-deep text-kernel parity gate (HARD — #2479 batch: fts/mapreduce/entities)
|
||||
run: |
|
||||
cd src/go/memory-store-deep && go build -o /tmp/msd-${{ gitea.run_id }} . && go test -run "TestTextKernelsParity|TestDriftRerankBlendParity" -v
|
||||
- name: scaffold builders parity gate (HARD — #2479 batch: 7 pure builders)
|
||||
run: |
|
||||
cd src/go/scaffold && go build -o /tmp/scaffold-${{ gitea.run_id }} . && go test -run TestBuildersParity -v
|
||||
- name: tool-executor prepared-path parity gate (HARD — #2479 batch)
|
||||
run: |
|
||||
cd src/go/tool-executor && go build -o /tmp/tool-exec-${{ gitea.run_id }} . && go test -run TestPreparedPathParity -v
|
||||
- name: failure-filer parity gate (HARD — #2479 batch: classify/redact/tier/marker)
|
||||
run: |
|
||||
cd src/go/failure-filer && go build -o /tmp/failfiler-${{ gitea.run_id }} . && go test -run TestFilerParity -v
|
||||
- name: tool-protocol shapes parity gate (HARD — #2479 batch: 5 record shapes)
|
||||
run: |
|
||||
cd src/go/tool-protocol && go build -o /tmp/tp-${{ gitea.run_id }} . && go test -run TestShapesFromDictParity -v
|
||||
- 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: |
|
||||
# go test -fuzz requires a SINGLE target pattern: `-fuzz .` with
|
||||
# multiple FuzzX targets exits 1 ("matches more than one fuzz test")
|
||||
# and pipefail turns that into a job failure. Enumerate targets and
|
||||
# fuzz each — and fail LOUD (no pipe-mask, exit 1 propagates).
|
||||
for dir in src/go/tool-executor src/go/curator-core src/go/memory-store-deep; do
|
||||
cd "$dir"
|
||||
for target in $(go test -list '^Fuzz' . | grep '^Fuzz'); do
|
||||
echo "fuzz: $dir/$target"
|
||||
go test -run "^${target}$" -fuzz "^${target}$" -fuzztime 15s . || exit 1
|
||||
done
|
||||
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 (lights up when the first #[test] 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
|
||||
cd src/go/rune-entry
|
||||
go vet ./...
|
||||
go test ./...
|
||||
go build -o /tmp/rune-entry-ci .
|
||||
|
||||
canary:
|
||||
runs-on: rune-ci-desktop
|
||||
@@ -491,8 +224,6 @@ jobs:
|
||||
cargo build --release --manifest-path src/rust/scaffold_core/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/memory_storage/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/memory_retrieval/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/cognition_core/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/query_memory/Cargo.toml
|
||||
- name: Run canary suite
|
||||
run: |
|
||||
FAILED=0
|
||||
@@ -531,9 +262,6 @@ jobs:
|
||||
src/rust/scaffold_core/canary_scaffold_core.py \
|
||||
src/rust/memory_storage/canary_memory_storage.py \
|
||||
src/rust/memory_retrieval/canary_memory_retrieval.py \
|
||||
src/rust/cognition_core/canary_growth_pins.py \
|
||||
src/rust/cognition_core/canary_persona.py \
|
||||
src/rust/cognition_core/canary_cognition_core.py \
|
||||
src/rune/canary_unbounded.py \
|
||||
src/rune/canary_full_system.py \
|
||||
src/rune/canary_native.py; do
|
||||
@@ -654,10 +382,7 @@ jobs:
|
||||
runs-on: rune-ci-desktop
|
||||
# #148: type-check MUST gate the protected status — a red type-check job
|
||||
# previously left the protected merge gate green (dependency-chain hole).
|
||||
# SRE fix (2026-10-10): only the 5 REAL gates gate the pipeline —
|
||||
# best-practices/documentation/gitea-offline are trivially green and
|
||||
# dilute the signal.
|
||||
needs: [lint, unit-tests, canary, type-check, go-surface, rust-surface]
|
||||
needs: [lint, unit-tests, canary, best-practices, documentation, type-check, gitea-offline]
|
||||
steps:
|
||||
- name: Checkout (bump gate reads version surfaces)
|
||||
if: ${{ startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump') }}
|
||||
@@ -725,11 +450,3 @@ jobs:
|
||||
CI_RESULT: ${{ needs.required-checks.result }}
|
||||
RUNE_EVENT_BRIDGE_URL: ${{ vars.RUNE_EVENT_BRIDGE_URL || 'http://127.0.0.1:8791' }}
|
||||
run: python3 scripts/notify_event_bridge.py
|
||||
|
||||
- name: query_memory shadow (pre-shim oracle vs Rust CLI — #2447 qualification)
|
||||
run: |
|
||||
# The shadow runs BOTH implementations on the frozen 24-command
|
||||
# sequence in isolated HOMEs; divergence is a defect. The pre-shim
|
||||
# Python oracle is recovered from git history (6f44a87~1) — the
|
||||
# authority-switched shared/query_memory.py is the Rust core now.
|
||||
python3 scripts/qm_shadow.py
|
||||
+118
-72
@@ -1,79 +1,125 @@
|
||||
name: deploy
|
||||
|
||||
on:
|
||||
push: null
|
||||
workflow_dispatch: null
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
# Deploys the EXACT pushed revision to the local Rune code deployment
|
||||
# (handoff 2026-09-10 §3/§6) — never "whatever HEAD is at deploy time".
|
||||
# Gate: the commit's required CI checks must be green before promotion.
|
||||
# Branch guard at job level: this Gitea instance did not create runs for
|
||||
# `on.push.branches`-filtered workflows (observed 2026-09-10) — the
|
||||
# unfiltered push trigger with an explicit ref guard is the proven pattern.
|
||||
runs-on: rune-ci-desktop
|
||||
if: ${{ gitea.ref == 'refs/heads/master' && !startsWith(gitea.event.pull_request.head.ref,
|
||||
'chore/auto-bump') }}
|
||||
if: ${{ gitea.ref == 'refs/heads/master' && !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump') }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: "Wait for CI qualification on this exact SHA (event-driven, T16 \xA716C)"
|
||||
env:
|
||||
GITEA_SERVER: ${{ gitea.server_url }}
|
||||
GITEA_REPO: ${{ gitea.repository }}
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
RUNE_WR_ROOT: /mnt/workdrive/wr-bridge
|
||||
RUNE_WR_CODE: /home/nick/.local/share/mimo-wait-resume
|
||||
run: "DEPLOY_SHA=$(git rev-parse HEAD)\nexport DEPLOY_SHA\necho \"Qualifying\
|
||||
\ $DEPLOY_SHA (event-driven)\"\n# READINESS BEFORE ACTION (\xA716U): fail\
|
||||
\ with a clear message if\n# the bridge rendezvous is not writable in THIS\
|
||||
\ user's context,\n# instead of a stack trace at FIFO creation time.\nif !\
|
||||
\ touch /mnt/workdrive/wr-bridge/resumes/.write-probe 2>/dev/null; then\n\
|
||||
\ echo \"::error::RUNE_WR_ROOT not writable by $(id -un) \u2014 bridge data\
|
||||
\ root misconfigured\"\n exit 1\nfi\nrm -f /mnt/workdrive/wr-bridge/resumes/.write-probe\n\
|
||||
python3 scripts/ci_event_wait.py --sha \"$DEPLOY_SHA\" --deadline 900\n"
|
||||
- name: Stage, verify, promote (monotonic)
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
GITEA_SERVER: ${{ gitea.server_url }}
|
||||
GITEA_REPO: ${{ gitea.repository }}
|
||||
run: 'python3 scripts/deploy_stage.py
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
'
|
||||
- name: Promotion truthfulness check
|
||||
id: promotion_truth
|
||||
run: "SHA=$(git rev-parse HEAD)\nCURRENT_TARGET=$(readlink /mnt/workdrive/rune-code/current\
|
||||
\ || true)\nif [ \"$CURRENT_TARGET\" = \"/mnt/workdrive/rune-code/${SHA:0:12}\"\
|
||||
\ ]; then\n echo \"PROMOTED: current == candidate ($SHA)\"\n echo \"promoted=true\"\
|
||||
\ >> \"$GITEA_OUTPUT\"\nelse\n # Not promoted. deploy_stage exit 0 + non-matching\
|
||||
\ current =\n # NOOP_ALREADY_CURRENT or STALE_SUPERSEDED \u2014 truthful\
|
||||
\ non-error\n # terminal states (a newer build already won). Do NOT claim\n\
|
||||
\ # promotion; the runtime-verification step below only runs for\n # real\
|
||||
\ promotions.\n echo \"NOT PROMOTED: current -> $CURRENT_TARGET (superseded/noop\
|
||||
\ \u2014 current is authoritative)\"\n echo \"promoted=false\" >> \"$GITEA_OUTPUT\"\
|
||||
\nfi\n"
|
||||
- name: Post-deploy runtime verification (only for real promotions)
|
||||
if: ${{ success() }}
|
||||
run: "SHA=$(git rev-parse HEAD)\nCURRENT_TARGET=$(readlink /mnt/workdrive/rune-code/current\
|
||||
\ || true)\nif [ \"$CURRENT_TARGET\" != \"/mnt/workdrive/rune-code/${SHA:0:12}\"\
|
||||
\ ]; then\n echo \"SKIP runtime verification: this job did not promote (superseded/noop)\"\
|
||||
\n exit 0\nfi\n# Exactly what the launcher execs: cd <current>/src, import\
|
||||
\ rune.\nRUNE_HOME=/mnt/workdrive/rune RUNE_MEMORY_DIR=/home/nick/.config/opencode/memory\
|
||||
\ \\\n /home/nick/.venvs/memory/bin/python3 -c \"\n import sys\n sys.path.insert(0,\
|
||||
\ '/mnt/workdrive/rune-code/current/src')\n import rune\n info = rune.build_info()\n\
|
||||
\ assert info['commit'] == '$SHA', f'runtime SHA mismatch: {info}'\n assert\
|
||||
\ rune.__version__ == info['version']\n print('RUNTIME VERIFIED:', info)\n\
|
||||
\ \"\n"
|
||||
- name: Release-history convergence fallback (SCAFFOLD-TRANCHE-0012C)
|
||||
if: ${{ success() && steps.promotion_truth.outputs.promoted == 'true' }}
|
||||
continue-on-error: true
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
RELEASE_SERVER_URL: ${{ gitea.server_url }}
|
||||
RELEASE_REPO: ${{ gitea.repository }}
|
||||
run: "VERSION=$(python3 -c \"import sys; sys.path.insert(0,'src'); import rune;\
|
||||
\ print(rune.__version__)\" 2>/dev/null || echo \"\")\nif [ -z \"$VERSION\"\
|
||||
\ ]; then\n echo \"SKIP: cannot determine version\"\n exit 0\nfi\npython3\
|
||||
\ scripts/release_history_cli.py refresh \\\n --version \"$VERSION\" \\\n\
|
||||
\ --server \"$RELEASE_SERVER_URL\" --repo \"$RELEASE_REPO\" \\\n --store\
|
||||
\ \"$GITHUB_WORKSPACE/store/scaffold/current.json\" \\\n --release-sha \"\
|
||||
$(git rev-parse HEAD)\" \\\n --deployed-sha \"$(git rev-parse HEAD)\" \\\n\
|
||||
|| echo \"::warning::release-history fallback refresh FAILED \u2014 in-lock\
|
||||
\ hook may have already converged; retry converges\"\n"
|
||||
concurrency:
|
||||
group: deploy-${ github.ref }
|
||||
cancel-in-progress: true
|
||||
- name: Wait for CI qualification on this exact SHA (event-driven, T16 §16C)
|
||||
# T16 §16C/§16D: the old sleep-30 → query → repeat loop is gone.
|
||||
# The waiter registers a correlation on the W/R event bridge and
|
||||
# yields in select() until ci.yml's notify-event-bridge job posts
|
||||
# the completion WAKE; the verdict is then re-read from canonical
|
||||
# Gitea (deploy_qualify.py). The 900s deadline is a FAILURE
|
||||
# DETECTOR (lost-event recovery), never the scheduler.
|
||||
env:
|
||||
GITEA_SERVER: ${{ gitea.server_url }}
|
||||
GITEA_REPO: ${{ gitea.repository }}
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
# Shared bridge data root: the deploy step runs as the runner
|
||||
# user while the daemon runs as nick — the rendezvous state
|
||||
# (waits/events/resumes/leases) must be shared. §16C live
|
||||
# finding: defaulting to the invoking user's home made the
|
||||
# controller unable to create its FIFO (PermissionError) and
|
||||
# the deploy failed fast+truthfully on both 0.66.63 pushes.
|
||||
RUNE_WR_ROOT: /mnt/workdrive/wr-bridge
|
||||
RUNE_WR_CODE: /home/nick/.local/share/mimo-wait-resume
|
||||
run: |
|
||||
DEPLOY_SHA=$(git rev-parse HEAD)
|
||||
export DEPLOY_SHA
|
||||
echo "Qualifying $DEPLOY_SHA (event-driven)"
|
||||
# READINESS BEFORE ACTION (§16U): fail with a clear message if
|
||||
# the bridge rendezvous is not writable in THIS user's context,
|
||||
# instead of a stack trace at FIFO creation time.
|
||||
if ! touch /mnt/workdrive/wr-bridge/resumes/.write-probe 2>/dev/null; then
|
||||
echo "::error::RUNE_WR_ROOT not writable by $(id -un) — bridge data root misconfigured"
|
||||
exit 1
|
||||
fi
|
||||
rm -f /mnt/workdrive/wr-bridge/resumes/.write-probe
|
||||
python3 scripts/ci_event_wait.py --sha "$DEPLOY_SHA" --deadline 900
|
||||
|
||||
- name: Stage, verify, promote (monotonic)
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
GITEA_SERVER: ${{ gitea.server_url }}
|
||||
GITEA_REPO: ${{ gitea.repository }}
|
||||
run: |
|
||||
python3 scripts/deploy_stage.py
|
||||
|
||||
- name: Promotion truthfulness check
|
||||
id: promotion_truth
|
||||
run: |
|
||||
SHA=$(git rev-parse HEAD)
|
||||
CURRENT_TARGET=$(readlink /mnt/workdrive/rune-code/current || true)
|
||||
if [ "$CURRENT_TARGET" = "/mnt/workdrive/rune-code/${SHA:0:12}" ]; then
|
||||
echo "PROMOTED: current == candidate ($SHA)"
|
||||
echo "promoted=true" >> "$GITEA_OUTPUT"
|
||||
else
|
||||
# Not promoted. deploy_stage exit 0 + non-matching current =
|
||||
# NOOP_ALREADY_CURRENT or STALE_SUPERSEDED — truthful non-error
|
||||
# terminal states (a newer build already won). Do NOT claim
|
||||
# promotion; the runtime-verification step below only runs for
|
||||
# real promotions.
|
||||
echo "NOT PROMOTED: current -> $CURRENT_TARGET (superseded/noop — current is authoritative)"
|
||||
echo "promoted=false" >> "$GITEA_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Post-deploy runtime verification (only for real promotions)
|
||||
if: ${{ success() }}
|
||||
run: |
|
||||
SHA=$(git rev-parse HEAD)
|
||||
CURRENT_TARGET=$(readlink /mnt/workdrive/rune-code/current || true)
|
||||
if [ "$CURRENT_TARGET" != "/mnt/workdrive/rune-code/${SHA:0:12}" ]; then
|
||||
echo "SKIP runtime verification: this job did not promote (superseded/noop)"
|
||||
exit 0
|
||||
fi
|
||||
# Exactly what the launcher execs: cd <current>/src, import rune.
|
||||
RUNE_HOME=/mnt/workdrive/rune RUNE_MEMORY_DIR=/home/nick/.config/opencode/memory \
|
||||
/home/nick/.venvs/memory/bin/python3 -c "
|
||||
import sys
|
||||
sys.path.insert(0, '/mnt/workdrive/rune-code/current/src')
|
||||
import rune
|
||||
info = rune.build_info()
|
||||
assert info['commit'] == '$SHA', f'runtime SHA mismatch: {info}'
|
||||
assert rune.__version__ == info['version']
|
||||
print('RUNTIME VERIFIED:', info)
|
||||
"
|
||||
- name: Release-history convergence fallback (SCAFFOLD-TRANCHE-0012C)
|
||||
# The PRIMARY convergence mechanism is deploy_stage.py's out-of-lock
|
||||
# publisher (publishes from CURRENT deployment authority, §14B/§14C).
|
||||
# This step is a non-blocking FALLBACK: if the primary publish failed
|
||||
# (e.g. missing Gitea config), this retries. NEVER fails the job —
|
||||
# documentation failure never outweighs deployment validity.
|
||||
if: ${{ success() && steps.promotion_truth.outputs.promoted == 'true' }}
|
||||
continue-on-error: true
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
RELEASE_SERVER_URL: ${{ gitea.server_url }}
|
||||
RELEASE_REPO: ${{ gitea.repository }}
|
||||
run: |
|
||||
VERSION=$(python3 -c "import sys; sys.path.insert(0,'src'); import rune; print(rune.__version__)" 2>/dev/null || echo "")
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "SKIP: cannot determine version"
|
||||
exit 0
|
||||
fi
|
||||
python3 scripts/release_history_cli.py refresh \
|
||||
--version "$VERSION" \
|
||||
--server "$RELEASE_SERVER_URL" --repo "$RELEASE_REPO" \
|
||||
--store "$GITHUB_WORKSPACE/store/scaffold/current.json" \
|
||||
--release-sha "$(git rev-parse HEAD)" \
|
||||
--deployed-sha "$(git rev-parse HEAD)" \
|
||||
|| echo "::warning::release-history fallback refresh FAILED — in-lock hook may have already converged; retry converges"
|
||||
@@ -1,156 +0,0 @@
|
||||
name: Fault Watch
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["CI Pipeline"]
|
||||
types: [completed]
|
||||
schedule:
|
||||
- cron: '*/15 * * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
fault-watch:
|
||||
runs-on: rune-ci-desktop
|
||||
if: ${{ !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump') }}
|
||||
steps:
|
||||
- name: Check HEAD's named gates and file/close fault issues
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
|
||||
// The ONLY gates that matter — the five real code checks.
|
||||
const REQUIRED_GATES = ['lint', 'unit-tests', 'rust-surface', 'go-surface', 'canary'];
|
||||
|
||||
// Get the HEAD commit's combined status
|
||||
let headSha;
|
||||
try {
|
||||
const branchRes = await github.rest.repos.getBranch({ owner, repo, branch: 'master' });
|
||||
headSha = branchRes.data.commit.sha;
|
||||
} catch (e) {
|
||||
core.warning(`Cannot get HEAD branch: ${e.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const statuses = [];
|
||||
try {
|
||||
const res = await github.rest.repos.listCommitStatusesForRef({
|
||||
owner, repo, ref: headSha, per_page: 100,
|
||||
});
|
||||
statuses.push(...res.data);
|
||||
} catch (e) {
|
||||
core.warning(`Cannot list statuses for ${headSha}: ${e.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Deduplicate: keep only the LATEST status per context
|
||||
const latest = new Map();
|
||||
for (const s of statuses) {
|
||||
if (!latest.has(s.context)) latest.set(s.context, s);
|
||||
}
|
||||
|
||||
// Check each required gate
|
||||
const failures = [];
|
||||
const passes = [];
|
||||
for (const gate of REQUIRED_GATES) {
|
||||
let found = false;
|
||||
for (const [context, status] of latest) {
|
||||
// Match gate name in the context string (Gitea prefixes with workflow name)
|
||||
if (context.includes(gate)) {
|
||||
found = true;
|
||||
if (status.state === 'success') {
|
||||
passes.push(gate);
|
||||
} else if (status.state === 'failure') {
|
||||
failures.push({ gate, sha: headSha.substring(0, 8), context, description: status.description || 'no description' });
|
||||
}
|
||||
// pending = still running, don't count as failure
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// Gate hasn't reported yet on this SHA — not a failure, it's pending
|
||||
core.info(`Gate ${gate}: no status reported on ${headSha.substring(0, 8)} — pending`);
|
||||
}
|
||||
}
|
||||
|
||||
core.info(`HEAD ${headSha.substring(0, 8)}: passes=${passes.join(',')} failures=${failures.length}`);
|
||||
for (const f of failures) {
|
||||
core.info(` FAIL: ${f.gate} — ${f.description}`);
|
||||
}
|
||||
|
||||
if (failures.length === 0) {
|
||||
core.info('All named gates green or pending — no faults to file.');
|
||||
// Auto-close: find open ci-fault issues whose gate is now green
|
||||
const openFaults = [];
|
||||
try {
|
||||
const issues = await github.rest.issues.listForRepo({
|
||||
owner, repo, state: 'open', labels: 'ci-fault', per_page: 50,
|
||||
});
|
||||
openFaults.push(...issues.data.filter(i => !i.pull_request));
|
||||
} catch (e) { core.warning(`Cannot list ci-fault issues: ${e.message}`); }
|
||||
for (const issue of openFaults) {
|
||||
// Check if this issue's gate is now green
|
||||
const gateName = issue.title.match(/gate (\w+)/i)?.[1] ||
|
||||
issue.body?.match(/Gate:\s*(\w+)/i)?.[1];
|
||||
if (gateName && passes.includes(gateName)) {
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: issue.number,
|
||||
body: `✅ **Gate ${gateName} is green on HEAD** (${headSha.substring(0, 8)}). Auto-closing.`,
|
||||
});
|
||||
await github.rest.issues.update({
|
||||
owner, repo, issue_number: issue.number, state: 'closed',
|
||||
});
|
||||
core.info(`Auto-closed ci-fault issue #${issue.number} (${gateName} green).`);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// File failures as issues — dedup by (gate, error-signature)
|
||||
for (const f of failures) {
|
||||
const dedupKey = `ci-fault-${f.gate}`;
|
||||
// Check for an existing open issue with this gate
|
||||
let existing = null;
|
||||
try {
|
||||
const issues = await github.rest.issues.listForRepo({
|
||||
owner, repo, state: 'open', labels: 'ci-fault', per_page: 50,
|
||||
});
|
||||
existing = issues.data.find(i =>
|
||||
!i.pull_request && i.title.toLowerCase().includes(f.gate.toLowerCase())
|
||||
);
|
||||
} catch (e) { core.warning(`Cannot check existing issues: ${e.message}`); }
|
||||
|
||||
if (existing) {
|
||||
// Update with a comment (same gate, maybe different SHA)
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: existing.number,
|
||||
body: `🔴 **Still failing on ${f.sha}** — ${f.description}\n\nCommit: ${headSha}`,
|
||||
});
|
||||
core.info(`Updated existing ci-fault issue #${existing.number} for ${f.gate}.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a new ci-fault issue
|
||||
await github.rest.issues.create({
|
||||
owner, repo,
|
||||
title: `CI FAULT: gate ${f.gate} failing on HEAD`,
|
||||
body: [
|
||||
`## CI Gate Failure`,
|
||||
``,
|
||||
`**Gate:** ${f.gate}`,
|
||||
`**SHA:** ${f.sha}`,
|
||||
`**Status:** failure`,
|
||||
`**Description:** ${f.description}`,
|
||||
`**Commit:** ${headSha}`,
|
||||
``,
|
||||
`This issue was auto-filed by the fault-watch. It auto-closes when the gate goes green on a pushed commit.`,
|
||||
``,
|
||||
`**Severity rule:** if this gate failure means ALL subsequent submissions also fail (pipeline-blocking), fix immediately. Otherwise: finish the current batch, then fix before the next submission.`,
|
||||
].join('\n'),
|
||||
labels: ['ci-fault', 'bug'],
|
||||
});
|
||||
core.info(`Filed ci-fault issue for ${f.gate} on ${f.sha}.`);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
name: Local-Model First-Pass Review (#131)
|
||||
|
||||
# Non-blocking PR review by a local model (Ollama on the 4070 Ti).
|
||||
# Advisory only — nothing gates on the local model. The two-gate reviews
|
||||
# (spec + quality) remain the enforcement path; this is a first-pass
|
||||
# filter adding redundancy against controller degradation.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
first-pass-review:
|
||||
runs-on: rune-ci-desktop
|
||||
# Advisory review needs PR context (diff base + comment target). Push
|
||||
# runs have neither — run NOTHING on push (the 20721 lesson: guarding
|
||||
# only the collect step let the post step fail the run at
|
||||
# /issues//comments). Auto-bump PRs stay excluded as before.
|
||||
if: ${{ !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump') }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Collect the PR diff
|
||||
run: |
|
||||
if [ -z "$GITEA_BASE_REF" ]; then
|
||||
echo "no PR context (push run) — advisory review not applicable"
|
||||
exit 0
|
||||
fi
|
||||
git diff "origin/${GITEA_BASE_REF}...HEAD" --stat > /tmp/pr_stat.txt
|
||||
git diff "origin/${GITEA_BASE_REF}...HEAD" > /tmp/pr_diff.txt
|
||||
wc -l /tmp/pr_diff.txt /tmp/pr_stat.txt
|
||||
env:
|
||||
GITEA_BASE_REF: ${{ gitea.event.pull_request.base.ref }}
|
||||
- name: Local-model review (Ollama — advisory, never blocking)
|
||||
env:
|
||||
OLLAMA_HOST: ${{ secrets.OLLAMA_HOST }}
|
||||
run: |
|
||||
# Fail-open: no Ollama reachable → skip with a note, never fail.
|
||||
if ! curl -sf "${OLLAMA_HOST:-http://192.168.1.50:11434}/api/tags" > /dev/null 2>&1; then
|
||||
echo "Ollama unreachable — skipping first-pass review (advisory only)"
|
||||
exit 0
|
||||
fi
|
||||
MODEL="${OLLAMA_MODEL:-qwen2.5-coder:7b}"
|
||||
python3 scripts/local_firstpass_review.py \
|
||||
--diff /tmp/pr_diff.txt --stat /tmp/pr_stat.txt \
|
||||
--model "$MODEL" --host "${OLLAMA_HOST:-http://192.168.1.50:11434}"
|
||||
- name: Post findings as PR comment
|
||||
if: ${{ gitea.event.pull_request.number != 0 }}
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
PR_NUMBER: ${{ gitea.event.pull_request.number }}
|
||||
run: |
|
||||
if [ -f /tmp/review_findings.md ]; then
|
||||
export PR_NUMBER
|
||||
python3 - <<'PYEOF'
|
||||
import json, os, urllib.request
|
||||
body = open("/tmp/review_findings.md").read()
|
||||
if not body.strip():
|
||||
print("no findings — no comment")
|
||||
exit(0)
|
||||
base = os.environ["GITEA_SERVER_URL"] + "/api/v1/repos/" + os.environ["GITEA_REPOSITORY"]
|
||||
req = urllib.request.Request(
|
||||
base + "/issues/" + os.environ["PR_NUMBER"] + "/comments",
|
||||
data=json.dumps({"body": "## First-pass review (local model, advisory)\n\n" + body}).encode(),
|
||||
headers={"Authorization": "token " + os.environ["GITEA_TOKEN"], "Content-Type": "application/json"},
|
||||
method="POST")
|
||||
with urllib.request.urlopen(req, timeout=30) as r:
|
||||
print("comment posted:", r.status)
|
||||
PYEOF
|
||||
fi
|
||||
@@ -1,38 +1,38 @@
|
||||
name: Merge robot
|
||||
|
||||
# Deterministic merge-on-green for this repo's PRs. No LLM, no polling by the
|
||||
# agent: the forge event model does the watching, this job does the one action.
|
||||
# Runs hourly + on CI completion events so green PRs merge without any agent
|
||||
# turn being spent on "check CI, merge, clean up".
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: 23 * * * *
|
||||
- cron: '23 * * * *'
|
||||
workflow_dispatch: {}
|
||||
workflow_run:
|
||||
workflows:
|
||||
- CI Pipeline
|
||||
- Auto-version and Release
|
||||
types:
|
||||
- completed
|
||||
workflows: ["CI Pipeline", "Auto-version and Release"]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
pull_requests: write
|
||||
issues: write
|
||||
contents: read
|
||||
|
||||
env:
|
||||
OWNER: conductor
|
||||
REPO: rune
|
||||
|
||||
jobs:
|
||||
merge-green:
|
||||
runs-on: rune-ci-desktop
|
||||
steps:
|
||||
- name: "Checkout repo \u2014 job never checked out, scripts/merge_robot.py missing,\
|
||||
\ exit 2 since #211"
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Merge PRs whose protected checks are green (fail-loud)
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }}
|
||||
SERVER: ${{ gitea.server_url }}
|
||||
run: 'python3 scripts/merge_robot.py "$GITEA_TOKEN" "$SERVER/api/v1/repos/conductor/rune"
|
||||
|
||||
'
|
||||
concurrency:
|
||||
group: merge-robot
|
||||
cancel-in-progress: false
|
||||
max-parallel: 1
|
||||
- name: "Checkout repo — job never checked out, scripts/merge_robot.py missing, exit 2 since #211"
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Merge PRs whose protected checks are green (fail-loud)
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.ROBOT_TOKEN }} # conductor token; GITEA_TOKEN is reserved (auto token, read-only)
|
||||
SERVER: ${{ gitea.server_url }}
|
||||
run: |
|
||||
python3 scripts/merge_robot.py "$GITEA_TOKEN" "$SERVER/api/v1/repos/conductor/rune"
|
||||
@@ -15,11 +15,3 @@ state/
|
||||
index/
|
||||
journal/
|
||||
src/rust/*/target/
|
||||
|
||||
# batch 134: Go build artifacts — binaries are CI-built per gate (go build -o /tmp/...),
|
||||
# never stored. Each module dir keeps go.mod/main.go/truth*.json + *_test.go only.
|
||||
src/go/*/[^.]*
|
||||
!src/go/*/*.go
|
||||
!src/go/*/*.json
|
||||
!src/go/*/*.mod
|
||||
!src/go/*/*.sum
|
||||
@@ -26,9 +26,6 @@ Only use `git commit --no-verify` in a genuine emergency: it bypasses the hooks
|
||||
- Every workflow is registered in the pipeline registry — new pipeline machinery ships with documentation (in ./.gitea/workflows/*.yml)
|
||||
- Every TUI surface is registered — no silent UI growth (in ./src/rune/*tui*.py)
|
||||
- New rune modules ship with tests or a canary — no ungoverned code surfaces (in ./src/rune/*.py)
|
||||
- Rust crate files stay under a line budget (in ./src/rust/*/src/*.rs)
|
||||
- Go modules stay under a line budget (in ./src/go/**/*.go)
|
||||
- No secrets in Rust or Go source files (in ./src/rust/*/src/*.rs, ./src/go/**/*.go)
|
||||
- PRDs are living documents — their generated state sections regenerate identically from governed sources
|
||||
- PRD staleness is a CI failure — docs rot is silent failure (in ./scripts/gen_prd_state.py)
|
||||
- The adversarial review procedure is binding — dispatch templates must reference it (in ./docs/adversarial-review.md)
|
||||
@@ -36,7 +33,6 @@ Only use `git commit --no-verify` in a genuine emergency: it bypasses the hooks
|
||||
- Production failure fixtures are a governed surface — the registry and its README exist (in ./tests/fixtures/production)
|
||||
- Fixture payloads and the manifest travel together — tamper-evidence needs both
|
||||
- The fixture manifest and its generated regression tests travel together
|
||||
- The dichotomy is enforced at the commit boundary — every src/rune module lands in its measured side, dead oracles and wrong-language kernels fail with the correct implementation as the instruction (in ./src/rune)
|
||||
|
||||
### Behaviours
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Rune
|
||||
|
||||
**Current release: v0.189.0**
|
||||
**Current release: v0.99.5**
|
||||
|
||||
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
|
||||
|
||||
|
||||
+203
-219
@@ -1,251 +1,207 @@
|
||||
{
|
||||
"_comment": "GENERATED by rune.spine \u2014 compatibility view for legacy umbrella consumers. DO NOT EDIT: structural truth lives in store/spine/current.json; edits here are flagged by spine drift.",
|
||||
"_generated_by_spine": true,
|
||||
"generated_at": "2026-10-10T06:45:48Z",
|
||||
"generated_at": "2026-09-16T18:23:38Z",
|
||||
"umbrellas": {
|
||||
"capability": {
|
||||
"description": "Tool selection and execution authority",
|
||||
"modules": [
|
||||
"audit_ledger",
|
||||
"builder_bridge_cli",
|
||||
"core_server",
|
||||
"cs_loader",
|
||||
"evidence_capsule",
|
||||
"forge",
|
||||
"intent_continuity",
|
||||
"message_queue",
|
||||
"native_units",
|
||||
"provider_context",
|
||||
"research_budget"
|
||||
],
|
||||
"depends_on": [
|
||||
"memory"
|
||||
],
|
||||
"mirrors": [],
|
||||
"canaries": [
|
||||
"canary_native",
|
||||
"canary_native",
|
||||
"canary_p0_05",
|
||||
"canary_p0_05",
|
||||
"canary_p1_01",
|
||||
"canary_p1_01",
|
||||
"canary_rune_entry",
|
||||
"canary_rune_serve"
|
||||
],
|
||||
"configs": [],
|
||||
"depends_on": [
|
||||
"memory"
|
||||
],
|
||||
"description": "Tool selection and execution authority",
|
||||
"go_surfaces": [
|
||||
"rune-entry"
|
||||
],
|
||||
"mirrors": [],
|
||||
"modules": [
|
||||
"adaptive_router",
|
||||
"builder_bridge",
|
||||
"builder_bridge_cli",
|
||||
"capability_broker",
|
||||
"connection_pool",
|
||||
"core_server",
|
||||
"cs_loader",
|
||||
"evidence_probe",
|
||||
"forge",
|
||||
"forge_client",
|
||||
"intent_continuity",
|
||||
"local_tool_runtime",
|
||||
"message_queue",
|
||||
"native_units",
|
||||
"openai_compat_transport",
|
||||
"provider_context",
|
||||
"recall_uplift",
|
||||
"route_risk_flags",
|
||||
"tool_executor",
|
||||
"tool_protocol"
|
||||
],
|
||||
"rust_crates": [
|
||||
"capability_scoring"
|
||||
]
|
||||
},
|
||||
"governance": {
|
||||
"description": "Quality control, drift detection, promotion, audit",
|
||||
"modules": [
|
||||
"build_pipeline_policy",
|
||||
"cc_loader",
|
||||
"contracts",
|
||||
"failure_auto_filer",
|
||||
"forge_client",
|
||||
"grading",
|
||||
"mutation_guards",
|
||||
"paths",
|
||||
"programme_gates",
|
||||
"sc_loader",
|
||||
"worthiness"
|
||||
"canaries": [
|
||||
"canary_full_system",
|
||||
"canary_schema_migration",
|
||||
"canary_audit_ledger",
|
||||
"canary_spine_meta"
|
||||
],
|
||||
"configs": [
|
||||
".coveragerc",
|
||||
"go-version.txt",
|
||||
"lint-baseline.json",
|
||||
"pyright-baseline.json"
|
||||
],
|
||||
"depends_on": [],
|
||||
"description": "Quality control, drift detection, promotion, audit",
|
||||
"mirrors": [],
|
||||
"canaries": [
|
||||
"canary_audit_ledger",
|
||||
"canary_full_system",
|
||||
"canary_full_system",
|
||||
"canary_schema_migration",
|
||||
"canary_schema_migration",
|
||||
"canary_spine_meta"
|
||||
]
|
||||
},
|
||||
"growth": {
|
||||
"description": "Learning and improvement",
|
||||
"modules": [
|
||||
"autonomy_loop",
|
||||
"behavior",
|
||||
"audit_ledger",
|
||||
"build_pipeline_policy",
|
||||
"cc_loader",
|
||||
"claim_audit",
|
||||
"cognitive_loop",
|
||||
"dream_cycle",
|
||||
"drift_cache",
|
||||
"drift_compression",
|
||||
"contracts",
|
||||
"curator",
|
||||
"drift_core",
|
||||
"drift_ledger",
|
||||
"drift_observability",
|
||||
"growth_delta",
|
||||
"growth_pipeline",
|
||||
"growth_simulator",
|
||||
"meaningful_events",
|
||||
"night_mode",
|
||||
"outcome_ledger",
|
||||
"outcome_utility",
|
||||
"self_improve",
|
||||
"self_modify",
|
||||
"skill_compiler"
|
||||
"failure_auto_filer",
|
||||
"programme_gates",
|
||||
"sc_loader"
|
||||
],
|
||||
"rust_crates": [
|
||||
"evidence_provenance",
|
||||
"scaffold_core"
|
||||
]
|
||||
},
|
||||
"growth": {
|
||||
"canaries": [
|
||||
"canary_full_system"
|
||||
],
|
||||
"depends_on": [
|
||||
"governance",
|
||||
"memory"
|
||||
],
|
||||
"description": "Learning and improvement",
|
||||
"mirrors": [],
|
||||
"canaries": [
|
||||
"canary_full_system",
|
||||
"canary_full_system"
|
||||
"modules": [
|
||||
"autonomy_loop",
|
||||
"cognitive_loop",
|
||||
"dream_cycle",
|
||||
"elastic_cognition",
|
||||
"goal",
|
||||
"growth_delta",
|
||||
"growth_simulator",
|
||||
"self_improve",
|
||||
"subconscious_pass"
|
||||
]
|
||||
},
|
||||
"identity": {
|
||||
"canaries": [
|
||||
"canary_full_system"
|
||||
],
|
||||
"depends_on": [
|
||||
"governance"
|
||||
],
|
||||
"description": "Who the agent is \u2014 persona, voice, anchors",
|
||||
"mirrors": [],
|
||||
"modules": [
|
||||
"behavior",
|
||||
"identity_anchors",
|
||||
"persona_definition",
|
||||
"persona_gate",
|
||||
"prompt_sync",
|
||||
"safety_override",
|
||||
"self_model",
|
||||
"voice_hybrid",
|
||||
"voice_injector",
|
||||
"voice_sync"
|
||||
],
|
||||
"depends_on": [
|
||||
"governance"
|
||||
],
|
||||
"mirrors": [],
|
||||
"canaries": [
|
||||
"canary_full_system",
|
||||
"canary_full_system"
|
||||
"voice_sync",
|
||||
"voicebox"
|
||||
]
|
||||
},
|
||||
"inference": {
|
||||
"description": "Model routing and outbound requests",
|
||||
"modules": [
|
||||
"adaptive_router",
|
||||
"evidence_probe",
|
||||
"inference_paths",
|
||||
"inference_trace",
|
||||
"local_tool_runtime",
|
||||
"model_connect",
|
||||
"model_profiles",
|
||||
"model_registry",
|
||||
"model_routing",
|
||||
"openai_compat_transport",
|
||||
"provider_budget",
|
||||
"provider_registry",
|
||||
"recall_router",
|
||||
"recall_uplift",
|
||||
"response_adapter",
|
||||
"route_risk_flags",
|
||||
"standardized_providers",
|
||||
"tc_loader",
|
||||
"token_optimizer"
|
||||
"canaries": [
|
||||
"canary_p1_02",
|
||||
"canary_p1_06",
|
||||
"canary_resource_authority"
|
||||
],
|
||||
"depends_on": [
|
||||
"capability"
|
||||
],
|
||||
"description": "Model routing and outbound requests",
|
||||
"mirrors": [],
|
||||
"canaries": [
|
||||
"canary_p1_02",
|
||||
"canary_p1_02",
|
||||
"canary_p1_06",
|
||||
"canary_p1_06",
|
||||
"canary_resource_authority",
|
||||
"canary_resource_authority"
|
||||
"modules": [
|
||||
"inference_trace",
|
||||
"model_connect",
|
||||
"model_profiles",
|
||||
"model_registry",
|
||||
"model_routing",
|
||||
"provider_budget",
|
||||
"provider_registry",
|
||||
"response_adapter",
|
||||
"standardized_providers",
|
||||
"tc_loader",
|
||||
"token_optimizer"
|
||||
],
|
||||
"rust_crates": [
|
||||
"token_counting"
|
||||
]
|
||||
},
|
||||
"memory": {
|
||||
"description": "Storing, retrieving, and managing knowledge",
|
||||
"modules": [
|
||||
"abstraction",
|
||||
"abstraction_ladder",
|
||||
"auto_context",
|
||||
"cache",
|
||||
"concept_topology",
|
||||
"connection_pool",
|
||||
"curator",
|
||||
"drift-ledger",
|
||||
"experience_encoding",
|
||||
"ffi_query_memory_smoke",
|
||||
"graph_memory",
|
||||
"graph_shard_bridge",
|
||||
"lexicon_evolution",
|
||||
"memory_consolidation",
|
||||
"memory_env",
|
||||
"memory_selector",
|
||||
"memory_store",
|
||||
"memory_types",
|
||||
"mems_loader",
|
||||
"message_graph",
|
||||
"mr_loader",
|
||||
"ms_loader",
|
||||
"query_memory",
|
||||
"retrieval_benchmark",
|
||||
"shard_manager",
|
||||
"sleep_time",
|
||||
"state_checkpoint",
|
||||
"subconscious_pass",
|
||||
"tier_manager",
|
||||
"warm_neuron_store",
|
||||
"warm_router"
|
||||
"canaries": [
|
||||
"canary_full_system",
|
||||
"canary_memory_synthesis",
|
||||
"canary_query_memory"
|
||||
],
|
||||
"depends_on": [
|
||||
"governance"
|
||||
],
|
||||
"description": "Storing, retrieving, and managing knowledge",
|
||||
"mirrors": [],
|
||||
"canaries": [
|
||||
"canary_full_system",
|
||||
"canary_full_system",
|
||||
"canary_memory_synthesis",
|
||||
"canary_memory_synthesis",
|
||||
"canary_query_memory",
|
||||
"canary_query_memory"
|
||||
"modules": [
|
||||
"abstraction",
|
||||
"cache",
|
||||
"drift_cache",
|
||||
"drift_compression",
|
||||
"ffi_query_memory_smoke",
|
||||
"graph_memory",
|
||||
"graph_shard_bridge",
|
||||
"memory_consolidation",
|
||||
"memory_env",
|
||||
"memory_selector",
|
||||
"memory_store",
|
||||
"mems_loader",
|
||||
"mr_loader",
|
||||
"ms_loader",
|
||||
"query_memory",
|
||||
"recall_router",
|
||||
"retrieval_benchmark",
|
||||
"shard_manager",
|
||||
"tier_manager",
|
||||
"warm_neuron_store"
|
||||
],
|
||||
"rust_crates": [
|
||||
"memory_retrieval",
|
||||
"memory_scoring",
|
||||
"memory_storage",
|
||||
"query_memory"
|
||||
]
|
||||
},
|
||||
"orchestration": {
|
||||
"description": "Task lifecycle, operator, TUI presentation",
|
||||
"modules": [
|
||||
"attention_capsule",
|
||||
"auto_detect",
|
||||
"build_mode",
|
||||
"build_orchestrator",
|
||||
"builder_bridge",
|
||||
"capability_broker",
|
||||
"chat_bubble",
|
||||
"context_broker",
|
||||
"cron_engine",
|
||||
"custodian",
|
||||
"dependency_tracker",
|
||||
"elastic_cognition",
|
||||
"event_bus",
|
||||
"event_envelope",
|
||||
"execution_trace",
|
||||
"gitea_auth",
|
||||
"gitea_pipeline",
|
||||
"gitea_provision",
|
||||
"goal",
|
||||
"hook_engine",
|
||||
"message_widgets",
|
||||
"microkernel",
|
||||
"pane_authority",
|
||||
"parallel_processor",
|
||||
"pins",
|
||||
"progressive_escalation",
|
||||
"rune_graphic",
|
||||
"rune_operator",
|
||||
"rune_profiler",
|
||||
"rune_spinner",
|
||||
"subsystem_health",
|
||||
"system_registry",
|
||||
"task_gate",
|
||||
"task_persist",
|
||||
"tiered_executor",
|
||||
"time_awareness",
|
||||
"tool_executor",
|
||||
"tool_protocol",
|
||||
"tui_transport",
|
||||
"tui_validator",
|
||||
"umbrella_update",
|
||||
"verification_layer",
|
||||
"witness",
|
||||
"work_manager"
|
||||
"canaries": [
|
||||
"canary_cognitive_strata",
|
||||
"canary_conversation_state",
|
||||
"canary_gitea_pipeline",
|
||||
"canary_orchestration_foundation",
|
||||
"canary_p1_07",
|
||||
"canary_surface_parity",
|
||||
"canary_tui_drift",
|
||||
"canary_tui_transport"
|
||||
],
|
||||
"depends_on": [
|
||||
"capability",
|
||||
@@ -254,28 +210,63 @@
|
||||
"inference",
|
||||
"perception"
|
||||
],
|
||||
"description": "Task lifecycle, operator, TUI presentation",
|
||||
"mirrors": [],
|
||||
"canaries": [
|
||||
"canary_cognitive_strata",
|
||||
"canary_cognitive_strata",
|
||||
"canary_conversation_state",
|
||||
"canary_conversation_state",
|
||||
"canary_gitea_pipeline",
|
||||
"canary_gitea_pipeline",
|
||||
"canary_orchestration_foundation",
|
||||
"canary_orchestration_foundation",
|
||||
"canary_p1_07",
|
||||
"canary_p1_07",
|
||||
"canary_surface_parity",
|
||||
"canary_surface_parity",
|
||||
"canary_tui_drift",
|
||||
"canary_tui_drift",
|
||||
"canary_tui_transport"
|
||||
"modules": [
|
||||
"auto_detect",
|
||||
"build_mode",
|
||||
"build_orchestrator",
|
||||
"chat_bubble",
|
||||
"cron_engine",
|
||||
"custodian",
|
||||
"dependency_tracker",
|
||||
"event_bus",
|
||||
"event_envelope",
|
||||
"gitea_auth",
|
||||
"gitea_pipeline",
|
||||
"gitea_provision",
|
||||
"hook_engine",
|
||||
"message_widgets",
|
||||
"microkernel",
|
||||
"night_mode",
|
||||
"outcome_ledger",
|
||||
"parallel_processor",
|
||||
"pins",
|
||||
"progressive_escalation",
|
||||
"rune_graphic",
|
||||
"rune_operator",
|
||||
"rune_profiler",
|
||||
"rune_spinner",
|
||||
"rune_tui",
|
||||
"safety_override",
|
||||
"sleep_time",
|
||||
"subsystem_health",
|
||||
"system_registry",
|
||||
"task_gate",
|
||||
"task_persist",
|
||||
"tiered_executor",
|
||||
"time_awareness",
|
||||
"tui_transport",
|
||||
"tui_validator",
|
||||
"umbrella_update",
|
||||
"verification_layer",
|
||||
"warm_router",
|
||||
"work_manager"
|
||||
]
|
||||
},
|
||||
"perception": {
|
||||
"canaries": [
|
||||
"canary_context_broker",
|
||||
"canary_full_system"
|
||||
],
|
||||
"depends_on": [
|
||||
"memory"
|
||||
],
|
||||
"description": "Input processing and context assembly",
|
||||
"mirrors": [],
|
||||
"modules": [
|
||||
"attention_capsule",
|
||||
"auto_context",
|
||||
"auto_tasks",
|
||||
"behaviour_ledger",
|
||||
"build_basis",
|
||||
@@ -292,6 +283,7 @@
|
||||
"construction_pattern",
|
||||
"construction_patterns_builtin",
|
||||
"construction_projection",
|
||||
"context_broker",
|
||||
"context_pressure",
|
||||
"drift_resume",
|
||||
"event_wait",
|
||||
@@ -303,7 +295,6 @@
|
||||
"programme_continuation",
|
||||
"project_registry",
|
||||
"release_notes",
|
||||
"rune_tui",
|
||||
"salience_gate",
|
||||
"scaffold",
|
||||
"spine",
|
||||
@@ -316,20 +307,13 @@
|
||||
"testing_mode",
|
||||
"toolchain",
|
||||
"tui_backlog",
|
||||
"voicebox",
|
||||
"wait_guard",
|
||||
"wait_guard_corpus"
|
||||
"wait_guard_corpus",
|
||||
"witness"
|
||||
],
|
||||
"depends_on": [
|
||||
"memory"
|
||||
],
|
||||
"mirrors": [],
|
||||
"canaries": [
|
||||
"canary_context_broker",
|
||||
"canary_context_broker",
|
||||
"canary_full_system",
|
||||
"canary_full_system"
|
||||
"rust_crates": [
|
||||
"rune_spine"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
# DICHOTOMY REBASE — HONEST AUDIT (function-level)
|
||||
|
||||
_Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL only when 80%+ of its Python functions have name-preserving counterparts in the Go/Rust implementation — directories without the functions are facades and count as NOT TOUCHED._
|
||||
|
||||
**Function-level completion: 23%** (535/2357 runtime functions matched)
|
||||
|
||||
| Status | Modules | Lines | Meaning |
|
||||
|---|---|---|---|
|
||||
| FULL | 8 | 734 | 80%+ of functions ported |
|
||||
| PARTIAL | 79 | 39290 | 20–80% — real logic exists, gaps named below |
|
||||
| NOT TOUCHED | 114 | 31504 | no name-preserving implementation |
|
||||
| Total runtime | 201 | 71528 | |
|
||||
|
||||
## NOT TOUCHED — the port queue, in priority order (largest first)
|
||||
|
||||
| Module | Lines | Fns | Side |
|
||||
|---|---|---|---|
|
||||
| rune_tui | 4170 | 159 | TUI-LAST |
|
||||
| curator | 1838 | 43 | GO |
|
||||
| spine | 1204 | 31 | RUST |
|
||||
| abstraction | 656 | 17 | GO |
|
||||
| contracts | 629 | 7 | RUST |
|
||||
| construction_intent | 555 | 16 | RUST |
|
||||
| canary_audit_ledger | 541 | 2 | TEST-INFRA |
|
||||
| event_wait | 518 | 14 | GO |
|
||||
| tui_validator | 514 | 13 | TUI-LAST |
|
||||
| memory_selector | 511 | 13 | RUST |
|
||||
| system_registry | 504 | 14 | RUST |
|
||||
| construction_pattern | 496 | 12 | RUST |
|
||||
| auto_tasks | 460 | 14 | GO |
|
||||
| drift_ledger | 456 | 16 | RUST |
|
||||
| goal | 453 | 20 | GO |
|
||||
| release_notes | 446 | 16 | GO |
|
||||
| model_routing | 432 | 13 | GO |
|
||||
| worthiness | 411 | 13 | unclassified |
|
||||
| token_optimizer | 410 | 22 | RUST |
|
||||
| behavior | 408 | 9 | RUST |
|
||||
| capability_ledger | 405 | 18 | RUST |
|
||||
| chat_bubble | 401 | 12 | TUI-LAST |
|
||||
| prompt_sync | 379 | 14 | RUST |
|
||||
| drift-ledger | 355 | 14 | unclassified |
|
||||
| programme_continuation | 349 | 11 | RUST |
|
||||
| canary_rune_serve | 329 | 13 | TEST-INFRA |
|
||||
| canary_p1_07 | 324 | 10 | TEST-INFRA |
|
||||
| layout_contract | 316 | 6 | RUST |
|
||||
| message_queue | 316 | 13 | GO |
|
||||
| drift_observability | 315 | 8 | RUST |
|
||||
| build_basis | 314 | 12 | RUST |
|
||||
| canary_p0_07 | 310 | 10 | TEST-INFRA |
|
||||
| attention_capsule | 296 | 7 | RUST |
|
||||
| canary_p1_01 | 294 | 12 | TEST-INFRA |
|
||||
| drift_cache | 292 | 15 | RUST |
|
||||
| outcome_ledger | 286 | 7 | RUST |
|
||||
| time_awareness | 286 | 14 | RUST |
|
||||
| canary_p1_06 | 280 | 7 | TEST-INFRA |
|
||||
| auto_context | 273 | 8 | GO |
|
||||
| canary_p1_03 | 271 | 9 | TEST-INFRA |
|
||||
| canary_gitea_automation | 263 | 3 | TEST-INFRA |
|
||||
| canary_p1_02 | 253 | 10 | TEST-INFRA |
|
||||
| construction_patterns_builtin | 249 | 1 | RUST |
|
||||
| canary_full_system | 248 | 2 | TEST-INFRA |
|
||||
| toolchain | 236 | 5 | RUST |
|
||||
| task_gate | 235 | 8 | RUST |
|
||||
| canary_native | 231 | 3 | TEST-INFRA |
|
||||
| lexicon_evolution | 229 | 7 | unclassified |
|
||||
| openai_compat_transport | 227 | 9 | GO |
|
||||
| shard_manager | 223 | 9 | RUST |
|
||||
| spine_language | 218 | 5 | RUST |
|
||||
| evidence_probe | 213 | 9 | GO |
|
||||
| canary_p0_04 | 207 | 8 | TEST-INFRA |
|
||||
| forge_client | 203 | 18 | GO |
|
||||
| canary_context_broker | 199 | 10 | TEST-INFRA |
|
||||
| canary_p0_05 | 199 | 13 | TEST-INFRA |
|
||||
| testing_mode | 196 | 12 | RUST |
|
||||
| cc_loader | 195 | 26 | RUST |
|
||||
| grading | 193 | 3 | unclassified |
|
||||
| canary_spine_meta | 192 | 7 | TEST-INFRA |
|
||||
| verification_layer | 190 | 12 | RUST |
|
||||
| message_graph | 187 | 12 | unclassified |
|
||||
| ffi_query_memory_smoke | 183 | 5 | RUST |
|
||||
| behaviour_ledger | 174 | 12 | RUST |
|
||||
| canary_tui_transport | 174 | 7 | TEST-INFRA |
|
||||
| canary_tui_drift | 170 | 2 | TEST-INFRA |
|
||||
| inference_trace | 164 | 6 | RUST |
|
||||
| ms_loader | 163 | 16 | RUST |
|
||||
| canary_gitea_pipeline | 159 | 2 | TEST-INFRA |
|
||||
| forge | 146 | 11 | GO |
|
||||
| rune_graphic | 145 | 5 | TUI-LAST |
|
||||
| project_registry | 139 | 11 | RUST |
|
||||
| canary_rune_entry | 137 | 3 | TEST-INFRA |
|
||||
| tui_backlog | 125 | 5 | TUI-LAST |
|
||||
| state_checkpoint | 123 | 8 | unclassified |
|
||||
| drift_resume | 118 | 3 | RUST |
|
||||
| canary_conversation_state | 115 | 2 | TEST-INFRA |
|
||||
| canary_query_memory | 111 | 2 | TEST-INFRA |
|
||||
| tui_transport | 108 | 10 | TUI-LAST |
|
||||
| canary_unbounded | 105 | 2 | TEST-INFRA |
|
||||
| spine_loader | 105 | 7 | RUST |
|
||||
| message_widgets | 104 | 6 | TUI-LAST |
|
||||
| self_modify | 102 | 7 | unclassified |
|
||||
| sc_loader | 96 | 6 | RUST |
|
||||
| inference_paths | 95 | 2 | unclassified |
|
||||
| mutation_guards | 94 | 2 | unclassified |
|
||||
| concept_topology | 90 | 7 | unclassified |
|
||||
| cs_loader | 90 | 5 | RUST |
|
||||
| tc_loader | 88 | 5 | RUST |
|
||||
| canary_schema_migration | 86 | 1 | TEST-INFRA |
|
||||
| mems_loader | 83 | 5 | RUST |
|
||||
| execution_trace | 71 | 4 | unclassified |
|
||||
| experience_encoding | 70 | 1 | unclassified |
|
||||
| abstraction_ladder | 68 | 3 | unclassified |
|
||||
| pane_authority | 67 | 2 | unclassified |
|
||||
| skill_compiler | 64 | 4 | unclassified |
|
||||
| meaningful_events | 61 | 3 | unclassified |
|
||||
| outcome_utility | 59 | 4 | unclassified |
|
||||
| memory_types | 54 | 2 | unclassified |
|
||||
| growth_pipeline | 53 | 2 | unclassified |
|
||||
| paths | 53 | 6 | unclassified |
|
||||
| wait_guard_corpus | 46 | 0 | RUST |
|
||||
| canary_cognitive_strata | 44 | 1 | TEST-INFRA |
|
||||
| research_budget | 44 | 3 | unclassified |
|
||||
| self_model | 44 | 3 | unclassified |
|
||||
| evidence_capsule | 43 | 3 | unclassified |
|
||||
| builder_bridge_cli | 42 | 1 | GO |
|
||||
| __init__ | 40 | 1 | RUST |
|
||||
| mr_loader | 38 | 13 | RUST |
|
||||
| canary_memory_synthesis | 33 | 1 | TEST-INFRA |
|
||||
| canary_resource_authority | 33 | 1 | TEST-INFRA |
|
||||
| canary_surface_parity | 33 | 1 | TEST-INFRA |
|
||||
| canary_orchestration_foundation | 32 | 1 | TEST-INFRA |
|
||||
| canary_gitea_delegation | 31 | 1 | TEST-INFRA |
|
||||
|
||||
## PARTIAL — gaps to close (matched/total fns; first missing named)
|
||||
|
||||
| Module | Lines | Coverage | Missing (first named) |
|
||||
|---|---|---|---|
|
||||
| rune_operator | 2746 | 15/68 | _build_model_router, _bounded, _probe_failure_classes, _sorted_tool_names, _memory_query_from_trace, _observation_from_compaction |
|
||||
| memory_store | 2586 | 29/78 | _ctx_budget, now_iso, ensure_memory_type_column, _embed, _temp_json, _entities_to_json |
|
||||
| context_broker | 870 | 6/28 | _py_default_estimator, _cc_core, _py_default_budget, _py_default_memory_budget, _py_memory_disabled_value, reset_discovered_windows |
|
||||
| local_tool_runtime | 809 | 8/30 | _find_capability_executor, _extract_context_length, context_length, reset_context_length_cache, supports_tools, supports_thinking |
|
||||
| construction_interface | 1193 | 6/27 | _to_stage_check, _guard_specs_from_obligations, t_layout, _obligations_projection, _obligation_scope_files, main |
|
||||
| structural_store | 656 | 12/33 | _sorted, new_doc, load, _redact_secrets, save, canonical_digest |
|
||||
| persona_gate | 724 | 7/26 | _now, _cc_pg_core, _py_lex, _lex_input, _py_overlap, _embed_raw |
|
||||
| sleep_time | 984 | 8/26 | _ctx_budget, _ensure_dirs, db_connect, fetch_sessions, retain_to_store, reflect_local |
|
||||
| provider_registry | 679 | 11/28 | _ctx_budget, _format_tools_openai, _execute_tool_calls, _execute_tool_calls_anthropic, get_registry, connect_provider |
|
||||
| tool_protocol | 461 | 10/27 | _utc_now_iso, _contains_tool_object_key, to_ollama_tools, dispatch_validated_tool, tool_requires_approval, to_dict |
|
||||
| warm_router | 1540 | 19/36 | _ensure_use_history_table, record_outcome, record_neuron_fire, _py_base_level_from_uses, base_level_activation, _db |
|
||||
| construction_decision | 1014 | 4/20 | normalize_need, _sc_core, _py_language_placement, resolve_surface, ss_entity, implemented_contracts |
|
||||
| tool_executor | 1836 | 31/47 | _execute_tool_now, _prepared_path, serialize_prepared_tool, deserialize_prepared_tool, confirm_write, _resolve_execution_cwd |
|
||||
| work_manager | 594 | 9/25 | group_by_file, load_config, save_config, load_batches, save_batches, create_work |
|
||||
| growth_delta | 449 | 5/20 | _ctx_budget, _store_db, _llm, _parse_json, _load_deltas, _save_deltas |
|
||||
| memory_consolidation | 743 | 7/22 | _consolidation_memory_oracle, _consolidation_neuron_oracle, _load_knowledge, _save_knowledge, _load_lessons, _save_lessons |
|
||||
| provider_budget | 357 | 5/20 | get_tracker, track_usage, check_provider, get_best_provider, failover, get_status |
|
||||
| safety_override | 574 | 7/22 | _keyword_stopwords, _cc_probe, cc_loader_pin, self_test, _py_matches, escalation_rate |
|
||||
| cron_engine | 440 | 13/27 | get_cron_engine, run_task, start_engine, stop_engine, to_dict, fire_on_task_complete |
|
||||
| night_mode | 421 | 5/19 | _ctx_budget, get_night_mode, start_night_mode, stop_night_mode, get_status, get_report |
|
||||
| scaffold | 868 | 17/31 | init, add_domain, add_component, add_contract, set_prd, set_next_action |
|
||||
| build_mode | 521 | 20/33 | _load_state, _save_state, assess_complexity, start_research, start_feasible, start_consult |
|
||||
| capability_broker | 908 | 7/20 | _native_tool_schemas, _select_for_job, load_registry, _native_tool_cards, _cards_are_stale, load_cards |
|
||||
| failure_auto_filer | 527 | 11/24 | _error_text, unconsumed, mark_consumed, unconsumed, mark_consumed, submit |
|
||||
| cache | 492 | 6/17 | _record_hit, _record_miss, flush_stats, get_cache, put_cache, invalidate_scope |
|
||||
| elastic_cognition | 774 | 3/14 | _ctx_budget, _build_constitution, _get_constitution, _load_cloud_config, execute_at_tier, _execute_deterministic |
|
||||
| identity_anchors | 542 | 5/16 | show_anchors, show_rules, show_pronouns, _announcement_patterns, _pronoun_patterns, _hedge_patterns |
|
||||
| parallel_processor | 194 | 3/14 | _shutdown_processor, get_processor, run_parallel_with_args, get_status, test_parallel, run_parallel_with_args |
|
||||
| structural_model | 352 | 9/20 | workspace_record, workspace_advance, _init_project, save, reload, add |
|
||||
| capability_fit | 455 | 3/13 | record_semantic_fit, _provides_contracts, _consumers, discover_candidates, _cs_core, decide |
|
||||
| claim_audit | 484 | 4/14 | _get_warm_neuron_store, reframe, _graph_has, _warm_has, verify, journal |
|
||||
| drift_core | 517 | 4/14 | _ms_core, _now_iso, _py_check_promotion_eligibility, promote_entry, compute_fama, compute_drift_velocity |
|
||||
| model_profiles | 438 | 5/15 | get_profile_path, load_profile, save_profile, build_profile_from_ollama, scan_all_models, get_or_create_profile |
|
||||
| tier_manager | 262 | 5/15 | _cc_probe, cc_loader_pin, _py_core_now, _py_get_tier, _py_promote, _py_demote |
|
||||
| witness | 475 | 8/18 | _ctx_budget, _now, _cc_probe, cc_loader_pin, _py_extract_topic, _py_detect_signals |
|
||||
| drift_compression | 307 | 3/12 | _py_get_compression_ratio, _py_compress_text, _py_compress_entry, _py_should_warn, _py_warn_before_compress, get_compression_ratio |
|
||||
| builder_bridge | 326 | 3/11 | _construction_store, _active_construction_lines, _default_selector, _cached_memory, _get_selector, _retrieve_memory |
|
||||
| graph_memory | 474 | 2/9 | now_iso, connect, resolve_entity, add_edge, query, stats |
|
||||
| intent_continuity | 168 | 2/9 | to_dict, from_dict, _load, save, create_detour, resolve_detour |
|
||||
| pins | 284 | 5/12 | _store_path, _save, _detail_blob, unpin, _py_pin_recall, list_pins |
|
||||
| voice_hybrid | 427 | 3/10 | _connect, _load_growth, _save_growth, source_profiles, always, grow |
|
||||
| voice_sync | 299 | 3/10 | _now, get_delivery_register_from_db, get_delivery_register, update_rune_md, check_sync, handle_hook |
|
||||
| audit_ledger | 212 | 2/8 | _compute_hash, get_entries, log_promotion, log_gate_result, log_drift_alert, main |
|
||||
| context_pressure | 262 | 3/9 | log_measurement, read_log, log_stats, _now, handle_hook, main |
|
||||
| core_server | 234 | 6/12 | make_server, log_message, _send_json, _send_ndjson, do_GET, do_POST |
|
||||
| microkernel | 434 | 6/12 | now_iso, discover, _extract_manifest, _load_registry, _save_registry, _run_hook |
|
||||
| model_registry | 253 | 2/8 | test_registry, to_dict, get_profile, get_enabled_profiles, get_profiles_by_tier, list_profiles |
|
||||
| persona_definition | 210 | 2/8 | _by_topic, compile_full, emit_constitution, emit_identity, emit_persona, handle_hook |
|
||||
| progressive_escalation | 279 | 2/8 | execute_with_escalation, test_escalation, handle_hook, to_dict, execute, verify |
|
||||
| voicebox | 164 | 5/11 | _run, start_recording, stop_recording, _transcribe_and_type, on_press, on_release |
|
||||
| connection_pool | 148 | 3/8 | get_pool, get_connection, get_status, get_connection, get_status |
|
||||
| hook_engine | 860 | 3/8 | discover_functions, tag_function, validate_placements, generate_report, handle_hook |
|
||||
| iteration | 190 | 3/8 | _now, context_packet, predictive_impact, descriptive_impact, add |
|
||||
| task_persist | 269 | 5/10 | _save, export, restore, main, handle_hook |
|
||||
| tiered_executor | 291 | 3/8 | _ctx_budget, test_executor, to_dict, to_dict, _execute_model |
|
||||
| adaptive_router | 625 | 15/19 | _floor_applies_from_flags, _floor_reason, _record_transition_with, _detect_external_refs |
|
||||
| construction_commands | 268 | 1/5 | _refuse, _validate, _accept, dispatch |
|
||||
| construction_mode | 395 | 1/5 | _tokens, _contains_any, to_dict, from_dict |
|
||||
| model_connect | 471 | 7/11 | _ctx_budget, _now, _get_cloud_models, handle_hook |
|
||||
| self_improve | 246 | 1/5 | _now, suggest_improvements, handle_hook, main |
|
||||
| subconscious_pass | 187 | 1/5 | main, _extract_topic, save_reflection, get_recent_findings |
|
||||
| construction_activation | 237 | 1/4 | _scaffold_for, _auto_structural_awareness, dispatch_from_decision |
|
||||
| construction_projection | 225 | 1/4 | _contract_entity, validate, write_mini_doc |
|
||||
| dependency_tracker | 202 | 2/5 | check_propagation, get_full_map, main |
|
||||
| event_envelope | 303 | 5/8 | test_envelope, to_canonical_dict, to_dict |
|
||||
| response_adapter | 222 | 4/7 | parse_plain_response, test_adapter, to_dict |
|
||||
| salience_gate | 243 | 1/4 | test_salience, handle_hook, to_dict |
|
||||
| subsystem_health | 163 | 3/6 | set_auto_filer, record_failure, configure_logging |
|
||||
| warm_neuron_store | 122 | 3/6 | _db, neuron_slugs, handle_hook |
|
||||
| cognitive_budgeter | 208 | 1/3 | test_budgeter, to_dict |
|
||||
| event_bus | 244 | 5/7 | _store_path, handle_hook |
|
||||
| graph_projection | 108 | 3/5 | write_all, _now |
|
||||
| rune_profiler | 165 | 1/3 | profile_model_call, main |
|
||||
| stage_guards | 281 | 7/9 | to_dict, chk |
|
||||
| standardized_providers | 281 | 3/5 | list_providers, connect_all_local |
|
||||
| structural_migration | 77 | 2/4 | apply_migration, consent_brief |
|
||||
| voice_injector | 138 | 3/5 | test_injection, to_dict |
|
||||
| construction_depth | 138 | 1/2 | to_dict |
|
||||
| recall_router | 165 | 2/3 | handle_hook |
|
||||
|
||||
## FULL — ported, parity-gated
|
||||
|
||||
| Module | Lines | Fns | Side |
|
||||
|---|---|---|---|
|
||||
| recall_uplift | 141 | 1/1 | RUST |
|
||||
| rune_spinner | 130 | 4/5 | RUST |
|
||||
| wait_guard | 116 | 1/1 | RUST |
|
||||
| failure_recovery | 108 | 1/1 | RUST |
|
||||
| programme_gates | 85 | 4/5 | RUST |
|
||||
| impact_preview | 69 | 2/2 | RUST |
|
||||
| provider_context | 48 | 1/1 | GO |
|
||||
| route_risk_flags | 37 | 1/1 | RUST |
|
||||
@@ -1,134 +0,0 @@
|
||||
# THE LANGUAGE DICHOTOMY LEDGER — measured, not assumed
|
||||
|
||||
_Created 2026-10-06 from real benchmarks. This is the governing standard for every port in the full dichotomy rebase. Every port must pass the "which language is better for THIS operation?" test before being assigned._
|
||||
|
||||
---
|
||||
|
||||
## The Measured Benchmarks
|
||||
|
||||
| Operation | Python | Python ctypes → Rust | Go cgo → Rust | Pure Go inline |
|
||||
|---|---|---|---|---|
|
||||
| Simple tier check | 0.05 µs | 1.4 µs | 1.4 µs | — |
|
||||
| Consolidation (669B payload) | 0.2 µs | 2.9 µs | 3.4 µs | 0.3 µs |
|
||||
| Concurrent HTTP (10 requests) | 10.8ms (4.0x) | — | 8.4ms (5.1x) | — |
|
||||
| CPU-bound pattern matching (1000 msgs) | 9.6ms (0.8x — GIL) | — | ~2.5ms (est. 3.5-4x) | — |
|
||||
| Compression + zlib wrapper | 0.2 µs | 13.7 µs (worse!) | — | — |
|
||||
|
||||
## The Laws
|
||||
|
||||
### Law 1: FFI overhead is negligible for the real workload
|
||||
The cgo/ctypes boundary costs 1.4-3.4 µs per call. Ollama inference costs 200-5000 ms. FFI overhead is 0.0003-0.0017% of total request time. The language of the caller doesn't matter for the boundary.
|
||||
|
||||
### Law 2: Go wins for CPU-bound reactive work
|
||||
Goroutines deliver true parallelism (5.1x concurrent HTTP, ~3.5-4x CPU-bound). Python's GIL serialises CPU-bound work (0.8x speedup with 4 threads). Go wins for: operator, witness, event bus, work manager, tool executor.
|
||||
|
||||
### Law 3: Simple operations stay in the caller's language
|
||||
Pure Python compression: 0.3 µs. Same op via Rust FFI: 10.4 µs. The FFI overhead exceeds the compute benefit for simple operations. If a Go module needs a string truncation, do it IN GO.
|
||||
|
||||
### Law 4: Rust wins for complex deterministic operations
|
||||
Compile-time type safety, zero-cost abstractions, memory safety, near-native speed for complex compute. Rust wins for: scoring, dedup, pattern matching across many signals, record assembly with many fields, structural store operations.
|
||||
|
||||
### Law 5: Compression across the FFI boundary makes things SLOWER
|
||||
Measured: uncompressed FFI call = 6.1 µs. With zlib wrapper = 13.7 µs (+125%). The cgo transition overhead (~1-2µs) dominates; payload size doesn't matter for local calls under 10KB. Compression helps only for network transfers (>100KB payloads).
|
||||
|
||||
### Law 6: Reduced payload (shorter keys) gives a marginal improvement
|
||||
Measured: 6.1 → 4.6 µs (-25%) by shortening JSON keys from "wash_count" to "w". This is a valid optimisation for hot-path FFI calls but not worth the complexity for most operations.
|
||||
|
||||
### Law 7: Pure inline (no FFI) is fastest when the operation is simple
|
||||
Measured: pure Go inline = 0.3 µs vs 6.1 µs via FFI. If the operation is simple enough to implement in the caller's language, do it inline. Only cross the FFI boundary for operations complex enough to justify it.
|
||||
|
||||
---
|
||||
|
||||
## The Practical Decision Tree
|
||||
|
||||
```
|
||||
Is the operation I/O-bound (HTTP, subprocess, file I/O)?
|
||||
→ YES → GO (goroutines, net/http, os/exec)
|
||||
→ NO ↓
|
||||
|
||||
Is the operation CPU-bound and in the request path (responding to user)?
|
||||
→ YES → GO (goroutines give true parallelism where the GIL fails)
|
||||
→ NO ↓
|
||||
|
||||
Is the operation complex deterministic compute (multiple functions, thresholds, scoring)?
|
||||
→ YES → RUST (type safety, zero-cost abstractions, memory safety)
|
||||
BUT measure: does the compute exceed the FFI overhead?
|
||||
→ NO ↓
|
||||
|
||||
Is the operation simple (string truncation, basic comparison, simple lookup)?
|
||||
→ YES → Do it INLINE in the caller's language (no FFI)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The Wave Assignment (corrected)
|
||||
|
||||
| Wave | Language | Why |
|
||||
|---|---|---|
|
||||
| W4: event-bus, hook-engine, message-queue, microkernel, subsystem-health, parallel-processor, work-manager, failure-filer, cron-engine, night-mode, cache, connection-pool, recall-router | **Go** | I/O-bound, CPU-bound reactive, event-driven |
|
||||
| W4b: tool-executor, tool-protocol, local-tool-runtime | **Go** | I/O-bound, request-path |
|
||||
| W5a: model-connect (all 10 provider modules) | **Go** | I/O-bound (HTTP), connection pooling |
|
||||
| W5b: operator, adaptive_router, build_mode, warm_router, etc. | **Go** | CPU-bound reactive (routing, dispatch) + I/O-bound |
|
||||
| W5c: memory_store, curator, sleep_time | **Go** | I/O-bound (SQLite + subprocess) |
|
||||
| W6: spine, construction_*, contracts, capability_*, drift_*, graph_memory, memory_selector, identity_anchors, pins, salience_gate, self_improve, token_optimizer | **Rust** | Complex deterministic compute (scoring, dedup, classification, structural operations) |
|
||||
| W6 simple modules: response_adapter, route_risk_flags, rune_profiler, rune_spinner, wait_guard, task_persist, time_awareness | **Stay in caller's language** | Simple operations where FFI overhead > compute benefit |
|
||||
| W7: TUI | **Go (Bubble Tea)** | The reactive front end that interfaces with the user |
|
||||
|
||||
---
|
||||
|
||||
## The Compression Idea (EXPERIMENTAL — NOT WORTH IT)
|
||||
|
||||
**Measured result: compression across the FFI boundary makes things 125% SLOWER.**
|
||||
|
||||
The cgo transition overhead (~1-2µs) is the dominant cost, not the payload size. Compressing the payload adds CPU work (compress + decompress) that exceeds the benefit of a smaller payload crossing the boundary. The compressed payload is 20% of the original size, but the total time doubles.
|
||||
|
||||
Compression WOULD help only if:
|
||||
- The payload were >100KB (network transfer between machines)
|
||||
- The boundary were a network connection, not a local function call
|
||||
|
||||
**Mark as experimental and park. Do not implement.**
|
||||
|
||||
---
|
||||
|
||||
## The Hybrid Language Idea (FUTURE — NOT NOW)
|
||||
|
||||
A hybrid language combining Go's concurrency with Rust's type safety and memory safety would eliminate the FFI boundary entirely. This would be the ideal language for the entire runtime.
|
||||
|
||||
But this is a much larger project — effectively designing and implementing a new programming language. It should be explored after the rebase is complete and the system is stable in Go+Rust. The cgo boundary works today with negligible overhead.
|
||||
|
||||
---
|
||||
|
||||
## Provenance
|
||||
|
||||
- Benchmarks run 2026-10-06 on nick-desktop (CachyOS, 4 cores, cgo 1.21, modernc.org/sqlite)
|
||||
- Rust kernel: libcognition_core.so from cognition_core crate
|
||||
- Go binaries: statically linked, go 1.21
|
||||
- Python: /home/nick/.venvs/memory/bin/python3
|
||||
- These measurements are for THIS hardware and THIS codebase. Re-measure if the hardware changes.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## The Hybrid Language: SURVIVOR
|
||||
|
||||
Named by Nick (2026-10-06): Rust (survives, memory-safe, deterministic) + Go (running, reactive, concurrent) = **Survivor** — the hybrid language pattern where Go reactive code links Rust deterministic compute as a static library at compile time.
|
||||
|
||||
### The Survivor Build Pattern
|
||||
- Rust crates compile as staticlib (.a) + cdylib (.so)
|
||||
- Go binaries link the .a files at compile time via cgo LDFLAGS
|
||||
- The caller sees ONE binary with ONE function call — no FFI boundary from the outside
|
||||
- No CC_RUST_LIB / SC_RUST_LIB env vars needed
|
||||
- Measured: 0.6µs/call vs 1.4-3.4µs for the .so approach
|
||||
|
||||
### Survivor Go Packages
|
||||
All under src/go/cognition/:
|
||||
- cognition (root): tier, consolidation, witness, safety, drift, pins, growth
|
||||
- retrieval: memory_retrieval kernel (mr_call)
|
||||
- storage: memory_storage kernel (mems_read_query)
|
||||
- scaffold: scaffold_core kernel (sc_check_transition, sc_close_quality, sc_language_placement)
|
||||
- provenance: evidence_provenance kernel (ep_* functions)
|
||||
- spine: rune_spine kernel (sp_drift, sp_export, sp_project, sp_query)
|
||||
- scoring: memory_scoring kernel (ms_* functions)
|
||||
- capability: capability_scoring kernel (cs_evaluate_fit, cs_score_card)
|
||||
- token: token_counting kernel (tc_compress_context, tc_estimate_tokens)
|
||||
- query: query_memory kernel (qm_* functions)
|
||||
@@ -1,52 +0,0 @@
|
||||
# Phase G Slice 2 (T7.3) — Evidence-Provenance Surface Census (#2449)
|
||||
|
||||
Generated 2026-10-08 (contract BUILDER-2026-10-08T14:02:24Z-588ca6). The
|
||||
six-module surface, its Rust candidate, and the per-module switch state —
|
||||
measured, not asserted. This is the frozen-contract input.
|
||||
|
||||
## The Rust candidate
|
||||
|
||||
`src/rust/evidence_provenance/` — 24 `pub extern` symbols, CI-built on all
|
||||
three rust steps (evidence_provenance/Cargo.toml in every list). The
|
||||
cdylib carries the ep_* core (compute_hash, append_entry, verify_chain)
|
||||
plus the per-module helper seams (ca_*, and the loader families).
|
||||
|
||||
## Per-module switch state
|
||||
|
||||
| module | loader integration | parity evidence | state |
|
||||
|---|---|---|---|
|
||||
| claim_audit.py | ep_loader (ca_evidence_terms, ca_verify_gate, ca_report_aggregate) — 17/17 proven vs this module's Python vintage (docstring) | ep parity 17/17 | SWITCHED |
|
||||
| behavior.py | 4 loader/ctypes refs | ep_loader import + parity battery | SWITCHED |
|
||||
| behaviour_ledger.py | 11 loader/ctypes refs | dual-import (validation ledger) | SWITCHED |
|
||||
| evidence_probe.py | 4 loader/ctypes refs | ep_loader delegation | SWITCHED |
|
||||
| verification_layer.py | 3 loader/ctypes refs | ep_loader delegation | SWITCHED |
|
||||
| audit_ledger.py | 0 — NO loader integration | drift-key vintage split (see below) | REMAINING GAP |
|
||||
|
||||
Test batteries observed green this session: claim_audit/audit_ledger/
|
||||
behavior/evidence_probe/verification_layer families 14/14;
|
||||
test_evidence_provenance_shims.py 6/6.
|
||||
|
||||
## The remaining work (batches after this census)
|
||||
|
||||
1. **audit_ledger switch** — the only module with zero loader integration.
|
||||
Pin the DRIFT KEY FIRST: the live promotion_ledger.jsonl (21 entries)
|
||||
verifies valid under the DEPLOYED vintage key `rune-drift-integrity-2024`;
|
||||
the src/rune default (`rune-governed-adaptation-2024`) fails it. The
|
||||
Rust seam must carry the deployed-vintage key as the verification key
|
||||
for existing entries (the frozen contract pins this).
|
||||
2. **Vintage reconciliation** — src/rune/ is the hardened NEWER vintage
|
||||
(memory_env-pathed DB, defensive code); deployed + shared/ audit_ledger
|
||||
are OLDER. The switch must reconcile, not clobber (RECONCILE-DON'T-CLOBBER).
|
||||
3. **Supersession ledger** — per-module close records after shadow evidence.
|
||||
4. **Shadow** — run the ep parity battery + per-module canaries as the
|
||||
shadow evidence per the slice-1 pattern (see scripts/qm_shadow.py for
|
||||
the shape).
|
||||
|
||||
## Grounding findings carried from the issue (verified this session)
|
||||
|
||||
- Only 3 of 6 modules are deployed (~/.config/opencode/scripts/):
|
||||
audit_ledger, behavior, claim_audit. Consumers confirmed: rune_tui.py
|
||||
(claim_audit, behavior), curator.py + canaries (audit_ledger),
|
||||
rune_operator.py:581 (evidence_probe).
|
||||
- The divergent-vintage finding and the live-ledger drift-key finding are
|
||||
banked above and pin the contract.
|
||||
@@ -44,13 +44,3 @@ were removed after RP10 proved the canonical Research-to-Build pipeline
|
||||
(epic #257). Their trigger label (`research-pending`) was stripped from all
|
||||
disposable issues on 2026-09-08 (RP0). Historical evidence retained in
|
||||
research/issue-* directories and closed issues (#245, #254-#256, #260-#263).
|
||||
|
||||
## fault-watch (`.gitea/workflows/fault-watch.yml`)
|
||||
- **Trigger:** CI Pipeline completion + every 15 min schedule
|
||||
- **Purpose:** Monitors the 5 named gates (lint/unit-tests/rust-surface/go-surface/canary) on HEAD SHA. Auto-files `ci-fault` issues (labeled ci-fault+bug) on failure, auto-closes when the gate goes green on a pushed commit.
|
||||
- **Failure mode:** If the fault-watch itself fails, CI failures go undetected — the nightly cron sweep is the backstop.
|
||||
|
||||
## local-review (`.gitea/workflows/local-review.yml`)
|
||||
- **Trigger:** Pull request events (opened, synchronize)
|
||||
- **Purpose:** Runs the local review pipeline (lint gates + parity checks) on PR branches before merge.
|
||||
- **Failure mode:** A failure here blocks the PR merge — the required-checks job gates on it.
|
||||
@@ -75,29 +75,3 @@ And the role-separation rules: the black-box test author (fresh context) has
|
||||
already written the spec tests; the reviewer checks the implementation
|
||||
against tests it did not write; vacuity spot-checks (one manual mutant per
|
||||
load-bearing branch) are BLOCKER-grade findings when tests survive them.
|
||||
|
||||
## Dimensional review rubric (#129 — mandatory for P0/P1)
|
||||
|
||||
Holistic judgment ("is this good?") is replaced by per-dimension
|
||||
forced-choice scoring. Every review dispatch MUST score each dimension
|
||||
explicitly — a review missing any dimension is INCOMPLETE and bounces.
|
||||
|
||||
| Dimension | What to score | Verdicts |
|
||||
|---|---|---|
|
||||
| Correctness | Does the code do what the issue/spec requires? Verify call sites, not claims. | PASS / CONCERN / FAIL |
|
||||
| Design | Does the shape fit the codebase (parity laws, authority maps, no second authorities)? | PASS / CONCERN / FAIL |
|
||||
| Test quality | Do the tests prove the behavior (real-path, oracle-derived, would fail without the fix)? | PASS / CONCERN / FAIL |
|
||||
| Observability | Are failures visible (logged, journaled, gated) rather than silent? | PASS / CONCERN / FAIL |
|
||||
| Security | Approval boundaries, secret handling, injection surfaces — anything that widens trust? | PASS / CONCERN / FAIL |
|
||||
|
||||
Example (the required output shape):
|
||||
```
|
||||
Correctness: PASS (36 call sites verified).
|
||||
Design: PASS with concern (registry singleton).
|
||||
Test quality: CONCERN (no real-path test).
|
||||
Observability: PASS.
|
||||
Security: PASS.
|
||||
```
|
||||
Five explicit verdicts the controller acts on dimensionally — a CONCERN
|
||||
or FAIL in any dimension blocks the gate until discharged or explicitly
|
||||
accepted with a reason.
|
||||
@@ -1,60 +0,0 @@
|
||||
# SUPERSESSION REPORT — programmatic evidence
|
||||
_Created 2026-10-07. Question: is curator superseded by memory_consolidation? Can supersession be determined programmatically?_
|
||||
|
||||
## Answer in one paragraph
|
||||
|
||||
No — they are NOT supersessions of each other. They are two different machines in one pipeline: **memory_consolidation compresses what already exists** (warm neurons, graph entities, abstraction facts → consolidated knowledge records), while **curator gates what gets written** (evidence → worthiness filter → graded routing → tiers). Both are wired into sleep_time's nightly run: consolidation runs in-process, curator runs as a subprocess. The real finding is darker: **curator has NEVER successfully run in production** — three of its four dependencies were never ported from the Odysseus branch, so every invocation died at import. Both diagnoses were reached programmatically.
|
||||
|
||||
## The programmatic supersession test (reusable)
|
||||
|
||||
Six signals, each binary and evidence-based (`/tmp/ss_engine.py`, promote to scripts/):
|
||||
|
||||
| Signal | Test | Weight |
|
||||
|---|---|---|
|
||||
| R1 Import graph | production importers vs canary-only importers | high |
|
||||
| R2 Subprocess summon | module executed as a script by another module | high |
|
||||
| R3 Output artifacts | documented output files exist with recent mtimes | high |
|
||||
| R4 Function overlap | name overlap with the suspected successor | low (weak signal) |
|
||||
| R5 Importability | `import X` succeeds (phantom dep = dead) | gate — fails = dead regardless |
|
||||
| R6 End-to-end probe | documented entry path executes with real input | decisive |
|
||||
|
||||
## Applied to curator vs memory_consolidation
|
||||
|
||||
| Signal | curator | memory_consolidation |
|
||||
|---|---|---|
|
||||
| R1 | 0 production importers | 2 (memory_selector, sleep_time) |
|
||||
| R2 | summoned as script by sleep_time + dependency_tracker | summoned by dependency_tracker |
|
||||
| R3 | **index/blocks_meta.json DOES NOT EXIST — no journal files — never wrote output** | graph.sqlite exists but **stale (Aug 22)**; consolidation/*.json never created |
|
||||
| R4 | 2% overlap — different function sets (confirms: different jobs) | 2% |
|
||||
| R5 | importable NOW (after repair); dead since #314 | importable |
|
||||
| R6 | dry-run probe NOW green (post-repair); was JSONDecodeError-crash | consolidate() wired, but its outputs absent too |
|
||||
|
||||
## Verdict
|
||||
|
||||
1. **NOT a supersession.** 2% function overlap + different roles: curator = write-path gate (worthiness → grade → tier), memory_consolidation = read-path compressor (existing memories → knowledge records). One writes, one compresses. Both belong.
|
||||
2. **Both are broken in production.** Curator never ran (phantom deps). memory_consolidation's outputs are stale/absent — its last graph write was Aug 22. The whole sleep-time memory pipeline has been quietly degraded.
|
||||
3. **Disposition: REPAIR, not retire.** grading.py + worthiness.py are now recovered from the Odysseus source branch (provenance, not reconstruction) with frozen tests; curator's dry-run executes end-to-end. Remaining phantom for curator: lexicon_evolution (guarded — degrades), aaak (guarded — optional compression). Both degradable, not blocking.
|
||||
|
||||
## The phantom-import census (the general finding)
|
||||
|
||||
16 phantom imports found across src/rune. The important ones:
|
||||
|
||||
| Module | Importers | Guarded? | Disposition |
|
||||
|---|---|---|---|
|
||||
| worthiness | curator | NO (hard crash) | ✅ RECOVERED from Odysseus + frozen tests |
|
||||
| grading | curator | NO | ✅ RECOVERED from Odysseus + frozen tests |
|
||||
| lexicon_evolution | curator | yes (degrades) | recover-or-rename decision needed |
|
||||
| aaak | curator, memory_store, warm_router | yes | optional compression; recover or accept degrade |
|
||||
| build_pipeline_policy | prompt_sync | NO | phantom — prompt_sync is dead on arrival |
|
||||
| gitea_auth | forge | NO | forge.py dead; is forge itself superseded? |
|
||||
| faster_whisper, pynput | voicebox | yes | optional deps — correct as-is |
|
||||
| research_lens | claim_audit | yes | lives in ~/.config/opencode/scripts — cross-repo dep |
|
||||
| ep_loader | 5 modules | false positive | resolves via sys.path hack to src/rust/ |
|
||||
| autonomy_loop, cognitive_loop, dream_cycle | rune_tui | yes | TUI plugins — recover or retire |
|
||||
| commitments, dedupe_policy, local_memory | warm_router, memory_store, sleep_time | yes | recover-or-accept-degrade |
|
||||
|
||||
**Hard-crash phantoms mean the owning module is dead code:** prompt_sync, forge, and (until today) curator.
|
||||
|
||||
## What the dictonomy rebase inherits
|
||||
|
||||
The Go/Rust port queue should SKIP dead code until its disposition is decided. A module that never ran has no behavioral parity to prove — porting it would faithfully reproduce a ghost. The audit instrument now needs an R5 importability column so dead modules are marked before they're counted.
|
||||
+123
-146
@@ -1,150 +1,127 @@
|
||||
settings:
|
||||
warn_about_similar_files:
|
||||
above: 0.85
|
||||
ignore:
|
||||
- docs/review-lessons.yaml
|
||||
- docs/v1/**
|
||||
- docs/wiki/**
|
||||
- store/spine/**
|
||||
- shared/**
|
||||
- src/rune/drift_core.py
|
||||
- src/rune/drift_compression.py
|
||||
- src/rune/drift_observability.py
|
||||
- src/rune/shard_manager.py
|
||||
- src/rune/subconscious_pass.py
|
||||
- .gitea/ISSUE_TEMPLATE/**
|
||||
- shared/issue_templates/**
|
||||
- bridge/daemon/completion_file.py
|
||||
- scripts/completion_file.py
|
||||
- interop/rebase-proof/**
|
||||
- src/rust/*/Cargo.lock
|
||||
- src/rust/*/src/pyjson.rs
|
||||
- src/rust/query_memory/src/json_min.rs
|
||||
- store/scaffold/**
|
||||
ignore: ["docs/review-lessons.yaml", "docs/v1/**", "docs/wiki/**", "store/spine/**",
|
||||
# shared/ is the DEPLOYED-VINTAGE mirror tree (strangler era):
|
||||
# every src/rune <-> shared similarity here is intentional
|
||||
# (the shim delegates to the crate; the mirror is the deployed
|
||||
# vintage it strangles). Registering the deliberate pairs.
|
||||
"shared/**",
|
||||
"src/rune/drift_core.py", "src/rune/drift_compression.py",
|
||||
"src/rune/drift_observability.py", "src/rune/shard_manager.py",
|
||||
"src/rune/subconscious_pass.py",
|
||||
# deliberate mirror pairs outside the strangler set:
|
||||
# issue templates are mirrored into shared/issue_templates;
|
||||
# completion_file.py is the bridge/daemon mirror of scripts/;
|
||||
# interop/rebase-proof is a committed proof fixture.
|
||||
".gitea/ISSUE_TEMPLATE/**", "shared/issue_templates/**",
|
||||
"bridge/daemon/completion_file.py", "scripts/completion_file.py",
|
||||
"interop/rebase-proof/**",
|
||||
# per-crate copies by zero-dep design: each crate is
|
||||
# self-contained (no shared crate dependency), so the pyjson
|
||||
# JSON module is copied verbatim per crate and the tiny
|
||||
# zero-dep lockfiles are near-identical by construction.
|
||||
"src/rust/*/Cargo.lock", "src/rust/*/src/pyjson.rs",
|
||||
"src/rust/query_memory/src/json_min.rs",
|
||||
# store/scaffold is data (proof fixtures, gate objects),
|
||||
# same class as the already-ignored store/spine.
|
||||
"store/scaffold/**"]
|
||||
|
||||
henxels:
|
||||
- henxel: Canaries live at the repo's canary slot and are registered in CI
|
||||
in: ./src/rune/**/canary_*.py
|
||||
ci_runs_all_canaries: true
|
||||
- henxel: No secrets in tracked files
|
||||
no_secrets: true
|
||||
except:
|
||||
- ./tests/test_gitea_provision.py
|
||||
- ./tests/test_gitea_auth.py
|
||||
- ./.ci-venv/**
|
||||
- ./.test-venv/**
|
||||
- ./.canary-venv/**
|
||||
- ./backups/**
|
||||
- henxel: Plans are markdown, one per build
|
||||
in: ./plans
|
||||
allowed_filetypes:
|
||||
- .md
|
||||
filename_casing: kebab-case
|
||||
- henxel: Top-level docs are markdown or yaml references
|
||||
in: ./docs/*
|
||||
allowed_filetypes:
|
||||
- .md
|
||||
- .yaml
|
||||
except:
|
||||
- ./docs/v1/**
|
||||
- ./docs/wiki/**
|
||||
- ./docs/gitea_issue_reconciliation.json
|
||||
- ./docs/rebase/**
|
||||
- henxel: "The known giant stays visible \u2014 file-size debt is tracked, not silent"
|
||||
in: ./src/rune/*
|
||||
except:
|
||||
- ./src/rune/rune_tui.py
|
||||
- ./src/rune/rune_operator.py
|
||||
- ./src/rune/memory_store.py
|
||||
- ./src/rune/curator.py
|
||||
- ./src/rune/tool_executor.py
|
||||
- ./src/rune/warm_router.py
|
||||
- ./src/rune/spine.py
|
||||
max_lines: 1250
|
||||
- henxel: "The umbrella impact map is complete and truthful \u2014 every module mapped,\
|
||||
\ no phantom entries"
|
||||
in: ./config/umbrellas.json
|
||||
umbrella_manifest_is_complete: true
|
||||
- henxel: "Umbrella canaries exist in the repo \u2014 the propagation gate cannot\
|
||||
\ reference ghosts"
|
||||
in: ./config/umbrellas.json
|
||||
umbrella_canaries_exist: true
|
||||
- henxel: "The umbrella dependency graph stays a DAG \u2014 reflexive updates cannot\
|
||||
\ cycle"
|
||||
in: ./config/umbrellas.json
|
||||
umbrella_dag_acyclic: true
|
||||
- henxel: "The bug-fix discharge contract is a governed doc \u2014 it exists, is markdown,\
|
||||
\ and changes are deliberate"
|
||||
in: ./docs/bugfix-contract.md
|
||||
allowed_filetypes:
|
||||
- .md
|
||||
- henxel: "The discharge checker ships with the repo \u2014 red-first enforcement\
|
||||
\ is structural"
|
||||
in: ./scripts
|
||||
required_files:
|
||||
- check_discharge_contract.py
|
||||
- henxel: Discharge checker and its CI wiring change together
|
||||
changed_with:
|
||||
when: scripts/check_discharge_contract.py
|
||||
expect: ./.gitea/workflows/pipeline-gate.yml
|
||||
- henxel: "Every workflow is registered in the pipeline registry \u2014 new pipeline\
|
||||
\ machinery ships with documentation"
|
||||
in: ./.gitea/workflows/*.yml
|
||||
workflows_are_governed: true
|
||||
- henxel: "Every TUI surface is registered \u2014 no silent UI growth"
|
||||
in: ./src/rune/*tui*.py
|
||||
tui_panels_are_governed: true
|
||||
- henxel: "New rune modules ship with tests or a canary \u2014 no ungoverned code\
|
||||
\ surfaces"
|
||||
in: ./src/rune/*.py
|
||||
new_rune_modules_have_canary_or_test_coverage: true
|
||||
- henxel: Rust crate files stay under a line budget
|
||||
in: ./src/rust/*/src/*.rs
|
||||
except:
|
||||
- ./src/rust/*/src/pyjson.rs
|
||||
- ./src/rust/*/src/json_min.rs
|
||||
max_lines: 3000
|
||||
- henxel: Go modules stay under a line budget
|
||||
in: ./src/go/**/*.go
|
||||
max_lines: 2000
|
||||
- henxel: No secrets in Rust or Go source files
|
||||
in:
|
||||
- ./src/rust/*/src/*.rs
|
||||
- ./src/go/**/*.go
|
||||
no_secrets: true
|
||||
- henxel: "PRDs are living documents \u2014 their generated state sections regenerate\
|
||||
\ identically from governed sources"
|
||||
changed_with:
|
||||
when: config/umbrellas.json
|
||||
expect: ./docs/pipeline-prd.md
|
||||
- henxel: "PRD staleness is a CI failure \u2014 docs rot is silent failure"
|
||||
in: ./scripts/gen_prd_state.py
|
||||
required_files:
|
||||
- gen_prd_state.py
|
||||
- henxel: "The adversarial review procedure is binding \u2014 dispatch templates must\
|
||||
\ reference it"
|
||||
in: ./docs/adversarial-review.md
|
||||
required_files:
|
||||
- ../docs/reviewer-dispatch-template.md
|
||||
- henxel: "The fixture pipeline ships with the repo \u2014 production failure capture\
|
||||
\ is structural"
|
||||
in: ./scripts
|
||||
required_files:
|
||||
- capture_failure.py
|
||||
- henxel: "Production failure fixtures are a governed surface \u2014 the registry\
|
||||
\ and its README exist"
|
||||
in: ./tests/fixtures/production
|
||||
required_files:
|
||||
- manifest.json
|
||||
- README.md
|
||||
- henxel: "Fixture payloads and the manifest travel together \u2014 tamper-evidence\
|
||||
\ needs both"
|
||||
changed_with:
|
||||
when: tests/fixtures/production/**/payload.json
|
||||
expect: tests/fixtures/production/manifest.json
|
||||
- henxel: The fixture manifest and its generated regression tests travel together
|
||||
changed_with:
|
||||
when: tests/fixtures/production/manifest.json
|
||||
expect: tests/fixtures/production/test_production_fixtures.py
|
||||
- henxel: "The dichotomy is enforced at the commit boundary — every src/rune module lands in its measured side, dead oracles and wrong-language kernels fail with the correct implementation as the instruction"
|
||||
in: ./src/rune
|
||||
dichotomy_language_verdict: true
|
||||
- henxel: "Canaries live at the repo's canary slot and are registered in CI"
|
||||
in: ./src/rune/**/canary_*.py
|
||||
ci_runs_all_canaries: true
|
||||
|
||||
- henxel: "No secrets in tracked files"
|
||||
no_secrets: true
|
||||
except: ["./tests/test_gitea_provision.py", "./tests/test_gitea_auth.py", "./.ci-venv/**", "./.test-venv/**", "./.canary-venv/**", "./backups/**"]
|
||||
|
||||
- henxel: "Plans are markdown, one per build"
|
||||
in: ./plans
|
||||
allowed_filetypes: [.md]
|
||||
filename_casing: kebab-case
|
||||
|
||||
- henxel: "Top-level docs are markdown or yaml references"
|
||||
in: ./docs/*
|
||||
allowed_filetypes: [.md, .yaml]
|
||||
except: ["./docs/v1/**", "./docs/wiki/**", "./docs/gitea_issue_reconciliation.json", "./docs/rebase/**"]
|
||||
|
||||
- henxel: "The known giant stays visible — file-size debt is tracked, not silent"
|
||||
in: ./src/rune/*
|
||||
except:
|
||||
- ./src/rune/rune_tui.py
|
||||
- ./src/rune/rune_operator.py
|
||||
- ./src/rune/memory_store.py
|
||||
- ./src/rune/curator.py
|
||||
- ./src/rune/tool_executor.py
|
||||
- ./src/rune/warm_router.py
|
||||
max_lines: 1200
|
||||
|
||||
- henxel: "The umbrella impact map is complete and truthful — every module mapped, no phantom entries"
|
||||
in: ./config/umbrellas.json
|
||||
umbrella_manifest_is_complete: true
|
||||
|
||||
- henxel: "Umbrella canaries exist in the repo — the propagation gate cannot reference ghosts"
|
||||
in: ./config/umbrellas.json
|
||||
umbrella_canaries_exist: true
|
||||
|
||||
- henxel: "The umbrella dependency graph stays a DAG — reflexive updates cannot cycle"
|
||||
in: ./config/umbrellas.json
|
||||
umbrella_dag_acyclic: true
|
||||
|
||||
- henxel: "The bug-fix discharge contract is a governed doc — it exists, is markdown, and changes are deliberate"
|
||||
in: ./docs/bugfix-contract.md
|
||||
allowed_filetypes: [.md]
|
||||
|
||||
- henxel: "The discharge checker ships with the repo — red-first enforcement is structural"
|
||||
in: ./scripts
|
||||
required_files: [check_discharge_contract.py]
|
||||
|
||||
- henxel: "Discharge checker and its CI wiring change together"
|
||||
changed_with:
|
||||
when: scripts/check_discharge_contract.py
|
||||
expect: ./.gitea/workflows/pipeline-gate.yml
|
||||
|
||||
- henxel: "Every workflow is registered in the pipeline registry — new pipeline machinery ships with documentation"
|
||||
in: ./.gitea/workflows/*.yml
|
||||
workflows_are_governed: true
|
||||
|
||||
- henxel: "Every TUI surface is registered — no silent UI growth"
|
||||
in: ./src/rune/*tui*.py
|
||||
tui_panels_are_governed: true
|
||||
|
||||
- henxel: "New rune modules ship with tests or a canary — no ungoverned code surfaces"
|
||||
in: ./src/rune/*.py
|
||||
new_rune_modules_have_canary_or_test_coverage: true
|
||||
|
||||
|
||||
- henxel: "PRDs are living documents — their generated state sections regenerate identically from governed sources"
|
||||
changed_with:
|
||||
when: config/umbrellas.json
|
||||
expect: ./docs/pipeline-prd.md
|
||||
|
||||
- henxel: "PRD staleness is a CI failure — docs rot is silent failure"
|
||||
in: ./scripts/gen_prd_state.py
|
||||
required_files: [gen_prd_state.py]
|
||||
|
||||
- henxel: "The adversarial review procedure is binding — dispatch templates must reference it"
|
||||
in: ./docs/adversarial-review.md
|
||||
required_files: [../docs/reviewer-dispatch-template.md]
|
||||
|
||||
- henxel: "The fixture pipeline ships with the repo — production failure capture is structural"
|
||||
in: ./scripts
|
||||
required_files: [capture_failure.py]
|
||||
|
||||
- henxel: "Production failure fixtures are a governed surface — the registry and its README exist"
|
||||
in: ./tests/fixtures/production
|
||||
required_files: [manifest.json, README.md]
|
||||
|
||||
- henxel: "Fixture payloads and the manifest travel together — tamper-evidence needs both"
|
||||
changed_with:
|
||||
when: tests/fixtures/production/**/payload.json
|
||||
expect: tests/fixtures/production/manifest.json
|
||||
|
||||
- henxel: "The fixture manifest and its generated regression tests travel together"
|
||||
changed_with:
|
||||
when: tests/fixtures/production/manifest.json
|
||||
expect: tests/fixtures/production/test_production_fixtures.py
|
||||
@@ -189,179 +189,3 @@ def new_rune_modules_have_canary_or_test_coverage(param, file, root):
|
||||
f"legacy debt goes in docs/module-coverage-debt.md (tracked, not silent)"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@statement("dichotomy_language_verdict", help="every src/rune module lands in its measured dichotomy side — wrong-language kernels, dead oracles, and regressions fail with the correct implementation as the instruction")
|
||||
def dichotomy_language_verdict(param, file, scope):
|
||||
"""The dichotomy gate (Nick, 2026-10-10): the language law enforced at the
|
||||
commit boundary, with machine-actionable feedback for Rune/MiMo-Rune.
|
||||
|
||||
Authority: store/rebase/classification.json (the measured W0 map —
|
||||
per-module side + evidence). Three violations, each with a specific
|
||||
remediation instruction:
|
||||
|
||||
D1 WRONG-LANGUAGE KERNEL — a module classified RUST has no matching
|
||||
Rust crate/kernel surface while a Go directory claims its name:
|
||||
the deterministic core landed on the reactive side.
|
||||
D2 DEAD ORACLE — a module classified GO/RUST has a ported kernel
|
||||
(src/go/<name>/ or src/rust/<name>/ exists) but the Python module
|
||||
has zero delegation refs (cc_loader / <name>_loader / go-surface
|
||||
call). The port shipped; the adapter never calls it — a facade.
|
||||
D3 REGRESSION — a module classified GO or RUST has NO port directory
|
||||
at all AND the ratchet floor says it was already ported: progress
|
||||
went backwards.
|
||||
|
||||
Feedback format: each failure names the verdict, the measured evidence,
|
||||
and the literal next step (target path + oracle-first battery +
|
||||
contract-first), so the builder agent can act without re-deriving.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re as _re
|
||||
|
||||
if not (file.startswith("src/rune/") and file.endswith(".py")):
|
||||
return None
|
||||
stem = Path(file).stem
|
||||
if stem.startswith(("canary_", "test_", "__")):
|
||||
return None
|
||||
|
||||
root = scope.root
|
||||
try:
|
||||
cls = json.loads((root / "store" / "rebase" / "classification.json").read_text())
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return None # no measured map: the audit instrument owns coverage; do not guess
|
||||
rec = cls.get(stem)
|
||||
if not isinstance(rec, dict):
|
||||
return None
|
||||
side = rec.get("side", "")
|
||||
if side not in ("GO", "RUST", "TUI-LAST"):
|
||||
return None
|
||||
|
||||
go_dir = root / "src" / "go" / stem
|
||||
rust_dir = root / "src" / "rust" / stem
|
||||
evidence = str(rec.get("evidence", ""))[:160]
|
||||
|
||||
# D1 — wrong-language kernel: a GO-classified module must not own a Rust
|
||||
# crate that shadows its name, and vice versa.
|
||||
if side == "RUST" and go_dir.is_dir() and not rust_dir.is_dir():
|
||||
# Wave-3 kernels live in cognition_core by design (cc_<stem> externs).
|
||||
# A RUST-classified module whose kernel exists there is correctly landed
|
||||
# even without a same-named crate.
|
||||
cc = root / "src" / "rust" / "cognition_core" / "src" / "lib.rs"
|
||||
if cc.exists() and f"cc_{stem}" in cc.read_text(encoding="utf-8", errors="replace"):
|
||||
return None
|
||||
return (
|
||||
f"DICHOTOMY D1 (wrong-language kernel): {stem} is measured RUST "
|
||||
f"({evidence}) but src/go/{stem}/ exists with no src/rust/{stem}/. "
|
||||
f"FIX: port the deterministic core to src/rust/{stem}/ (oracle-first "
|
||||
f"truth battery from the Python module, parity-replayed as a HARD CI "
|
||||
f"gate, construction contract FIRST per the absolute-scaffolding law), "
|
||||
f"then retire the Go directory. Feedback path: scripts/dichotomy_audit.py"
|
||||
)
|
||||
if side == "GO" and rust_dir.is_dir() and not go_dir.is_dir():
|
||||
return (
|
||||
f"DICHOTOMY D1 (wrong-language kernel): {stem} is measured GO "
|
||||
f"({evidence}) but src/rust/{stem}/ exists with no src/go/{stem}/. "
|
||||
f"FIX: the reactive surface belongs in src/go/{stem}/ (parity battery "
|
||||
f"+ HARD CI gate + contract first), then retire the Rust crate."
|
||||
)
|
||||
|
||||
# D2 — dead oracle: the port exists but the Python module never delegates.
|
||||
# Delegation forms (all observed in the codebase): cc_loader/_cc_core,
|
||||
# sibling *_loader imports (ep_loader, qm_loader, ms_loader...), direct
|
||||
# ctypes/CDLL. Known pre-existing facades live in the DICHOTOMY DEBT file
|
||||
# (store/rebase/dichotomy_debt.json) — tracked, only-shrinks; a NEW facade
|
||||
# (not in the debt list) fails with the wiring instruction.
|
||||
ported = go_dir.is_dir() or rust_dir.is_dir()
|
||||
if ported and side in ("GO", "RUST"):
|
||||
text = scope.read_text(file) or ""
|
||||
delegating = bool(
|
||||
_re.search(
|
||||
r"import\s+\w*loader\b|from\s+[\w.]+\s+import\s+\w*loader|"
|
||||
r"_cc_core|cc_loader|ctypes|CDLL|go_surface|RUNE_\w+_CORE",
|
||||
text,
|
||||
)
|
||||
)
|
||||
is_loader = stem.endswith("_loader") or stem == "cc_loader"
|
||||
if not delegating and not is_loader:
|
||||
target = f"src/rust/{stem}/" if rust_dir.is_dir() else f"src/go/{stem}/"
|
||||
try:
|
||||
debt = set(json.loads(
|
||||
(root / "store" / "rebase" / "dichotomy_debt.json").read_text()
|
||||
).get("facades", []))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
debt = set()
|
||||
if stem in debt:
|
||||
return None # tracked debt — visible in the debt file, list only shrinks
|
||||
return (
|
||||
f"DICHOTOMY D2 (dead oracle): {stem} has a ported kernel at "
|
||||
f"{target} but the Python module has ZERO delegation references "
|
||||
f"(no cc_loader/_cc_core/*_loader/ctypes call). The port is a "
|
||||
f"facade — production still runs the Python path. FIX: wire the "
|
||||
f"delegation (tier_manager pattern: kernel when available, _py_* "
|
||||
f"parity floor otherwise, both pinned by tests). Pre-existing "
|
||||
f"facades go in store/rebase/dichotomy_debt.json (tracked, "
|
||||
f"list only shrinks). Feedback: scripts/dichotomy_audit.py"
|
||||
)
|
||||
|
||||
# D3 — regression: the ratchet says this module was ported (kernel dir in
|
||||
# git HEAD) but the working tree lost it.
|
||||
if side in ("GO", "RUST") and not ported:
|
||||
ratchet = root / "store" / "rebase" / "ported_ratchet.json"
|
||||
try:
|
||||
ratcheted = set(json.loads(ratchet.read_text()).get("ported", []))
|
||||
except (OSError, json.JSONDecodeError, AttributeError):
|
||||
ratcheted = set()
|
||||
if stem in ratcheted:
|
||||
return (
|
||||
f"DICHOTOMY D3 (regression): {stem} is ratcheted as ported but no "
|
||||
f"src/go/{stem}/ or src/rust/{stem}/ exists in the tree — ported "
|
||||
f"work was deleted. RESTORE the kernel directory (git history has "
|
||||
f"it); the ratchet floor never decreases."
|
||||
)
|
||||
|
||||
# D5 — intent-unconsulted landing: a ported kernel (Go dir or Rust
|
||||
# crate exists) whose intent file still says not_started means the batch
|
||||
# never consulted the module's WHY. Parity is judged against intent, not
|
||||
# just behavior — consult store/scaffold/intent/<stem>.json, satisfy its
|
||||
# laws, and advance its status (not_started → facade → ported → retired).
|
||||
if side in ("GO", "RUST", "TUI-LAST"):
|
||||
if go_dir.is_dir() or rust_dir.is_dir():
|
||||
try:
|
||||
intent_status = json.loads(
|
||||
(root / "store" / "scaffold" / "intent" / f"{stem}.json").read_text()
|
||||
).get("status", "")
|
||||
except (OSError, json.JSONDecodeError):
|
||||
intent_status = ""
|
||||
if intent_status == "not_started":
|
||||
return (
|
||||
f"DICHOTOMY D5 (intent-unconsulted landing): {stem} has a "
|
||||
f"ported kernel but its intent file "
|
||||
f"(store/scaffold/intent/{stem}.json) still says "
|
||||
f"not_started — the batch never consulted the module's WHY. "
|
||||
f"FIX: read the intent file, satisfy its laws, set parity_means "
|
||||
f"for this module, and advance status to ported (or facade if "
|
||||
f"delegation is not yet wired). Parity is judged against "
|
||||
f"intent, not just behavior."
|
||||
)
|
||||
|
||||
# D4 — retired-module resurrection: a module in the retirement ratchet
|
||||
# (strangler exit completed — parity proven + CI green + deployed) must
|
||||
# NOT reappear as a Python file. Singular codebase law.
|
||||
if side in ("GO", "RUST") and not os.path.isdir(f"src/go/{stem}") and not os.path.isdir(f"src/rust/{stem}"):
|
||||
try:
|
||||
retired = set(json.loads(
|
||||
(root / "store" / "rebase" / "retired_modules.json").read_text()
|
||||
).get("retired", []))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
retired = set()
|
||||
if stem in retired and (root / file).exists():
|
||||
return (
|
||||
f"DICHOTOMY D4 (retired-module resurrection): {stem} completed the "
|
||||
f"strangler exit (parity + CI green + deployed) and its Python was "
|
||||
f"deleted — but src/rune/{stem}.py exists again. The dichotomy is a "
|
||||
f"SINGULAR codebase: do not resurrect retired Python; extend the "
|
||||
f"kernel in its Go/Rust home instead. (See store/rebase/retired_modules.json.)"
|
||||
)
|
||||
|
||||
return None
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"BLE001": 47,
|
||||
"S110": 31
|
||||
"BLE001": 345,
|
||||
"S110": 75
|
||||
}
|
||||
@@ -1,50 +1,4 @@
|
||||
[
|
||||
{
|
||||
"name": "gamma",
|
||||
"description": "",
|
||||
"capabilities": [
|
||||
"cap.a"
|
||||
],
|
||||
"file": "",
|
||||
"full_path": "",
|
||||
"priority": 10,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"searchable_text": "gamma cap.a "
|
||||
},
|
||||
{
|
||||
"name": "alpha",
|
||||
"description": "",
|
||||
"capabilities": [
|
||||
"cap.a"
|
||||
],
|
||||
"file": "",
|
||||
"full_path": "",
|
||||
"priority": 50,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"searchable_text": "alpha cap.a "
|
||||
},
|
||||
{
|
||||
"name": "delta",
|
||||
"description": "",
|
||||
"capabilities": [],
|
||||
"file": "",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"auto_invoked": true,
|
||||
"hooks": [
|
||||
"pre-turn",
|
||||
"post-turn"
|
||||
],
|
||||
"searchable_text": "delta "
|
||||
},
|
||||
{
|
||||
"name": "read_file",
|
||||
"description": "Read a file with optional windowed viewing (offset/limit). Returns numbered lines. Use offset/limit for large files (100 lines at a time).",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"neurons": {},
|
||||
"divides": [],
|
||||
"sessions": {}
|
||||
"divides": []
|
||||
}
|
||||
@@ -38908,693 +38908,3 @@
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1a5dfcdba732", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2c8835ea9e171751c593b4cf87e8ffc1e70f49d763e6c932fc3a71b1131eab3e", "schema_version": 1, "timestamp": "2026-10-05T06:51:33.855682+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4c212c766420", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:816ee2ac1945082edb3e0cdc512856f4edcef61a860330f1aff91a70b896774f", "schema_version": 1, "timestamp": "2026-10-05T06:51:33.917103+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_98a1c9d79a80", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9c5bfcbe3d47d3783802c2dc21af1c34137bfca61aa7bd58266286ef74d41d86", "schema_version": 1, "timestamp": "2026-10-05T06:51:33.925785+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c8e85d0698b4", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T17:02:23.221494+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cf3f860608e2", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-07T17:02:23.238428+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_20e872e5d88c", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T17:02:23.254772+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_31eee4ea1417", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-07T17:02:23.275500+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_70303f4e353b", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-07T17:02:23.288599+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2165871a8b07", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T21:50:07.517414+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cd109af4691b", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-07T21:50:07.534419+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_92db59eca81d", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T21:50:07.550997+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_266636a3f208", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-07T21:50:07.572059+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_621d25107c36", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-07T21:50:07.582493+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8abe191f526d", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T21:52:49.494282+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8e9c8657d9ca", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-07T21:52:49.512258+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ff64b87cfc4f", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T21:52:49.529784+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9ad7c6b0ffa1", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-07T21:52:49.550840+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_008220fb67be", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-07T21:52:49.561702+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8fda0ad53b8a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:86c111b4e84a4d2cd53053117e68d6ea6ece238be5852b57310ad8043c3678fe", "schema_version": 1, "timestamp": "2026-10-07T21:54:35.633584+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9a444e3742a5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c1314e061f8b45790ad9d1ab57725bea6102ef8f99df0aa4009a3ad3a633ba23", "schema_version": 1, "timestamp": "2026-10-07T21:54:35.922904+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f077c4970c0a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d47099e2276311717957b8555ec490b8e24c81afbe3a0af57df48f7c489b97e1", "schema_version": 1, "timestamp": "2026-10-07T21:54:36.158316+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4e691406a9f4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9dcd09a28b2a84095074f1e400c48afb4c60c395f31f64f7083fe7b48843578e", "schema_version": 1, "timestamp": "2026-10-07T21:54:36.389771+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_74cf996e8626", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:70f5bb192f976b1d574d9d665e5ab1c08d01d2ff07f9222c671fcde6fa80076d", "schema_version": 1, "timestamp": "2026-10-07T21:54:36.668016+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ba3210994538", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f0c0bcfdf622040702fbb8fafb0639a0ab887e226477714d2de1abd6116dbd18", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.007430+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f58d440f9523", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:160e1e7b7903ace345f375caa4c39b3d0c3c01c7488c193463fdcaab97becebb", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.080182+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_518469127956", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6159a5caac34eb700f5cc353d0cd438f897ba5828acbca719947267032ce4e3e", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.091957+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_91c78904be72", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:19e97f778c2c590ec3c4e61581888ef6c7d26807faf34dddc9ec064af4a8b364", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.103086+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3efdac75c191", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:80dbbd51d6694ca94b17f757afce85b3f3a75c06525922db67aa66988cfb2f64", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.114323+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2acd229248ff", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1d26224d2f9156e64521074d499f21892ff4f0ab66b2ceb3cc657b3c3a5c5e6c", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.125790+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3520daf4f20a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f8fbb67df162b0ebc76a806dcad2cef768487901f5727b4dc9efbf8850f81692", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.137218+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_20add6258b7c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d9048dec0aaad358962fc0103f6de37f12faadc515b2aab905a1c2b9964c349c", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.149181+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8ce54bd7cc43", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:74db06c11104f6848b20336cd1f57e2b9d1185b4b19011a52b617c898a0f6612", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.160339+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5131d5482573", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c3ed7b6a42f127d35aa54c56c230f0ba89a2bd70f855ddc7816761a75f1134d4", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.171496+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_17bc41b331f6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7a1fe6831533c581b3fcc88f0c7a9ca1073ada3fa0de401f3b7c0fca1c240265", "schema_version": 1, "timestamp": "2026-10-07T21:54:37.181736+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_038787afd6b6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5859f5cbfb83a8ca15b1de0ccde10f6b33b5205b3323db017098719d9444e68e", "schema_version": 1, "timestamp": "2026-10-07T21:54:40.340757+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_31c8b408654d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:99706195e67294b38b84165c7d2f05b871432595f730ea1c92ae501e5f4bbe0b", "schema_version": 1, "timestamp": "2026-10-07T21:54:43.123577+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0abfb881aab6", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:055ead8fdd5d6e6b96c7222fc89d8b11480ed0158cb2a6a695b8e618799b726c", "schema_version": 1, "timestamp": "2026-10-07T21:54:43.138595+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e7d9a028ef7b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bfe6ce2169b1d32fda80aa9f3c2d8231753de38aeb6db568046e99e3ca24f5e6", "schema_version": 1, "timestamp": "2026-10-07T21:54:43.255289+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e51e65240183", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fd27ceecc0bf371f211b3b750a7dc90cd3c7fe66b64876f8ab0d2ba1800bdbf5", "schema_version": 1, "timestamp": "2026-10-07T21:54:43.264315+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6f617894976d", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-07T21:54:43.279799+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ad4b241df497", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:15ce52ca23b051549e713c3065ec650cd8e56ed623307db04dc4c79cfa297d24", "schema_version": 1, "timestamp": "2026-10-07T21:54:43.520823+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_76d014fb4723", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6460fcb01c64997884bf56435882c0913d37a59155aba0413724adb293b3de93", "schema_version": 1, "timestamp": "2026-10-07T21:54:43.532406+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_311f041098cb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:49e19e8a06214618573fb93f033b3c984fec0d7b524a14afd9d9185cb587833e", "schema_version": 1, "timestamp": "2026-10-07T21:54:43.542925+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_172c408df1f2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:36c2cd86b23b747d49e38fb07b350b3921e9217c625014c36aecbc49bd1ba634", "schema_version": 1, "timestamp": "2026-10-07T21:54:55.871600+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_561cdc1d2714", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fb61b5d354ad7efa7424b7d454e0645207fdb3ce26c61b57f2cb524f3db8eaaa", "schema_version": 1, "timestamp": "2026-10-07T21:54:55.893092+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5f3ffbb95fc6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:163904c8d0a60befb0e75d925107ce2c5dc0c3248b81ecff1f92b00f888c674b", "schema_version": 1, "timestamp": "2026-10-07T21:54:55.907712+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d2054596430d", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-07T21:54:55.945885+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c7d89f01eecb", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-07T21:54:56.005218+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e79cb7307883", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.291436+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7a1c64ef3ec9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:291d83c344a975dcac7368ae65020e769394497f12444d794b2a5d266d330f8d", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.314030+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8d4cc8e2d6d4", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d0d6601a3c699fdc5ae3754f55b0b7a292dd99cc28f9564f5ba6ed6c209f4383", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.321780+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1832f77429b4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a000144ca447a5cb9a165be5efb54e5163cf0d7b36653acf6bea6668e81eb3e3", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.333591+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_70ef1d086fdc", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7b609de024c032a68331d6aa876b7ced48567cd6946f70160d6d7a9a4a282f35", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.341279+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2f7989b6a3c0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9758915b9e9b356c139ff2eb6d6bd5bcec7fc4194af38c0ef4a2da72bca5cef6", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.351195+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dcb8debe856c", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:94352f12a2cf6a07742505fdd023e9533cb9087d0a406ec0e022a599c938d681", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.359496+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_807527575da3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:533639a993f88073354da7477dda3fda5bb563f8abc2bbf230548a3074c067b1", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.480541+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6b54ebdb6f99", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:49334c81c8dc884d75bc19511494cfb2df0cd9f9cbf869cb447d07b1c756f65a", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.489218+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ac3b213b03ca", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:214035183dc49e193f5ca2fe20f7d6ef9d4d83da65a67a85ffbf4f0756c26886", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.502051+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_109983e60e8c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b006dbadb3da487309b7699f19e6d0cc04a841dae7af3d1b501f7b15fe55acef", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.521588+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9469395e2260", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.535995+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_969c52948f42", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.546806+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7623a08c56a2", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.643481+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0a6e823d8f00", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.653500+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7bbd58381d0f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f5e417595a66417fa2f8fd21a5975dc3dddbcb0e27b5099f9de9016b21857eb6", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.662356+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_004b8887c9a7", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.730639+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ba998a84f466", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.740287+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_100a6c30abab", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0009b5794617101403d4490657f7130ffed0a12648501859ebf3b55155e35a4d", "schema_version": 1, "timestamp": "2026-10-07T21:55:00.748376+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_07f99d8cf12c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f4b702e0727d956b5d3b3e89fca189845fa033f126772ffab3c7c3e402c1d3e4", "schema_version": 1, "timestamp": "2026-10-07T21:56:45.370429+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_61b9647ed1f4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:193d4b90669073b664160e6ef77338de8d00ddfddf32d335a163d23784efe202", "schema_version": 1, "timestamp": "2026-10-07T21:56:45.383394+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d9c8a6e61eb7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4a3161ed9433efd927227a1d36e561d6c255adc04c1bc7b12ab8d4c89acc3870", "schema_version": 1, "timestamp": "2026-10-07T21:56:45.394390+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6041f1a608c0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e0d1c0cd1dcdb2135a2543b18fbf94a347ef72075951d2727054729517554e0d", "schema_version": 1, "timestamp": "2026-10-07T21:56:45.406795+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e2d57625ce73", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3bdddc9bc7970cf5a34a7d64d61aaa095988ebcf13f059f265c6a1224e081bf3", "schema_version": 1, "timestamp": "2026-10-07T21:56:45.421723+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0112550daa59", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:991957beacbba20e0e7f1e7de6534920bbd6ebbd69798d73d653ea69174dc995", "schema_version": 1, "timestamp": "2026-10-07T21:56:47.629724+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5643a339bf49", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:17f7f276f6f207c14c9d054e79d7d6b5fc6d9cb7f8d201895cc64464c51babd5", "schema_version": 1, "timestamp": "2026-10-07T21:56:47.643002+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b41972988dd5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f3950fbb2b8f9c8ce424cfcb0395c026be946e63811aff8b5102fff31e5ff0d1", "schema_version": 1, "timestamp": "2026-10-07T21:56:49.336108+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9441efd0f48d", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:67b382d1dbad09ce9557e782bff2a3ed2286c2d9afccaca343584de34346f399", "schema_version": 1, "timestamp": "2026-10-07T21:56:49.351088+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_924e1d1680a9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:be90266c3c0090c074cbc5797328c34f1a2b9553ec0504daf2e50df64850d44c", "schema_version": 1, "timestamp": "2026-10-07T21:56:49.465406+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9906fd7d0158", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3923e6976994168e8f8ee6996c2b256eff9e9dd93c7bd4116c4048961fc7d1d3", "schema_version": 1, "timestamp": "2026-10-07T21:56:49.474428+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_304f85e3cdc0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d5c9a9e56351a239202cce6efbbeed93c56687495fc40e480cca282107206b89", "schema_version": 1, "timestamp": "2026-10-07T21:56:49.535974+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0b9a54fe9b5f", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:873bb514a689011de1c18c5a50dd8dec135a08f873943192aefa3326b03cb923", "schema_version": 1, "timestamp": "2026-10-07T21:56:49.544067+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_71ae3bcb5afe", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fbaa16a9a95ae0a0356ae6d8124b2ad9c713d900b7e8e01464256d0f39faa545", "schema_version": 1, "timestamp": "2026-10-07T22:20:32.087228+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_db8a9e69bbb6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4fec0fe2480cd11b4ad74762053e17d9ae40cf15976a4e890a7a10ec33b9d431", "schema_version": 1, "timestamp": "2026-10-07T22:20:32.105185+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3eeb60274fa8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8fdf3e691a8ad0148d6dfc4928dd1dc91eba769460f30bbfa96d743bb9f62d08", "schema_version": 1, "timestamp": "2026-10-07T22:20:32.115792+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7d9c5fd81855", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9624934e34f2b4c1f2bd04a937708c26c7d1e141d11f73bb87925fbcb7d96234", "schema_version": 1, "timestamp": "2026-10-07T22:20:32.128062+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2c339582fc84", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ea9d159086d6530eeb1f5564ca7dacfb14f9a1de0b37cae0c8cd646ae60110db", "schema_version": 1, "timestamp": "2026-10-07T22:20:32.140563+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fd4b423b93ea", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dde976f0dc596548a11ce6580cef0ae85d951721ca72e1085cd4790fccc457bf", "schema_version": 1, "timestamp": "2026-10-07T22:20:35.830245+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3aa0f00648ad", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:86c6a2deaef20fcacaed65a2cf5819f4df6efc6189b048ad9396ef06113252df", "schema_version": 1, "timestamp": "2026-10-07T22:20:35.840584+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7e60c74e9a71", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ea5b48eb3688d78e872d8ff9889ab87a1ed267be428de3e3c347ebbffb4f2d35", "schema_version": 1, "timestamp": "2026-10-07T22:22:39.869985+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7168b32b63f7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1864f4eda9b04ed4864e0b2602e46f106e710586351ba96ee49de2ec6a15f224", "schema_version": 1, "timestamp": "2026-10-07T22:22:39.887267+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d5609923ad25", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1b945f5af71f01dfe2b92dde6046c725aeabafe23c72f133cc7e2009989b7ab4", "schema_version": 1, "timestamp": "2026-10-07T22:22:39.896953+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1faa2e769935", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:893b877c5ada88507b82856f69b03c30121eb686462ee160f77e8e382011102c", "schema_version": 1, "timestamp": "2026-10-07T22:22:39.908215+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d7399bf0c8e1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3fd3c196fc01e4deda58e7ded02c81b3e5e2047430ce65d0863a88b574fe5911", "schema_version": 1, "timestamp": "2026-10-07T22:22:39.920363+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ed86d0356416", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:076419d4037c1e00100ac388a0623970aba2be42df1adf65a6aac4583f3635ee", "schema_version": 1, "timestamp": "2026-10-07T22:22:43.542215+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bcaa55fa8f2d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2202a350fd9e9a4c28ee434d531529f31433fa871dc811b2b0aefcd682300d64", "schema_version": 1, "timestamp": "2026-10-07T22:22:43.552850+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_18223264de8c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7c9c6f155c1d4f26ea34338d2bb839e8838aead3a07447abe6ba10dfa2f3144c", "schema_version": 1, "timestamp": "2026-10-07T22:22:44.066146+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f1717c87c950", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:15ede50eeec32998bb8e63d48d41290b4d34c51c8dd9cdea6d827bdf143be401", "schema_version": 1, "timestamp": "2026-10-07T22:22:47.664673+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b8714893aab0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:161a6778e3784c3602c2e1ec9b287e47fbcad63bc434524e5790937aca517fdc", "schema_version": 1, "timestamp": "2026-10-07T22:22:47.676567+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d9b077929361", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:703cb05964d7f6f87b03e78c30da3fb17574409741f2b5929e1e15f2e5b2de0b", "schema_version": 1, "timestamp": "2026-10-07T22:25:18.354557+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a69e1cc57ce5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:496c211534953f77b180b67736bc0a11e9eb0484c2008de3dfd63276bf798ef8", "schema_version": 1, "timestamp": "2026-10-07T22:25:18.365743+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_769513566296", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6577d10c3009e4f266f62dfffa0d7d0b6fc1d9545f1defcf16ef7afd10b737b5", "schema_version": 1, "timestamp": "2026-10-07T22:25:18.376855+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3eaddcd22e89", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9298f998be01be2aff7c41877b8f3ef1ccf878e5ba74a1f252f8e76517b88bdd", "schema_version": 1, "timestamp": "2026-10-07T22:25:18.389138+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c031346bd409", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fb231da817c2f09c1ca791f5b52ff941c50f42dc63d3c9b3755862d5af684475", "schema_version": 1, "timestamp": "2026-10-07T22:25:18.404139+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ac291bfc7695", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:94eb4a5173c77171ea49e8f4e179260aa3acf975786d4ddfeca53b2b4ed6f728", "schema_version": 1, "timestamp": "2026-10-07T22:25:22.083341+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_22f358b7baed", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0a5ef40289ddc8707755a1d2a1454ca2c2127e63a33c17222b3c067d6ef1ebb8", "schema_version": 1, "timestamp": "2026-10-07T22:25:22.093948+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_466040bc7b12", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:26:04.366655+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f16ae179319b", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-07T22:26:04.384262+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3f68a3251bb1", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:26:04.401229+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e912dbafc49c", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-07T22:26:04.426178+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0b9dc7b0bdd1", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-07T22:26:04.438978+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4ddb2b9a011c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:53039ee9e14800635176e48adb1afaf0a991b86066eb1873ec5d784cf7dcc982", "schema_version": 1, "timestamp": "2026-10-07T22:27:50.460579+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4eff45396d22", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d9e97ef858ec451e37736c5945491980f8f14cb928a444c3be49921707e79958", "schema_version": 1, "timestamp": "2026-10-07T22:27:50.768630+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_347a021e5680", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3882e9dd4d6e7b7f2e8ee9581bff15e1e2bda55c408ec87ade3e10b579518f57", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.042134+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_945e2a9429ad", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cebb7f4b48ad50498d02895bd3436fdc7a08814111cd0491df9cb92672414cb3", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.262783+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f3ad36e41d40", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7af48941e0becd49fd5a268bb817ec34df2db3e7f6ab5fe89874ca6e1a799e1b", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.523859+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_02daed1f56d1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:28440d78a26289c8b8eb1d97027f6024d786cf640de49a9d04245fbc70176366", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.835770+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fd371fd04157", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6c08d7231d412fbb06a93b33f9d73721d594d131114ac1a182023b0f490482d7", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.905319+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bdde08d1afe5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2180cc26c661677aab7f6ecae2ed4131a2935a95a97b33a3765e79c319fafa2c", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.916834+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_54b0213feb38", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:90c1d7fab9f3b44afbd4cf7bac9eb0aa82392443ca2801a46b424181784709c8", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.928322+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_016c3b06955d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:69d30142ba27b0d79e323b77e3471bafc5474317e834a8b73cf208f39bb60737", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.939976+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a00d001acbf6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c3d03ef67bc717442db26fe8ef780ae7048c95d939395aa99df9b2b5bcc4ded1", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.951611+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_333a2024d201", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:93bdc4f34ae18b2263911a41edede9dd1a7e4afe675e354d5048d30cfdb8febf", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.962750+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_517a57445947", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2f8f8aeb6f885f72cca2aece824a6f7badc84137d829c49943f55d942a8c844a", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.975061+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c17e195b82be", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:50300c9bb904a624a5483cfe7a7948a9d73c63881072a5d7b6f3bf69b941e99e", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.986588+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_daae4591f27d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:593e8044adb278d43006880f1f9a8f4136e976481e9cc328d123b7a8674d4427", "schema_version": 1, "timestamp": "2026-10-07T22:27:51.997757+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7018fc048d78", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:646f29911138e3756a8ea1aacdb9552fc4adf66d1e08c78bf401d1b66045578c", "schema_version": 1, "timestamp": "2026-10-07T22:27:52.008082+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b7c94654bac0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:521a2a4ad30ce969312148e8e7bea2eef379c060a43d219b4913c8c7a2cdaf4d", "schema_version": 1, "timestamp": "2026-10-07T22:27:55.062575+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_84c0bad29087", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:54e05e12a5cb4d558be3b3439ddd9342aaa9729b12b11f1a16fdb5b043c28cd5", "schema_version": 1, "timestamp": "2026-10-07T22:27:57.811750+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c0f387aab382", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cf673b7759cd5ef4461c45bd67aa361d3969986a6c6e74259cc06379ff30f184", "schema_version": 1, "timestamp": "2026-10-07T22:27:57.827145+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4995dae96df3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:894b4ae5c39870b96a533ae8f1cad88063e76b369c716221154fdde96140ef5d", "schema_version": 1, "timestamp": "2026-10-07T22:27:57.931017+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_41f6e7a8542c", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5a2dcb1e7f95ecb34378431373ffb71ca6b35d27d0a3e9734d9475baba830714", "schema_version": 1, "timestamp": "2026-10-07T22:27:57.939823+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6be8b5a6d85e", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-07T22:27:57.955005+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_badf3c2541fc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9ddc77ced5533b7e1ff3b0513367e2e8de1bc9c9f32d5619f3ab7ab17f9b9d74", "schema_version": 1, "timestamp": "2026-10-07T22:27:58.191580+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8648ba620054", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cb9d27ea0602f5d35c8e5c3ff2f29b94962c1d3fc734f4fb6f15f3d7841b2efc", "schema_version": 1, "timestamp": "2026-10-07T22:27:58.202982+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_593b37a166c6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c7d0b578a1783f6f5cd927be3fc0d6919b0f4623238f283b9b5b5e36365d80a3", "schema_version": 1, "timestamp": "2026-10-07T22:27:58.212638+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_09e37925baec", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ce3fded0390ea22878714082393cb915d93bb27ce49a7c12bd7a0116982ef317", "schema_version": 1, "timestamp": "2026-10-07T22:28:06.712550+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8a04a62526ef", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e9f467ed0f40e7668cd30fa435ded14f8fd7b85aeff4b92357b8b1e7a462897d", "schema_version": 1, "timestamp": "2026-10-07T22:28:06.733812+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_94a7aef23dc9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1a3e23951b8caa21ded35f7da04978ded7a9b5d07650a3bf545acb3f077afbab", "schema_version": 1, "timestamp": "2026-10-07T22:28:06.747945+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_88e654452f71", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-07T22:28:06.787243+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5b07a37a3124", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-07T22:28:06.847059+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_63922ac861bd", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.052050+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5de4827e120d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cb6f7593cf00f29a9d693a0dadc0541dd52099927e4f9b60e024c70a4d49122d", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.074045+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_235d801770bc", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:acb4a307a8ba3c60a39d30b46d860b2dbaafe81dee24cb141f5d996c46fc8802", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.081764+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f20705037a76", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5c7d67629684b300301b6b43f6b4b6f92625724db292a9c1a83179cbe187d73f", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.093967+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_386609987d79", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4f489bbd159fae5dd9b7f2a6c13cc8329b9ef723ee4d295d52bd239d103cc0be", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.101694+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aecbfb7cbeae", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:37fe03f26629d70494a484c33a695dfd9eef7f713fc5c17e89a197133267d478", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.111271+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_87235f78f321", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:06e4e2f0e573c7c15d411300f1ed96513c873598ce68caaf0e1d824fc525a344", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.118957+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a4ed37b042c2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4013a3e76d6a2248aa5f1a4f2565aa1b8588399800563cbaf33f3a58f27768ba", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.234139+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_23ece372117d", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8f4e6edce6daa4a868f53ce971e3db3134a37d5e8451e98a65d5a2deb2b79d5a", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.242681+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0e31830aacd3", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:17a520c1df12bef0eecc760c9c02bdffa670e78df252b27426565e0e40cd023a", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.254758+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e89ada6e28d3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:285655ba9da5bd7e4e7a74cd5b5a72b120960ab28810aaf115aaef212526a5ad", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.273479+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f922cc2835f1", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.287814+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_070f935d8e43", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.297841+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_36b71c376190", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.390537+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c08b83e0192b", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.401995+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_94c0a537080d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:169617d1c445541ce519fc7b19737ca3ad53e18a37760bebae1e034a0364184d", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.412025+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_122a4a31eb43", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.482460+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e0807701ed52", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.492041+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0299cf8b7757", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dba1a138f96ce998897c20cff476601f0a0610fb3319a563aa7903b01f3b9437", "schema_version": 1, "timestamp": "2026-10-07T22:28:11.500217+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0b62129e7930", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:342b9bed2ffe53803c953380ecc7018560cc717a3f2a486a8008bacdede1c020", "schema_version": 1, "timestamp": "2026-10-07T22:29:56.053266+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_02a05cdfedbb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7da89c61cc516003948a51832e70c1209939746e8c7892316de10b08a9b13a76", "schema_version": 1, "timestamp": "2026-10-07T22:29:56.073204+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_acb9596822d6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:76a48df0f8d5f0527096e685a3f5c057c63c3fcf8c62f504172ddb05e3e7d113", "schema_version": 1, "timestamp": "2026-10-07T22:29:56.084338+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0aa9d3143716", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dd6ad048b15a824322e17954e549f370d20af8852477a38f934ddb33b3cb4635", "schema_version": 1, "timestamp": "2026-10-07T22:29:56.096440+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b50d9e432b03", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cfa50d2bc4d5e9c0a9620d73ca00758cfbf93b0f0082f56f2cb032dbedc07826", "schema_version": 1, "timestamp": "2026-10-07T22:29:56.112054+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f506bad3566a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fbcfde1cc10e7e5fedf1fb55998d990614d18f3f362ee12bc27ef4560cc31706", "schema_version": 1, "timestamp": "2026-10-07T22:29:58.312635+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6c0fd57a2c24", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4d71dea606d4ed092e0fc719f6990b5fccb72883536b00987cd53ada3856058e", "schema_version": 1, "timestamp": "2026-10-07T22:29:58.324921+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_23d08534f7f3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:23d6c79f1f34bea42c67d598ed494aada116a19990fdea88558a0ff0e8824b14", "schema_version": 1, "timestamp": "2026-10-07T22:30:00.006375+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00e13cbd7c5c", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6dfa16e1e0fc7473afde32abbd2f4a55e4e9b217824b758802cd3424b7af8ac7", "schema_version": 1, "timestamp": "2026-10-07T22:30:00.021291+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a278b60cfc19", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5ab295a8bafa37e567555b396736f42a591c1eac670db8fc50be0f96403a17d3", "schema_version": 1, "timestamp": "2026-10-07T22:30:00.140194+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8ca8f89a454e", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f27eef3033f9a1ee1077439768a4ddee7850e56837456adbbf0791d09693a174", "schema_version": 1, "timestamp": "2026-10-07T22:30:00.149090+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_18b222818a33", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:201f82ca02f6e8b8ba474292961eb10dd16ad4097ed0792ec8ad43fe4aaa516e", "schema_version": 1, "timestamp": "2026-10-07T22:30:00.207095+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_07cda33611b8", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3f2cc47d39804d0fc44bdc29c0f50c5894d8d6819e5f87abe6e9df6245e14cde", "schema_version": 1, "timestamp": "2026-10-07T22:30:00.215186+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7113143c225c", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:30:44.509822+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_21a21368c2bd", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-07T22:30:44.527144+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c71f7a0cb0a4", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:30:44.542974+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fe6a046d54d6", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-07T22:30:44.564284+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5a9183f07297", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-07T22:30:44.575697+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4f45a3735f9d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4bc0a9e8b5dfdae8a1bc74dcec31f3a59e107b2e2406ae309d244095f8ae17c2", "schema_version": 1, "timestamp": "2026-10-07T22:32:30.438339+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8b558e52f340", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c0509ea2634fb322a3cf77474f79f6802f238e6090dccb407d8572d61f8ecadf", "schema_version": 1, "timestamp": "2026-10-07T22:32:30.722914+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9cbf09a72de7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5ce21808afb7f89ce55bbcbc836290b10cf20876f547e58884028c35566f3e99", "schema_version": 1, "timestamp": "2026-10-07T22:32:30.956538+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_055f9d78efd9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5866a07b0bf58267dd3b3918477256ad360e78bb9cc39c2713f0cc6eb4d1dddf", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.173494+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_28bb2b1b0d0b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:48cda753f360615452fa6291471e4bf038a57b9d5b728bd757f7aeff9a37b1cf", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.438394+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f6d4bf355b3d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:29b6baef05485d5f39c1c45110db7b9faa0e018ba210e1603a7b8ee87d2509e6", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.755779+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c40bb8bd861e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:72e045cd528a5ebd4e3401b4c4f27ac515db98ed14a79cdd65c7f2516a083129", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.826676+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ef399b42fdb7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:20090925bec7222b527218a35d17b6f9f4179696080f56da910b342a3ef83cb1", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.838752+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d9afa85e4774", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d58f6f73e020b82d43b650d87da9efaecb5a21e44e6e5ef9ad45aa391dd70ce6", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.850118+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ba513b5dd920", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bdfeeb2a23b9c4daa378576229cd66ead278ad8e3be8379bfd4e2776bf1fc8fe", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.861614+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_56b94fb383e1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:40c445b2ad14d03e85d98d7ac4d496874e984278a101f681358385c1803fe5de", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.872931+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_74244e9d660c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ba915ad224a36d6d18e5b3ab9fe0bd7f9842634499aa475819c5f3d1e3afff41", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.883826+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fb3081fb8ae8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c7563789a5fc5b778ce29b32b4ab4fb34baffcc7044788790fbf0bc7e77d71e9", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.895001+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a16084fd974e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:52fd8f2b0a24cb40b20a7a2e133b1dcd54a93b9b7030e618b8d2f53a8f38de05", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.906464+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7bc53e268459", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:77e5e2ad1317b8a699434dfde9bb4ea3e7b3051dd7ed99aebcf12f21eff0af78", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.918417+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_68b87adc22cb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3574c881c6b7b371cfbf317bc46d08a1556859728ccf01e9d4a1770b08a6f2df", "schema_version": 1, "timestamp": "2026-10-07T22:32:31.928542+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8b7218d5e1b7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:75ca0f911a07c723c071e7cbdfb4ef9e1be34873127dd81bb5c40aeadc543ff2", "schema_version": 1, "timestamp": "2026-10-07T22:32:34.961936+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_77f9b0041998", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8a50e575280719de5599ab13c0a250834186fa1bac823c192bc072a4e19bc389", "schema_version": 1, "timestamp": "2026-10-07T22:32:37.715244+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ad21db440352", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ca68700e774000713a6b6b9273a0a3b9c3c0abc0bbc8cd7e00d49061c67ef0fd", "schema_version": 1, "timestamp": "2026-10-07T22:32:37.730677+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7cef74e540fc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9bb54d1c192d6a490ef1045ea3fc21698fa28f62a99d57416322c4ef27c3611a", "schema_version": 1, "timestamp": "2026-10-07T22:32:37.834971+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8ea3c7bbb758", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:21db6d14a45fa888e48eb6f28bcf7443baa8d197c6767129cbdec1655a1cfc81", "schema_version": 1, "timestamp": "2026-10-07T22:32:37.844144+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fc41869cc112", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-07T22:32:37.859630+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a73566b5cc22", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:519aaae63463d8fc83db85491ada75638fc9a54bc5b332bed66143a821e98c7f", "schema_version": 1, "timestamp": "2026-10-07T22:32:38.099255+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_196af426532c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:174ca3e78e7e7ddce80db727d08264601cd77e947fd6015834b0de593629a486", "schema_version": 1, "timestamp": "2026-10-07T22:32:38.111637+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ff2e91c88e36", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4c57a2d33e5c5939adda35e6143641b1f12cb5064bcc2b5ab8b10b6fea1f8edd", "schema_version": 1, "timestamp": "2026-10-07T22:32:38.121091+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a79c7f8e5386", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:05e16b5eaf7d52536bea50b38cca11b2ff729c80883457965e43232ad404d30e", "schema_version": 1, "timestamp": "2026-10-07T22:32:46.850311+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_37cf9c5c5e30", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:72c7e2386d16d4e1f2411150e1ea8554d9099a8174201c3c3dd68faf8edcf9c6", "schema_version": 1, "timestamp": "2026-10-07T22:32:46.870866+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3ddd0a51f217", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b8d1f80bdb7448af9098334dd3362a9ebf45f4f5adfee1369a2bd5b3a24fa766", "schema_version": 1, "timestamp": "2026-10-07T22:32:46.884731+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1180e0937357", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-07T22:32:46.923045+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ecb4d7975b06", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-07T22:32:46.982396+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1d0e4ab9ca79", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.130763+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ca371470ce5d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dc2a4bbe6241b837fead91d6ec19a5d88d7e104f47a08ed156c1861ddb5b281d", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.152456+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f4d361011648", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:048732dd6ea8bcd3da42b476de33774bda08c3c0df7010a7c13bd509a8558564", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.160253+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e88acd31b941", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:374a91a1e542aec3874131075e9dedbf11ec36a72ec8330a53a6a0c55a90a039", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.172119+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_13c85c04240f", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9ac62cd99803a528b54632091b69b46c55af75f72348449c5c6bf45f74ad3767", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.179752+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1d3461554237", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e620684f9187b5885e5cde61e75eca229cc28e95f6104888c4abb421366e555c", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.189635+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ce763ab919de", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:715867432dda9e71fafcb02edbf8fa60bfb8dd63aff29f3620e631f6b22f0de4", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.197235+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9169b91034d2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a549f99bd3caaf250914d3aff76f2d7ecae829fdcad9836144251221546ebe32", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.312474+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_62a9b84545a6", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:652cbd50ce5ad88b27fbdde6f0d5ba7d15dee28711837c876eb6589c490402f7", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.321083+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_82171f6bece2", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6407ae1effad24df0d972fcf884058bb04098577b5c2ed9d878ee059013871b5", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.333758+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f236c1ecaf0a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0882ad54e81d4e3ea8bc8450e40a23d57015ab638a99a8498c0c9f92494ba57d", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.353261+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6a015fa96825", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.367749+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f117f713c0fb", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.377938+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0dea97528232", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.473570+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b4db13fef707", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.483604+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_26627ac92c3a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:49d76d7f76139679f44b60e7f7c210e451e9cc202db1720f8757b64f5cbb5dc7", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.492446+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_27f06ecd4ba0", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.563532+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f14163f29dee", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.574495+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6433b932ca33", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c2e6f048094de90089dd073749c1d730ae322139ab2500d1605811f9bc1eaa78", "schema_version": 1, "timestamp": "2026-10-07T22:32:51.583507+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5614355488cc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5370033ce7c50f2c378bed6d9f7e08541165a4695591f776a3e00446e364cff2", "schema_version": 1, "timestamp": "2026-10-07T22:34:36.022322+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_41b48213b5b1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8a23e1eb395793adb41178bde88db6b419eb133b45fb049a7bc635ca7724828d", "schema_version": 1, "timestamp": "2026-10-07T22:34:36.041323+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1b51123c3d6e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a8d212593986386cb953f72f1731ebff05326d999cdbff908616196fc2246c96", "schema_version": 1, "timestamp": "2026-10-07T22:34:36.052904+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3a2f8b76c3e2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:41636dd39d1482ce50433b3ef29d87c2ef4dc3fb0734b01030205167de130681", "schema_version": 1, "timestamp": "2026-10-07T22:34:36.065153+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_402339b53a2b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3fb42a252b1db9754f83e9d82368facf8c8dec2d8644ecd54d893c39e0c4cf60", "schema_version": 1, "timestamp": "2026-10-07T22:34:36.080417+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2b9282fd5210", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e40196c90e70d987c34d520a9c1f16ed4b5e210b608c9c5f9e6ab39e038d72ef", "schema_version": 1, "timestamp": "2026-10-07T22:34:38.710635+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b70d0fb5cb30", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7333ced05760e596f2b789724ee48e73d67e95e37eb4bbc19ca32b2f2847bcaa", "schema_version": 1, "timestamp": "2026-10-07T22:34:38.723484+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2c6987a9edb5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:11a79f618107654c9dd7d08b9829e824d0a3577e42034b50e73946996bf2cfa3", "schema_version": 1, "timestamp": "2026-10-07T22:34:40.395783+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1932cd7af704", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:785f200997e04967b4d6d035e9d3ce9b2c553c30a76b03e84bd871d94f7f1dd9", "schema_version": 1, "timestamp": "2026-10-07T22:34:40.410812+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c0c260d8ed6e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c83628cd7def66933ddba8b7cba837d5feb784ae9b32e16f0dce047d6926d4f8", "schema_version": 1, "timestamp": "2026-10-07T22:34:40.524053+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_01f633350729", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d69299a426b218345858d4a276758049be1ee5e8c3cec85d8fe13e4af974d2a1", "schema_version": 1, "timestamp": "2026-10-07T22:34:40.534409+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00671d9850b8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5bfaba09e131ae052d36eb3a701f04cd1cf899e7d47664b53cfde184ca22260c", "schema_version": 1, "timestamp": "2026-10-07T22:34:40.595968+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fb5100e2bb1e", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a34a682ee0a12028c091dfe49ccb463787aa7753fb841aa8375b1ef30b95d608", "schema_version": 1, "timestamp": "2026-10-07T22:34:40.604305+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cb6056b763d2", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-07T22:44:35.879233+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_eb2594e92409", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bc365da03b06d4d5ec64a3546394ca70b615c06fc5cdd79d5a1e4cdea600286", "schema_version": 1, "timestamp": "2026-10-07T22:44:35.904076+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6736d4f959bc", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:28b78fdbc4791d82646bb1f9485c72ba4df8533977b1bdca5a121fa4f618d8e2", "schema_version": 1, "timestamp": "2026-10-07T22:44:35.911748+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a1587b384576", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:03625eb8dbcb91c21ca7191c6ed756e44db53ce5529d4ec145c713f9b12ed35d", "schema_version": 1, "timestamp": "2026-10-07T22:44:35.922561+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7cee7eba4b44", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2348016199e675f0a9334a8e825d55eb5b5b3e6e2d9cb1c79ce9ada5b881c319", "schema_version": 1, "timestamp": "2026-10-07T22:44:35.930125+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8dae7233b159", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:29d03ba67e964e1775669e14a99ca01946641cf1abe0bbd91d4a61d88ae0377b", "schema_version": 1, "timestamp": "2026-10-07T22:44:35.939791+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7001b04e4ea8", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b0e954dbc72fc2a41f39c6a8be8db895a4fc0211fddfca8f33640bf487349e2a", "schema_version": 1, "timestamp": "2026-10-07T22:44:35.947315+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5253a3bed3f4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c1d836ee915b7af160e582ab5e125c0e1ab2bdab183722f18d407603d8aa976e", "schema_version": 1, "timestamp": "2026-10-07T22:44:36.102214+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d1e923e4017e", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4cedb64363029ef4dbf198e4a80dc1da8bf7b96cabf36009b95f2e71b6679951", "schema_version": 1, "timestamp": "2026-10-07T22:44:36.110638+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2b7407a147d4", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0c4e8e2ee51e45fb1068990e5b8b1fef5faf3cfd9fcdbebea366b48d1c2ca4d1", "schema_version": 1, "timestamp": "2026-10-07T22:44:36.122148+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0131f7906397", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e113e31bd891847a28fc3c8e0af93c0bcfbf09d90ec274e7993f3ae8d5c3a46f", "schema_version": 1, "timestamp": "2026-10-07T22:44:36.137835+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3f834138804d", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-07T22:44:36.162706+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f44e3ba6d0c9", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-07T22:44:36.175120+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7a9ec8c3d488", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.537945+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5eb88c33d230", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.580492+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_314351f68c25", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a099f852c8f568d053d18b446f40eb00bc97e373ef7eda5e167f3d55f386ecd5", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.592803+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_19fdc5bfb331", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9c9ee5be2042b5d246c07a2c78c973541d481c53ab0b9e7d708ea3d9f36f4529", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.600377+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_29aa925b4e81", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:36ba89ede882c8c5b4d2d8a11b39f10ad67104bab37c7ceb5774d5e0627717cc", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.610990+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d23026fe7caf", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ec0685d1a95795daf288b7271e6df08fd6f06ce83803e8f7f218c2bdb63be914", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.618480+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7ca3a7301515", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0e98c95692e2e0803b0a8500cd46017f3a4f3b4aa90ebb7da004590ddbd4eeb0", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.628174+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ab49abab2767", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:48d81d4657eb736a8486c86df941345c88caf96a0b89d1112e1c57bc8c94269a", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.635623+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a42f641fad47", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1ddf7f4207ce04c3392d1bbe6c1f5c317ed4ad1e3669ab2be2316a81e65b5273", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.787039+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_69a73a9f3b53", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6d7f1066d4cbf0f4983a3719d7500a059743a65622179b6c528d5fe8dc5161d4", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.795572+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c74335ea4249", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1855f5c2a280a88bc6fba739ab751ddae611639e2ccaa5c53aadf1245e719fdd", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.806620+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4a6d30fbf41b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:41e79779d07466babbd6880e028723d26da47a1c3213819136286b70f25e82d7", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.823666+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0db575ca3b78", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.839574+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_da7eb07c587e", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T02:40:19.850405+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e3fdaf73e870", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:41:21.938001+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_56c4911777b0", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-08T09:41:21.949627+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0c04f0e1bfa6", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:41:21.964972+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_80aa6aa1fe16", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-08T09:41:21.983256+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ffbde39ede44", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-08T09:41:21.992979+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_437182b5a36e", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:43:11.773160+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7225b89e81b7", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-08T09:43:11.789784+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0acec5f0aecb", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:43:11.805512+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e844fa17747c", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-08T09:43:11.825843+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fefcf81d4bf7", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-08T09:43:11.836476+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a82c8a06e2fe", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4d9c1c90f13291d3624d97e3fef03cee090d4e49e3c9577dd16adf6d499090ae", "schema_version": 1, "timestamp": "2026-10-08T09:44:57.727482+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_751b46d3b73c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:84fe6f4ec84fe74021563781ba0e2d8d76daa908f2ce615ce1adcd34133f4ec3", "schema_version": 1, "timestamp": "2026-10-08T09:44:58.003567+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_598e1dd1dcd5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8a2765cdca6f617d9fdc1aff09f3fb720fae4b12cc89fa37fcab0cbc4a180dbe", "schema_version": 1, "timestamp": "2026-10-08T09:44:58.232406+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_681990635794", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:14ee11eae037ec11fec88169202831a3b855a24bfb81d79e5854652190e525fd", "schema_version": 1, "timestamp": "2026-10-08T09:44:58.443955+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_223757a774df", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3966607683aeff2b0e2741cf7e34733a3875a1a57e47f10a9d31398aa0c2c6f3", "schema_version": 1, "timestamp": "2026-10-08T09:44:58.701014+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cecda9d8f38e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6db44a4dedf5cd187b3745eeac504e73ffe8f07e07cd2df363f7f51a05d1a2d7", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.007265+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_893c8943f3e8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d10cc6faf3d02664225a6f0eed1a6a659f8ec245fa5e7312886c55da0d266b8e", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.075999+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fbc6f46b8602", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3206a9201364ede6c4d21aed865fd5a7bad3708fbd6dc014f0a2337585e2f06c", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.087194+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b5de8d54cf65", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d48593a716fdfa4fb0e92371d4c2d58ea86b15722d39aa63ddd1f41077b29420", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.098012+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ac8a7192f33a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d98026628a14504dc0b93885e1a399e5916fa898c32cb8fbc1a03c77dd40e9ef", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.108703+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_609b9ac8c0b5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:884ee87fa47285be18b7ab297f1fc35ce4ee2ac19e10a50df36635502095e077", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.119525+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bbe8b5eff605", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6f3143d6c8c66f28ac951ab757d0c6e913c8d3c9486d4eeb596f186945627db1", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.130017+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ff55b8af1530", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ee089a90998dace68230d81bccbb8952e29e8f8318a51a9e68209485d74c8aa2", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.141067+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ac89fcf3d21d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0093cc57f799515dc5c493a930fd62265fc9b0dc2c8f8e8447a50991dbebf0f8", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.153255+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e2ad802c61f5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ca6929201fbbf3af3c363f5cc09184754b3eb644a2f97afae3b48dd7c46f7177", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.165551+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_186c2bea657d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:03d62b59672566297caedad0875056eb40527b6fe9be5131c4cda17bfb65868b", "schema_version": 1, "timestamp": "2026-10-08T09:44:59.175637+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ec12ec5f6d50", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a42731cacd3d7ebb588fb26b611c9e94f3ee9636766932784a4138385567d0c5", "schema_version": 1, "timestamp": "2026-10-08T09:45:05.737171+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_68bb3434ba57", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:654581179dfec835024c7ab4ce6f1e69abc90423ce3d0e5f4f97cdac76b04b2a", "schema_version": 1, "timestamp": "2026-10-08T09:45:08.501627+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7896c48cc3f6", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0d08a7b7612e19a39132f9933a2cb92c585a2a1c6f1da19ba7dc1d7e7937a32c", "schema_version": 1, "timestamp": "2026-10-08T09:45:08.516519+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_260ad9ddc4b4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f28af5f04a0c73142cd700904be639e7a14a89d6cbdb0cca406be301c14bff75", "schema_version": 1, "timestamp": "2026-10-08T09:45:08.627724+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_87f6760a80a8", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:977abf28cc29eead5d52b63888114b51d7132eadc2a2c277b6ae5b4e78fafc3a", "schema_version": 1, "timestamp": "2026-10-08T09:45:08.636825+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bfec000cbdf8", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-08T09:45:08.651128+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7d552f469959", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2e42bb44dfca2020bfa055708eac41886001eb90adbf558bb72b3ebbb3f2358b", "schema_version": 1, "timestamp": "2026-10-08T09:45:08.881787+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_27019646a1ad", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4b68954f28fdc211918d566404462e1411641272527b0561a6be455aba407f88", "schema_version": 1, "timestamp": "2026-10-08T09:45:08.893193+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8d916ec2c895", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b762c9c3ecc86a22dcd86e4d48a0ccdaa5399066560d5bca767cd4e2f0e2a2f2", "schema_version": 1, "timestamp": "2026-10-08T09:45:08.902444+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8157d1b8e3a0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:53ea1b89118eee7d6a8df2124fad1506a1ba6ee9c432023e7373c6d746fb02a0", "schema_version": 1, "timestamp": "2026-10-08T09:45:19.726352+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6bab211ea26b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:24c0ef2b154a6791a803dcd778467b8e421dad5d4b6baf39de81f2f568403342", "schema_version": 1, "timestamp": "2026-10-08T09:45:19.747017+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_91b8d2ebd336", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:66a95c71f866e90a80793daddaa132179fc2d90002666ded01517266aa454fd8", "schema_version": 1, "timestamp": "2026-10-08T09:45:19.761216+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6486cf443c76", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-08T09:45:19.800112+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8a7ad7d0fb69", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:45:59.914295+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6c7ab40e201b", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-08T09:45:59.930973+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a6c3ea2b0c5e", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:45:59.947897+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a7ca32949d44", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-08T09:45:59.969481+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_056564fa00c7", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-08T09:45:59.979891+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d606ad4ed9f9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:03f03517cd373a635e50b219bc8b0a5554f847179f27a4c9ff973f8e6f9596c2", "schema_version": 1, "timestamp": "2026-10-08T09:47:45.510445+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5ab5d7d57926", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ceda484f5b46d3c4b391b95960023ca98d7117d6a8a5dc09b99388f1d671f3cf", "schema_version": 1, "timestamp": "2026-10-08T09:47:45.789556+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1340b9556c0a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f1714f99c823bec92c8c6d28ad1f62c9da79172d1a664429a245cb9bbcc9311c", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.020172+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5ffb3d8cd1bd", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8e71e95c43db6a384dd7d33f7c503e218961e1d01cc12995ad48329a47e6bb4a", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.237569+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ffddee815608", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c61a9bdf5e133d2bfb1dabcbf71b9e17fe03131790b6ed8c50f5d02134cc6069", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.497560+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2543e1eb4771", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2721893819c9a2a509b1d00a12d1f57735d61e53a8091523cc89cf9cfae9ecd3", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.810380+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_96f5c05faf45", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9405d2597f0f9fcfc1231a7e19e051e09cc195095200814499fef250f78fef35", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.878411+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b7b5869611e6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e0d76699dfba8ae7a8fef8be621a9d6afd6ec719607dce7d5d416f76d187ce91", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.889530+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bda2879a711e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e3dd63753a17237efadaf92030843f79578d1889e2ca81812c58511e7785f430", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.900090+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a11cb2e84200", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4f891b61ee7dc9346d85a11fdfb7a67138a7273e6a3bbf2cb1b33d02e32f2140", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.910593+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1f5acdbbac2e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e2fb0f9c3d918ee794fb59eb32c5a5c800a141d57a1b274e30922169802445ed", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.921436+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c0ca6d3c6b96", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f11d8f39fab87d55c64c37ee0ccce0685b3df1effd3d14d1c79a8b8a4d737fcc", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.932012+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5f7122416bb9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:819cea304c09dc6d5c77a3f4c86b2b9410d3d726b9bd1c995b15f97928403c3d", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.942723+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d41949e979c1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bd69cfaa5cbabd0c992322c179f4d695af1dc13a05ecf577241b6eae81a89314", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.953507+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f79995affed9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:efc96cdf97cfd490b11102df26e17b453b30e67a7c340567c7d728e2e80e0d9d", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.964379+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aeaf58e0d165", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:794234f32a06f946f4b8e5ed6b03636eceb0e92bdc48fcdc9cd1a9488a9cb3ad", "schema_version": 1, "timestamp": "2026-10-08T09:47:46.974439+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3b4d811444f6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a01ce5f3881ffac9019dcee78eda847704f528fa11aeea1e1fecfe69179a1941", "schema_version": 1, "timestamp": "2026-10-08T09:47:49.952067+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1abfc8aa940f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c714377972246922d783774490628b98d7f2c7c925ff0305abaf816a461c6d9a", "schema_version": 1, "timestamp": "2026-10-08T09:47:52.750541+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_940125bbf729", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:287a27bf5d784180c42e92be85628e9dcdf30b2029c1696d169ed3cb7cb28c2b", "schema_version": 1, "timestamp": "2026-10-08T09:47:52.765836+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_874033969859", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9795795aef9ecc78bb4709639596c49b28a1ccfbd65c0aebf7f4f5de6cc03bcb", "schema_version": 1, "timestamp": "2026-10-08T09:47:52.882678+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8f0b83acc918", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5f4cf8e555e15611b3c7a013c31ac8931faabcb3e10f6814fcac881ce24601d9", "schema_version": 1, "timestamp": "2026-10-08T09:47:52.891219+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6029508ecda8", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-08T09:47:52.905940+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_39193f797622", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:22b370233a44437079a242b3bb798bb06f048ae402bd6f78bd0deafe59016bb6", "schema_version": 1, "timestamp": "2026-10-08T09:47:53.135277+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b56718f4e6d4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5b801f128b877be46923e4ca9b06c9a899a28c566b0ec9580417df1fc2af9896", "schema_version": 1, "timestamp": "2026-10-08T09:47:53.147344+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_58c191d34018", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9b14cf24f966868a50ab3ae0aea4982e08e5f430c5ee39afe018c75f3360a944", "schema_version": 1, "timestamp": "2026-10-08T09:47:53.156834+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e050fcd2d7bb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b8204f50a342a057b7cd699eccab331c9c60408752a0ac198d3c0dc73fe336e0", "schema_version": 1, "timestamp": "2026-10-08T09:48:00.873555+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a4ce70c4b581", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:911452d598e7123bcfb3aab01935b4e3e15ce802adb4287669cbe700b25cc942", "schema_version": 1, "timestamp": "2026-10-08T09:48:00.894120+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9f93590e4d9e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3a2cb7d7b5d2560627b9288c1dd8b79d045174b6f49247eda5ae3fa6b8c56b70", "schema_version": 1, "timestamp": "2026-10-08T09:48:00.908233+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00b82b052ba4", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-08T09:48:00.946407+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0dd3239236ce", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-08T09:48:01.035186+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f5d66b664f41", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.227054+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_74f96831df80", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b2be8c73ca442a15b70fb5d32ffa93355b8f6f554c233b0fea5ef745886d6d1c", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.248177+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_10e582c5a0b9", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c66cf528cfac5380ab7931d658f7634a3eab89e24d46e90f6f17a0c95455bca7", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.255786+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4511d6a1e0f9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1e9b6bd53ba6a6ea091ed695b8e0301bb29365eb118c57eee297d29c320cd267", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.267447+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a9dd4c8fc113", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:60a32cd0bde35291c821f75dc5013829dfa5a7d549945f17c3771711cc2d1bb6", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.275055+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d01514d2ab92", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:41cef0caf0097cc4c4fd68d9c7e4563e294f7edc9fe41c30b4abbfdb6a6f393a", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.285077+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_de478c41b547", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bf1acdd423ccc94da1a56b8c12cbaa26c87cf6d50822c9f8757da23fde49a727", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.292677+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_64d863d1d00c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:06cef615c165941da337cf146137b0ee4158d503c38bae91907f64afc6425930", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.444200+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4d45b7d1917a", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:04b9d82c90ab2cba10b66b5e57f57fdc9e2a8281f7c585139025a2b3f21a08bd", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.452770+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d2ed7656f3ef", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a57bb66928129d29b78f18bbb9deafe67ef6da9bce8ffea11e0f319702b9653f", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.464888+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_82275d728545", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d7f6e9d8a2928f9b7a4fe5cf376bec9ea0f6342fe5a7ccc0e9c9be8f96aae76d", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.484016+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ad64042054a3", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.498418+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a701f505ebe7", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.511292+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_80a14371e664", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.601207+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1080f5f1eebc", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.611394+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e35d19e42d2a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4a63247070df9dd3f2b9b1f3244ee610b92eb0ffcbee7eb08d1b7ca6154036d4", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.620158+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f268277d568f", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.686068+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e64ce1d9b3d5", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.696205+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b99dadea9676", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c005fd018ba43868293811579cb018ba5bc761c5064c22d33aaaff55e0e7cd30", "schema_version": 1, "timestamp": "2026-10-08T09:48:05.704695+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_295099578bb1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e9c7af445f61326870023ea52bd0c68037da30ec8d4e73bd6898b2e46740a6d0", "schema_version": 1, "timestamp": "2026-10-08T09:49:50.434228+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8720296590a3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d2c40597c6ded9d31e15ccf918350ce1f01f668228c5ee3faef2f94006b787d1", "schema_version": 1, "timestamp": "2026-10-08T09:49:50.446341+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cb5c16fb2da1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9c7347c1767e3f94108589561ab1a515b7291c814b1c8290574e8e200b824979", "schema_version": 1, "timestamp": "2026-10-08T09:49:50.456684+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a217078e0be7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d79414e120715fa32b8f235b5ad93fe43f1cdfa29508666ef7786a5834fc92a9", "schema_version": 1, "timestamp": "2026-10-08T09:49:50.468780+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a0bfc6ee49f5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:abb67a0d3aa9c2acb11a4937d012e7e95f23a1784f3a39da571839542bfd753d", "schema_version": 1, "timestamp": "2026-10-08T09:49:50.483369+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_70d1a83c040f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0a9de9419bc5370ec4d15ade261a49b1c4d5ee6e5672b17fc02b1db5f21e0334", "schema_version": 1, "timestamp": "2026-10-08T09:49:52.664876+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_34a6282f00e6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0e9818a43b19375f37095205c791c994010a6c0397b3b42752dc54feeb44ffba", "schema_version": 1, "timestamp": "2026-10-08T09:49:52.676699+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4807fdefe40b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a7c0c90d70631254b400bd4092db2d91c61ed1f87112f5837f23d286c3112e63", "schema_version": 1, "timestamp": "2026-10-08T09:49:54.353519+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8816e29ed833", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:61d2716418143d03913c67867c61a50129ed07ae7465bfcebc009f7c995e4943", "schema_version": 1, "timestamp": "2026-10-08T09:49:54.368548+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_823dd43a0828", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:acc7787917bc766fa4771df07da5b8de0135015667abc3ae90b8064f7d833b46", "schema_version": 1, "timestamp": "2026-10-08T09:49:54.481013+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_53a152ccc0df", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e777d078d3af80da79f0140a25bfa6a5d1f55214d455c0a087ff98ff558543aa", "schema_version": 1, "timestamp": "2026-10-08T09:49:54.489728+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3364588a6e09", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c99fbf5961c78447f14b86f32d0b39bd85fd57a3e18f736064b3eb8e14790f80", "schema_version": 1, "timestamp": "2026-10-08T09:49:54.548141+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6b939e9cdaef", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf98981ea6cef633e53348abb7fa9530a33bc6f319a1251d7df58a58f22a310", "schema_version": 1, "timestamp": "2026-10-08T09:49:54.555842+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cd8fd2e8a5b2", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-08T09:50:48.433613+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bd97b6712c9c", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-08T09:50:48.512329+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0abe932bf7f8", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-08T09:57:24.745745+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c8ab2dbb3c72", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-08T09:57:24.796771+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3730c5387754", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:58:06.226913+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1fff64c6f2e7", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-08T09:58:06.246748+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_16056fbb022f", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T09:58:06.269099+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8ee9de9e36d7", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-08T09:58:06.293585+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_49c7929fb5f8", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-08T09:58:06.307457+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a0f107053f7f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3b4e4989c65bc4ad84b1eec5e05889266a3f6d3a7cd15b32d5097cebb91b779e", "schema_version": 1, "timestamp": "2026-10-08T09:59:51.905097+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9081fb0f79e1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0100d2f4e37c495f742ce2131f4b74e1a7d624c1d78e7a2b1b430a9f445d905e", "schema_version": 1, "timestamp": "2026-10-08T09:59:52.193094+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8b5ac7c1b91c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a84901d9d0e96a31e6c798cfe69f1621b3ad4ba4769f584df52beabaeff18b32", "schema_version": 1, "timestamp": "2026-10-08T09:59:52.426155+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4e5fb2334a43", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d2d736a44abe6790a945a7a05b5f8113aa7324e76279ea99a66271fc60e7c728", "schema_version": 1, "timestamp": "2026-10-08T09:59:52.638400+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e3138648da70", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6b68e338b175cd493f1062a1679eae6bff47cd836f5a60883b25e9531b28a948", "schema_version": 1, "timestamp": "2026-10-08T09:59:52.900993+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a9562e40d4ae", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b5646e9ef7d1edf70949b6c4698acd782cd09e25828d56b91e08d45da63f5672", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.209084+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_10512a04420f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:18113c90cca5f35e34552495a766011c0b1a4747a65d1ba1330f1cd9cef486d8", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.278258+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_944c3f187f5b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:25037863bd764fb163312998a4596631970aee8cd6d871bccc34d4a8f962ea42", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.289398+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aa8a125f6c10", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:445f0fefe0bb4d7b3ffccbbb88caf7f5a8446925fe21c75ec8233e5b76d8d521", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.300593+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_347ddd9f798f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e2769478d18a89822bc0f3d4cda9a19fbf9fcd2158a22a3416ae9eb6eff2e933", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.312613+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c06ec750c228", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a72c900344411a13320e71c1957b5b51524da2a6c534f964210e3bc16347e3b3", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.324137+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e63d239355c0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1a468ffec07524fe4769d735615f75560bc278af706f26d9afc4f1d7ce72efd9", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.335238+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b4ac62bfdb36", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:08bedf5949157090deb35fc7c0e4ac89662f471e05b7d06d6093d0c4521f74d8", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.346126+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7760a1b67441", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3a503dc9da8e253c6c381b8a796fabfcc3a4b9d380f3f92d7a683f157840faf9", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.356937+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6742e5dc215d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5ec17d579ef33707b4093e112f308dfce193b2a2decce24c0c736b1a8a6af46c", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.367713+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2d6236e900fe", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:70b17257d3051cff7c9f1fe389e5fc40b6343a2f6ad0d61be14e1bd8766d2020", "schema_version": 1, "timestamp": "2026-10-08T09:59:53.377897+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_487411be3efc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c15adfeac4e79b031ed5faddd083dd953a38d2d3ad9de5befbbc38ada03de8f6", "schema_version": 1, "timestamp": "2026-10-08T09:59:56.498932+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b691386fece4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0152155ffbe970fb3c916ffc59b61884e5effdfa010014f53e64ce02d5f97477", "schema_version": 1, "timestamp": "2026-10-08T09:59:59.253624+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4934019a3149", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:22d0c3c1980342243ee601f3be764ddb2b9c698f16c727cc72dd7f0c2e0920ef", "schema_version": 1, "timestamp": "2026-10-08T09:59:59.269375+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_45ec9e90e431", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:809d83f75f5cb995ef2158faa5858dee61c97d0a69204837cc918b9c6270cbc1", "schema_version": 1, "timestamp": "2026-10-08T09:59:59.378227+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_30e24017f92b", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:312d3e78398b2807e3f890af2a7f62589a820c58f875054153e573f7fa178c61", "schema_version": 1, "timestamp": "2026-10-08T09:59:59.387860+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c8a3645cfc9a", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-08T09:59:59.403380+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_685ba7f5be8d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f89b3373cd305b4cad21c224984ad4eb89e84b191850e77e91190e0cdc2a52aa", "schema_version": 1, "timestamp": "2026-10-08T09:59:59.639226+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_254584af0c33", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dfa07c229c272107899ea4b8f3dc58c3d4886fe657b52537531b3fe5c22cf003", "schema_version": 1, "timestamp": "2026-10-08T09:59:59.651331+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_71dd8b15a2ed", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e696dd6ae1d4f02879865088d9a766db1e958a73435a138755e66061d5ad482d", "schema_version": 1, "timestamp": "2026-10-08T09:59:59.660894+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1d411d8a6f8c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6641c61a71a2b125de98e95d10be30d7495a30fd5da84253e4983de6f24946ee", "schema_version": 1, "timestamp": "2026-10-08T10:00:08.090151+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f07e9c0fb1d3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:02621f7ba4d66b064646a9b87d3254d0b42671c266812c5c42535d9eb660d724", "schema_version": 1, "timestamp": "2026-10-08T10:00:08.111514+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c557648a29f9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bcb44b3d5cee01f779b2c72d383bc9c664ba58da913393a6499eca8da8e95c30", "schema_version": 1, "timestamp": "2026-10-08T10:00:08.125817+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_adb78bbf2eda", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-08T10:00:08.165397+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_30101e5d3034", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-08T10:00:08.224039+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1a11e23984da", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.317184+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1b48c7469561", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2c5537fd8a2841c863c36c084513d319ad8f1206a11bd05abb10e417d39699ef", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.338858+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f81e47e9ac25", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4c22c1c9573548d50956b70f9d311388424f95f93adec97355031e53a10edb4b", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.346658+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e8e3a578ca9b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9286dcdfbfd38ebc37cc0f62101df98edf3a63e2eb1de4bde3fef094ae8387f5", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.358522+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8f31585626cf", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d550ea162ae4a5f184a9d1feacfaafcd15f1db4cee71d632db776c72ee90690e", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.366285+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7e4a40032e87", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:47e759236f978d18710dba288a913ff540a79540151ea1a5bc2307f78af5931f", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.376681+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_92e06c32bedb", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:22c5a7bd57a57d2dd8f4e302a07a5285539ce133d7e8426c68b0cd4ad90ec81f", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.384464+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_13c0a613e49c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:50baef846ce916604e9470d24c124f717682cbd019478a34e611020c01606899", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.538316+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9b6dd5a45b62", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8444acca1c22d73bdcd5740864311b521588995b3ddf177acd8d5ad456c300cd", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.546941+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f3bf08c1ca3b", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2ef186ebec0f42f4eb7ad33f1dc6911d0c01d8292ed29e1674d1cfa07adfdca2", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.558941+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_81ca45a349d9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:00e0eeb8021f8b40f75d97c78e8a232ae60855090c0acc23c0b86bd6aaac8a0b", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.578446+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4fff05c1fb59", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.593420+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d35d14dc5deb", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.604160+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5a41daf44125", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.695796+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8077be3c9427", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.708867+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9e5d43941416", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ef197be7b253e2d682d9bd97042ac3b88c4cbb3410f6835840dc93a1cf4f0646", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.718586+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_497c7226ec64", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.785463+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5fcb8322fbbf", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.795316+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bdd856a82fb8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d0f16bb67c685c9127b928bcde007ce19851652fd6fab829351d57a68bd33e8a", "schema_version": 1, "timestamp": "2026-10-08T10:00:12.803712+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2056a94bbfd5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:297a6e01c7d2c87aceff84fba850045308ff2d2f9ca688da35faf50fc6ff8dd5", "schema_version": 1, "timestamp": "2026-10-08T10:01:57.465860+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_91802f2bb293", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:58b66ad26bbba0224cfc211e56245cb543f406adadf7c4784b49a3a1cf7a676e", "schema_version": 1, "timestamp": "2026-10-08T10:01:57.485645+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7b19b3ac2625", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d37d3ab5b69d86d203d999a95e328b494eb5bab0f6426f12a5293e93bd80d9cf", "schema_version": 1, "timestamp": "2026-10-08T10:01:57.497392+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_98f8436f47ef", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d8e841452b219575100926b55fe7c2f1e060139e1a07de65463fa9ab17bcdb0c", "schema_version": 1, "timestamp": "2026-10-08T10:01:57.509479+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3a0f4b81dad4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fc3d1e357db96456d922408d837aa80ee4bb6392411f65a3633f09bc80009097", "schema_version": 1, "timestamp": "2026-10-08T10:01:57.524039+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_005f7c4b0633", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:505872b8e7ab6b5bbd6695b8b1ef92a3b15af2fd2f6dbbff3ada30ee26a798cd", "schema_version": 1, "timestamp": "2026-10-08T10:01:59.687979+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_32f1dcae4310", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9da744a6a979f846906040fe5b05aa5c6210f2ea89a94d51ac7e0c8da97ab21c", "schema_version": 1, "timestamp": "2026-10-08T10:01:59.700123+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_17996cd40620", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ac742e40b4887f8c73a920b500d5517e1d3fe57bcdf21ff6abb3b75dde4f6a94", "schema_version": 1, "timestamp": "2026-10-08T10:02:01.367855+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_62ca758a0dfd", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e3866dea4c1403f5d2dc86d95b1a8a8a1388323c0e786259898b131fc7571ac7", "schema_version": 1, "timestamp": "2026-10-08T10:02:01.383127+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ba7a6b1f603d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:66d9683caacf5752b453fd01f0d50347137e0c334ac04d799c9ddcceee657136", "schema_version": 1, "timestamp": "2026-10-08T10:02:01.491601+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_239fc4506361", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:be4ca75d6f5adf0e64aff8f8d5371c717cc07ee49cfc1311689377161d7e057a", "schema_version": 1, "timestamp": "2026-10-08T10:02:01.500409+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e697cec1a8db", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5e81303b217a6341659d97b47457baa31d2432e4830f7114dc39040954b68a92", "schema_version": 1, "timestamp": "2026-10-08T10:02:01.557984+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_99c5c80fe116", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:79b17dbb134a1be0b3f10b698cd83db191e19ceb07ead3eee0f800e2fe2a7c93", "schema_version": 1, "timestamp": "2026-10-08T10:02:01.565930+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dd372bf4462a", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-08T10:03:46.218633+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1fef6db946d4", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-08T10:03:46.273317+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d77a986d5e99", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:03:46.378330+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5b89f47e9373", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-08T10:03:46.388436+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c2c4bf0faca0", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:03:46.406257+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d24f11995cff", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-08T10:03:46.427986+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9fd1c85df4c4", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-08T10:03:46.438753+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d3be3fc9de88", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:04:25.192105+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d8b043a943c7", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-08T10:04:25.209493+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_73cce7307abc", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:04:25.226388+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6b3fc463fe6b", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-08T10:04:25.247522+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4de7ba25792b", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-08T10:04:25.259645+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ce41312a462d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4e248d1ce61111bb2b947bf22b2088b219df97d52101ebd89fda9967d432e8e8", "schema_version": 1, "timestamp": "2026-10-08T10:06:11.505115+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_69d8089742a5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e4b3f4aa95a57612fa926f08d03072d6a773276671fbed5452bc0263474df40e", "schema_version": 1, "timestamp": "2026-10-08T10:06:11.819085+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c98199c225f5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:53e13305e6617c76b2acfebf4d9d594fe495a11c649801bce66810972a8f5b85", "schema_version": 1, "timestamp": "2026-10-08T10:06:12.084455+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7753af3c3036", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4d6a7d98c5c38fbf46b96c81076561fe0ea3c720aa5f9784940fab76e1b3ad83", "schema_version": 1, "timestamp": "2026-10-08T10:06:12.327968+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e33922d293c1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b3e4f61eb577ae0488a73d12eb9d7e8a337cb6cfeb3662e7f2498eb5753b79ff", "schema_version": 1, "timestamp": "2026-10-08T10:06:12.612596+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_93c9f67e307f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e1a61aba572e8920e714404d531c25cac409d33bd4df2ee45132363ad7b11a55", "schema_version": 1, "timestamp": "2026-10-08T10:06:12.936820+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_50a3a9a0bda2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:16281323f1698c806cbe015778b508fe5ea55cf5c897cab65bc8237d8f326182", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.003779+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1f29d86a606d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:34f0bd31421a3cc4122f53347ccfa709b580dc7a308108dfa64f3fdecc43b6b4", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.015440+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a630011cc244", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4b47beb23c283a57500f6bde37b6e88de3fc11542b638f7e50f046ba927fe4d4", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.026219+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d1ce1d32d8ee", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d349ef0b7168c7ffa37e8dcf2193af4afa9f63cecec3149eabb7813b578efb9c", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.037019+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b5958f5a729a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9267e87f823c486ca102657c81cd725e88f2c4c1caed2b2cf23bf12330cf4d17", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.048378+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_410c17bae193", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:deb33435aad37604d9f4f56430a1ed6516c5f356d09c27d5fa8ae28708f93c54", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.059276+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_680ff0a8c40d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bf72e3142329aac9e694649e0dd5f44a2667f16e61621f80e4fcf498a697028f", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.070505+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f2362d6ae27c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f0fa7db4a34fad5f25017dfca64bab15953ed00ed458f54dc2e4e109593ec6f6", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.081394+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_52b740b46901", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e0a9307f9f0c2595411763a160ecf38d91e45f01c43ed872d5ef04cdb798cab6", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.092449+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2ce868f25a09", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dd35a29901d6dcdbbb9792493ca5a145684076e6511810ac54e5b2f38f015684", "schema_version": 1, "timestamp": "2026-10-08T10:06:13.102727+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3f6fdb4ad214", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:42057cae421c0f533c77d7753ac33fb8441de729156d692a2d6a91fdd19980cc", "schema_version": 1, "timestamp": "2026-10-08T10:06:26.615937+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_29786416989f", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:45cd1bb11e57bbc840199d9948e142e7c4bb10e669db6074e23c6bb69f9b86f6", "schema_version": 1, "timestamp": "2026-10-08T10:06:26.624866+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4b06014f7f01", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7f60a81d364dbd059944a2dfa9016a83cd95320e0f3fe4917405a1ec86bba294", "schema_version": 1, "timestamp": "2026-10-08T10:06:29.437698+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f57e0f5e5efe", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8adad34fb0370869aedba8d37a6703e6198062af8e83b6584281a36448b9032f", "schema_version": 1, "timestamp": "2026-10-08T10:06:29.453124+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8c1e334baab6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:246917930a9112549e9f49f6107ea58f368d316d5effe04d8f10ac87af84c41c", "schema_version": 1, "timestamp": "2026-10-08T10:06:29.589390+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0060315a512c", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:db155941bfb2698a680f4e17f82c14d3279ab975bc8a5090f2114c1631217969", "schema_version": 1, "timestamp": "2026-10-08T10:06:29.598264+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_88080aed209f", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-08T10:06:29.613781+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_938537495f74", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8011eeb30430775948061a0528ea3ad9bb85859a377c6d6bb9ff34d1d8598868", "schema_version": 1, "timestamp": "2026-10-08T10:06:29.854613+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_45d6a7af116a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:32ec2cb1b93f39cc69be645620015a0d194c845b51863610a84379a85d015770", "schema_version": 1, "timestamp": "2026-10-08T10:06:29.866694+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_398453fac90e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:613f66ac657f84b9b05c70e375dbaf3b7547464c17a34ac9dbcbd4ee2928b7f8", "schema_version": 1, "timestamp": "2026-10-08T10:06:29.876278+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6b812aeb9663", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:85f5c8623d1c5ef6912da49a2df68a387886e5322229fbda6748f5b3bfb5553d", "schema_version": 1, "timestamp": "2026-10-08T10:06:38.782157+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1f5be408a07a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a6f3c6aa943d77562045a1f2f2d085ed2e0048fb817ae4efbcece163cd444fdc", "schema_version": 1, "timestamp": "2026-10-08T10:06:38.803319+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1a3879cd152b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4e1cb35db7f28ab6570bd3d8858c203c0a9aa92bb652c0f2e28261783ec8039e", "schema_version": 1, "timestamp": "2026-10-08T10:06:38.817554+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_76e5dd9fdda8", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-08T10:06:38.856410+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cfa340b2f123", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-08T10:06:38.916214+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_82e754af8013", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.168494+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e372fab15310", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cf0fef8260c3221c7b1300f3002eb86cc213621f749dba18d7355bb15a0ff6a7", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.187060+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1d6985cd7062", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:37004fdd7e44e7b8dc0945f78dfdb5b7971f3e08ec8a802a0b9ebae0169fe1cb", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.194950+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_199f638a70ca", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:146db3f55384e87597f38cb4e198920e7cfbe65995135b60f3b24bbea30bb815", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.207123+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_05d0bc227199", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:71517b1d8d80950132d5784bac2bba04c5d41fe92a1439a0779c63f10fbc042e", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.214847+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_68a3202482e1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b6f833867ec5fb074b378e5c5e33ad73033a54931823ae817094644c7bde12bf", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.224899+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_22980381b390", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:18c97b6bee3bec4bf8173821ef53197b2f8e8466c95d63457402164600cabffe", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.232942+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_40d1af023c06", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:db812f351fed870b45533f0c69baad7dc18faa657f94e611fc0ee1862cf89c2b", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.392673+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f6189f24502a", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1c7770c58fd725720f618bca11e601ce036c08782f33069b3565026d4eb643a5", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.401454+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_36e4e016f0c6", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:56a70a54537795af8d64b984b8a95cb1cd0c47443e66fa8f3015a59c316b99fe", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.414168+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_58f94bf5d801", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d6481c78c27a1ee3983256c75a23614b0198242e1cc568f7d04d987664bb618a", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.433145+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d9efb4b165ce", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.448060+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7511faa67ac2", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.461599+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cca61612f46d", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.571495+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2f3bc5ae0f35", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.584314+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c1de02270565", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:845883c4fd9e90d544ab2db6920c4c317e9164a9b16edb3e827302aa3f642840", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.594433+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6c77234a102c", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.695977+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_80d859e7f0a4", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.711369+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8794478f60d2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ce47dea80bfe884b1831b8f38f1c90084873472272a802ca6ccb6fa68ef337ea", "schema_version": 1, "timestamp": "2026-10-08T10:06:43.720220+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a8ab2c0d0f7a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:05d03992e92d068b740d170bb48502c9ba60520e78d3034100fd4c0d4fd41723", "schema_version": 1, "timestamp": "2026-10-08T10:08:28.834159+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c68e8f970cd0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f7e0eb5ff92265f1bac94864461115f541041068d78297e2f2c03f6a92755113", "schema_version": 1, "timestamp": "2026-10-08T10:08:28.853944+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4c482373143d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0e2eabd0db17c1465f07bfe618989fde41d4f8869a46743f9287aad57da25e81", "schema_version": 1, "timestamp": "2026-10-08T10:08:28.866107+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_88716d071ecb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5809eb7f3c0c9218cd0f95a4bdb56fc4749350703e7124e5145ec673d52f25ba", "schema_version": 1, "timestamp": "2026-10-08T10:08:28.879266+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7e1ee29d1e01", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:70e16f6c3849027cea9e3edce55b1ef7fb0e7a171b13291ca042ae355878274b", "schema_version": 1, "timestamp": "2026-10-08T10:08:28.896216+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_12156faf4d06", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9476724c328a812bf66604f683b7e505185f194d17701baec1bf46a1219d3ad0", "schema_version": 1, "timestamp": "2026-10-08T10:08:31.390405+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8e0d9b0b21e9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:376ebf0a5c96a5e1e0d71b881cb9db7f8e0015cdc7bca79c61ae739e1de10cee", "schema_version": 1, "timestamp": "2026-10-08T10:08:31.405703+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_74aab8deeaa2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ac30651a70b59182e7cc26863398e35bb5ca71a68583b0057fb2a586702ce897", "schema_version": 1, "timestamp": "2026-10-08T10:08:33.149411+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_802ba79f7cf5", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:91e88044c74ae6435ce0e920508282357ee8f3d070478bfce5c031a1acd483a2", "schema_version": 1, "timestamp": "2026-10-08T10:08:33.165894+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2d7a775d4216", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b1d0c0f4062f8783c825e1b59c2745c82d6831cef78a178f8ff743f94e8b7feb", "schema_version": 1, "timestamp": "2026-10-08T10:08:33.292251+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e2627ac7ee82", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:83da0a8c8616e718c3e1fea3787ded1e140e88fa6f306be8cf245b0bdc6d005e", "schema_version": 1, "timestamp": "2026-10-08T10:08:33.300946+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9ad3a236b77b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:808f4ea8601531cf2dd30e680c0db6d8f2f482af379b3b43d5a0a52bcfdad0a4", "schema_version": 1, "timestamp": "2026-10-08T10:08:33.366702+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_59c3309edf9d", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bbe83b123edaee1e83333b574895742ece5c104c9066524fde0c6675d5aff8b7", "schema_version": 1, "timestamp": "2026-10-08T10:08:33.374880+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c5fd39408c96", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5bf2fa6f19383967c71569b1eaa95239447a3b37a94874a2e777a069ea48d310", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.633570+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6f7e7510b7b9", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.645704+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a8345edbd547", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a7d49f9f9147c9d63646e1ee23453a5c70e676e619d0324265b0accda50d30bc", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.660398+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7ecd45f23111", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ec6387ab74b1d10da16fb639bebd75421e590add7451365e6167103630d193a8", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.669048+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ce872155d99f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5bafd319acf67a7433e717b8c5ef4a435cdeb2e2e43b70ec619b5845012d8d08", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.682546+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f95f0d528276", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a18155c946da3882c188561fa01ed63756148bba0e97a33cebb35075777a5380", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.692145+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9f15a6039f89", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d24fd8b74832cfee95965bc7fb0e79c0c71b4c2271ebe8290dc57e85f124a592", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.704494+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c198833eb126", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:62d0e6ff790d0ff1d77c03a16013cc75ef05b035daa503e7eb0ed3d422bedfcd", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.713369+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_64d813c9da57", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4b9b0072d746b3e08ee575de174d4b0367dae8ae041a263fa6b2235905254197", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.881701+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fd19ac8384b5", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:78d0da8e35c5fb5fafe6af37a49e5c92894a8d79f46dc8cbf26dbd7a3586103e", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.891228+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3c40230d3626", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5601908882fa9136fda697ecc373286d3e2be77eecaa10d1c5ac81a4b8062758", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.903976+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_77bbc5f4528d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8430e25758af05a0d40bdd14af4ddce793e471a20a991ca1436ce9916e413eb3", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.922035+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_79fa579633d2", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.937238+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_85dd02b520a0", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:11:11.952159+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_eaa9f292cd0d", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:13:14.954090+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1902dff5dced", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-08T10:13:14.971239+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f251bd3fa924", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:13:14.990966+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e266e1c59d70", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-08T10:13:15.013563+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6034668d69cd", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-08T10:13:15.025801+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ed1d299f1c24", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bd0bbb1e3488433f353c442b1ca58993a8cac4ec96f05811e26cce57614053e0", "schema_version": 1, "timestamp": "2026-10-08T10:15:01.237684+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dad3da3be210", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:62c41a94d92973998f95529e703a79208ac95a52523c1049f75526adf767c380", "schema_version": 1, "timestamp": "2026-10-08T10:15:01.582332+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a88a52102595", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b05665deae18651982747fd88866bc9ca101ec344534dde7d61e7e7ff8d0b4d8", "schema_version": 1, "timestamp": "2026-10-08T10:15:01.828145+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3dc411a93adf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5aa9e2228b668c390b5a11141bdc796c526a62d4ec538ce26c35c670c1f9f08c", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.058789+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f8d34643fba2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:03a3b216f87dfbdb536bca8ce440b24284322e0f04ffbd309f7c24694c170655", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.329047+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6f802ad8b1f3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f933e64a3d3824a24b7ceb90cbb8b79717a6202a8117980b8b86436ff96fa18f", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.632952+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0ceb5ccaf5f4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8dfddd7698a41d79f7c12a9ca52a5aea303dc8eb3ea8cea1e355c683cb429d12", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.710185+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4b47896db8ce", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6a4591e645e0258c30071f68aa01a271fae5371713a729b4375ab2f8b3f32ca6", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.722767+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b4df767f81e5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bf4ba8a7a39729b91cd02a3c1e590b99e32ba456dfd183ffb0504f7a20d30b3c", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.734419+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_943517789f26", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:95dedb7e6b7e57bec5dbddea193700e0fa0083f35b7455cfe54215d9e42ab794", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.747363+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_20a32c219b8e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:31e36900a599bb30201883b66fba0a8c5f92824b23463711d9369fa99fd70ee6", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.760039+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_72da870c5a26", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1eac5fb5d0f09db2e5c13e2d11d2cec6f1142f64eb5e959a7fe248f81ed41b9c", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.772140+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8a4aff952450", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6a483c187db33a1fcc3b07e6d5b157ba0e4a621d85d353104806b5c529aa3083", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.784411+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_28c7bb718e73", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b538168bd8c85cb5d7e58d878a7b10f2a03ccbcb5194beb8bbebc76c85681684", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.797887+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_59be2a9714bf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:60402fe9945c7822ba7d68aede2147d212b184913081ae2afcc55bb8ccd2047f", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.809461+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5676e8d2f508", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c776383eb53999a8ea9123b4c1a84056a7758c58a88c424f1f96f7f4f76cbe7b", "schema_version": 1, "timestamp": "2026-10-08T10:15:02.820502+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_01aa7e7ea5cd", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:47958f9f3a2039ca6ad6bb9c685c54616b9a739f9ffb756cfc04de1491ca61a5", "schema_version": 1, "timestamp": "2026-10-08T10:15:05.045199+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9a7ed2609757", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c67c9b79cbd71c9b5d8e800eb1ef13c5473bc41fc0d045d06e70e48786a30683", "schema_version": 1, "timestamp": "2026-10-08T10:15:07.832663+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f51c8a688888", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:303a1250e701bef1e67426c28a4be467ae71e24b26788673747ccc66f8b1e612", "schema_version": 1, "timestamp": "2026-10-08T10:15:07.848113+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e09957e9cfe2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:00c8a7aaff3379058744cf2755b33ab3de36edaf078a76035c51c5776547a934", "schema_version": 1, "timestamp": "2026-10-08T10:15:07.953879+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5626ee5d42ef", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f90f641e1e94bb1ec1da469bb91fb47b1ea27b53d2c8b6e4c9ecbb3c03ab1115", "schema_version": 1, "timestamp": "2026-10-08T10:15:07.963120+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0736efee1ead", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-08T10:15:07.979038+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00c6a3e3c007", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8f4aab68394b9e427d0e1bbebb8d89dcaebe5ff7340281cbd345450d9b482be0", "schema_version": 1, "timestamp": "2026-10-08T10:15:08.225294+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1a8ada9300f0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ec037cee6e39d28330928b700ba7d355ee8d53c750e03db7cdb41cf84369b488", "schema_version": 1, "timestamp": "2026-10-08T10:15:08.236591+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1761e9c20f1e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c73986c9c207636b130c7560295e633f0bd57ac9427cb3042848459b3b478908", "schema_version": 1, "timestamp": "2026-10-08T10:15:08.246259+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dfc6071c3fc3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:07a80bc8a3010402677d4b87cf302bc033bb0acaad3feeb413680daea5a3dc62", "schema_version": 1, "timestamp": "2026-10-08T10:15:16.238965+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ef97f69845aa", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8ba5abcc68b676d426121e77d032cf491b0d70fca1ca276bd36a7d63710f9842", "schema_version": 1, "timestamp": "2026-10-08T10:15:16.260099+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3d6aba2db366", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:508cc080b1b918a7716edf03d8f3488203ba4664870618018f852cead486369c", "schema_version": 1, "timestamp": "2026-10-08T10:15:16.275145+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_19eb18e1ac4e", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-08T10:15:16.314461+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e5d3a371953a", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-08T10:15:16.378106+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b78c28bfc82b", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.643009+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6e30ec5559cb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f2a641b3825cd5173652bcf06853ab9d504f18f7adbf3aac661a34dcbd5202b9", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.665740+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7fe2d0641f36", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fb7fc4980c42badf0d2fd81e81beef130e3af67d81954fa436ce444a14434993", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.673750+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_85aa3fc267cb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ff902248e447b1ffcdb76a7f9b12a3e5c2bcec6ce13d9e94906ed06efe4cfc27", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.686886+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_83f6636d58f8", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:231a5f7973805d89fbd043ce97205f131ac7ba0f0011d0e4ccc8505cd5197f01", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.695031+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00183fea77d6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:faaf796c352dfb447597ef5283d3b46c36ffaeb8822037f75a84d3feba293bf2", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.705681+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_af56d67ec75c", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:03e0d49ef3f1488b65d23588158cad6232b6a17e6541ebe16cbc41c09f320eee", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.714538+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_36410ac105cc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:81ff66328e2af001497331b5a24b6c9a805fc52bc722d39b5f2c2c045b56046a", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.885261+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_68fbf3baebbc", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e6d0c6814ed1790797d280254582c821ab2b6769230e3f185aa8340aae095419", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.895185+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3e74da226656", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7c44c3be70c1cc6c4b920b99daf2ac70abd341124d2ee6f096c0cbacff14c8e9", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.911190+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4f4f71403def", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1b5c56b19af6c0a69987401963566412af03a02c0bd03a0ce3f1d7d004a0068b", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.936537+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0c63c1c62a77", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.955315+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_97bcdd3872ef", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:15:20.965478+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_94e057bc7ef7", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:15:21.057890+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7ca8523b841d", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:15:21.069436+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ad6e82bfd4a5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d7c0436f078ca2386843f7d50cc55d34070e7c8a5cb98ea5a25193194159e716", "schema_version": 1, "timestamp": "2026-10-08T10:15:21.079390+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ac7a4c29e597", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T10:15:21.144940+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_54fee936d3db", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T10:15:21.160005+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_52ee5136ba5a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1fb854871521eacbcf2916ea99b67f8499dc817b687a0e00fb8baf13b9215552", "schema_version": 1, "timestamp": "2026-10-08T10:15:21.170792+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a37dd7606214", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4f66d7560e2ac1fad4bfd9561a87132155de69b6a2e228337bab480bcefea44c", "schema_version": 1, "timestamp": "2026-10-08T10:17:06.102228+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_84a15b67e1c5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8871ba95de0019da1400f1f711ba1affc5519f57bee9894648b27f1057de3bae", "schema_version": 1, "timestamp": "2026-10-08T10:17:06.116889+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_838645029cf4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:eef665a8f5025c42d17ed779dd323bff4eb91bed77a94f6a4b88be2232578f35", "schema_version": 1, "timestamp": "2026-10-08T10:17:06.130092+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_71f2675458d2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:44fc0b8deb923e68304609e2ca5ac6bc5c5e93d608858c9845ac2c51c560a7b6", "schema_version": 1, "timestamp": "2026-10-08T10:17:06.143344+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_527e8ed12874", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a1a90d6ffa23b44d6ae12e7cd0a388f81a60700c34ab4e83da449282a209d9a9", "schema_version": 1, "timestamp": "2026-10-08T10:17:06.161757+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_48cab5228bd5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f13f1c5b5b061a01816056c9d7aa23ba55a308d23cb1cce0e96efe616af2890f", "schema_version": 1, "timestamp": "2026-10-08T10:17:08.363928+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_99f506db51ca", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:50a078277590f98ab2b1014a017cbf2972d3444f00a401cd33fad01a4b409a3a", "schema_version": 1, "timestamp": "2026-10-08T10:17:08.376539+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3c21d551c95d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6412038d71e19b0edbcd4547ff20d51d8286f16d885fa9f00305699f1b42cdac", "schema_version": 1, "timestamp": "2026-10-08T10:17:10.077598+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_be568b6b4721", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:48158cd4e977aba375db9a3c940081b147adc32f3597d86523010c9e0ad9e3ec", "schema_version": 1, "timestamp": "2026-10-08T10:17:10.092920+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d1252b968500", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e3a0ac6b4da18fdbbdbc73d4f7a38e11cc1f304f06908bc4f2f0d2159c50894c", "schema_version": 1, "timestamp": "2026-10-08T10:17:10.231283+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_def6f69c5640", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:21ebda50b2ec4036b507f39578f65b5e1c21b9077fa22507a24aeb2cbd9d9d63", "schema_version": 1, "timestamp": "2026-10-08T10:17:10.242252+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d063b273a3b0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:532e04418e8fb212543f8b514fb22dc48b24f888a5822f73b6cfab5297df85ac", "schema_version": 1, "timestamp": "2026-10-08T10:17:10.311501+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d552ac586f61", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:01ca35bb3daf64b85dfc225374321519321f7d6ac5eca4858bac93c23726499f", "schema_version": 1, "timestamp": "2026-10-08T10:17:10.320089+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9efef58f951e", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:46:59.785501+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_78826b359be8", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-08T11:46:59.796475+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_592e3651d983", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:46:59.814178+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3036fac834bb", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-08T11:46:59.833698+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8a1dc09d5748", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-08T11:46:59.844195+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7a93a66f6bcf", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-08T11:47:00.491964+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b4056ae33d3f", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T11:47:00.785014+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6c6e8f1df560", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:47:00.800536+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_23f442fc3a5a", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T11:47:00.880161+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_61685df84819", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:47:00.890350+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_90708a38fbb4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5b17ed04e31af27b8dc8019789de344d75e1b099fc6783a97d4faddd884fafe2", "schema_version": 1, "timestamp": "2026-10-08T11:47:00.900173+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5dfaa6edc9ec", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T11:47:00.986565+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_687b5418cb79", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:47:00.998996+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fd093c262348", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:96defe807e19a96fb20a057b33d573afc24b35c3f332cf24c42038469d40501c", "schema_version": 1, "timestamp": "2026-10-08T11:47:01.008962+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e293024dfde3", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:47:25.193979+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4229387b5595", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-08T11:47:25.204619+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e3cd657d08be", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:47:25.222316+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_235134f601cb", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-08T11:47:25.242518+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_404b892f9ba4", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-08T11:47:25.253460+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_47c2ce07ec0a", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-08T11:47:25.874585+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2824e9fd0d2c", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T11:47:26.129444+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0b73de4da6ae", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:47:26.146393+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_11a63a297e0e", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T11:47:26.226502+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_33c31a877cde", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:47:26.237499+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6e58cccf26ed", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e55b30017aa9c8df84662a42bc9f6cebb57f9d9df9f345d553c3576fd014adc3", "schema_version": 1, "timestamp": "2026-10-08T11:47:26.246116+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9a2595630390", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T11:47:26.347846+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_10e8a9b784a0", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T11:47:26.367028+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_49216627a74d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:505045ada0ed8cb966c28e32aaf38f018a7eaa6ac192374400bb803060865d83", "schema_version": 1, "timestamp": "2026-10-08T11:47:26.375893+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7ba4e482a4e4", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5cdd049621187f08e5463dcb964b4b4cb833cd3e9a90d0ab1f2a08f4b4b45fe5", "schema_version": 1, "timestamp": "2026-10-08T11:56:04.836186+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9a341fb05052", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5cdd049621187f08e5463dcb964b4b4cb833cd3e9a90d0ab1f2a08f4b4b45fe5", "schema_version": 1, "timestamp": "2026-10-08T11:57:16.915223+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e516347b5a6a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:af3d4be5c2c01125f68965d0c9a1ad30c0f2d3ebfc31492de5cbd933d50612d9", "schema_version": 1, "timestamp": "2026-10-08T13:47:25.015461+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_96e93c315d14", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3a3fd70eceea9f83512d7e1efd784ea20d59b537de6dd0ee93f943013e9a2b83", "schema_version": 1, "timestamp": "2026-10-08T13:47:25.089365+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1714bbb6e2db", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a8bc9a2f815f20262641bb11028fd9709f4b2587e128126890f86c7cf66fe3a0", "schema_version": 1, "timestamp": "2026-10-08T13:47:25.100262+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6e2f2122c61e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ab1871c1420b0739962a613bd79fdebf5ed0876e1525d2a5e4cafa52731f1d69", "schema_version": 1, "timestamp": "2026-10-08T13:47:25.111620+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_87597a350896", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2048aa1592fbcf0f871b14264afcfbade8cf74e4d76dab3834868bd7566bfc8b", "schema_version": 1, "timestamp": "2026-10-08T13:47:27.622323+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d055d71d8358", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:54e640f598c5870ac5896b633a1dec5f5d940fa3c5d4e9d846e54c02d5cbb6fa", "schema_version": 1, "timestamp": "2026-10-08T19:30:04.301970+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2f10093ec823", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ce008ca4e5dd63343f9defc791d5e97eb925672cf793e76ced1a9ad5abfd4d61", "schema_version": 1, "timestamp": "2026-10-08T19:30:04.313539+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_063accc6c4aa", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fcdfb55eeedf9540661bf5e40decea6b2a0e08c17a01bdc5fab4691e3f3d5316", "schema_version": 1, "timestamp": "2026-10-08T19:30:04.324724+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_46c543436d75", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:34ed4a85454425322d71b45051f6d98e04199d7bd7942b50aa29b1b6217af78f", "schema_version": 1, "timestamp": "2026-10-08T19:30:04.333097+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5bd1cb49b3ea", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6214410288c38c025981bb6adf5d841cfb9f0a3965b01da40f33f01a6373b173", "schema_version": 1, "timestamp": "2026-10-08T19:30:04.347529+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cc2276dad2c9", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1889a81650986254f870f54ba608aeea3b818ccf2f1aceedb02f732d0bee688a", "schema_version": 1, "timestamp": "2026-10-08T19:30:04.356013+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3b70b2d544bb", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-08T19:30:04.373125+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b369bb463f72", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-08T19:30:04.390511+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b9100bc91095", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:06de1a2d4bef656cc1a87d9ea5bda83ab82804f8e02392aeafc13970827099e8", "schema_version": 1, "timestamp": "2026-10-08T19:30:05.383712+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7fb367e5ec95", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-08T20:02:32.251570+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6e2eae36a71d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9977a6d02be1d9e67438451a8e98c326274e521e48249d76e5a3a43dfb46fea5", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.576900+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0230eaa227c7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e90546238df2aab6628aec498b928a101b4b272f883e9c20077ff923f8e0adec", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.590941+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3aa7e891622e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d2e6f3b6eaac2ebb3dabd7ae6e0b6ed115b2de587ac6ea85caf45ebbe8ee5034", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.604527+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9d3c19c7d8e7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:02f65dc61d0179f9c7716c1be57f557f118653478ad1a8cbae92f4cdb311984b", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.615784+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ba64dfb70668", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f5d0c2e9e946f0fc5529d05ad25bbf8428090d938b2261c7da47f1603a677e9d", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.628634+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_52d302b5e2a5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:df7501b8aa6e653f244d37e619c8de5a8b848b6e3aefd96af29f9b1f2b3a8288", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.641383+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6210228d752b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dedeeb8e1493635ad2dacb66ef85ffe2907bc21b02b8ee069838c6f95c8b8201", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.655114+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_417ad3cdc8a7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a00407bed6e9a96f4f934eabf774d130e059386aa6cd2afcda28437cc23c7270", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.666766+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8859231bc1ec", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b6e984afb76ef30adf074ccd9e3fc39d0599f1c107982f4d979fcbb884f0b834", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.678159+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_582a15cb0ab2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c8194ae237868d88d0c0670dfba9ae2d0d4a4a5c1e3b0fab56a03bb0fc59d0d8", "schema_version": 1, "timestamp": "2026-10-08T22:37:50.692553+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c7ede3f3d417", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:00342a2c690ed0b0f6a3674896cae0cd1c82a2d3ad56c87198904020a3fbe8d8", "schema_version": 1, "timestamp": "2026-10-08T22:37:57.940960+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f3371dcb3c58", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2d566f3ef26f88f55f7a58b9366f24658353d4f0a7a9c4eeaff9511974bbee8a", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.718892+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6a54aded6051", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:db9f86437b297420a1ccf47f16c34e81ab215170c0885080dced2e67c7bac6d6", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.738060+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f3d82d12b5bf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5931b7eab8e3b1f728ff68986fa1ff63528381472101eb83e4337b82ab0eec15", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.749770+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_332ab0e49365", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b318e09d2b8f6dc6818f28c34fc513225f7294bd5585cfee6a2ae3837f1f82b5", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.761798+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9eb6841db7a0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ebfc6a3ebcfcabeda3dbc070334fd8f2a01e9c8c4f320732bcef0600f2c3a95d", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.774693+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6b82b1aba326", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:71e13910d0707723f354ac714c0388652e46e7004f21dec66bc211aad81f2e98", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.786029+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_81540ecb9b4d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:83af143888ac9792e22cf995184e6b755009c8ce2a81429f8bb4aae143be328b", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.798195+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_37e2cd7fb439", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3236cb77e94d12556facb6d0c8f7f48944c2fc9af8381c315d8c1a4a19eb0456", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.809660+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cf744dc776f1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:22668e8c75584604941e2c5b7052de20ab368f8d8d16cf3dedbca11f91cd1ed1", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.820778+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_84d3061742aa", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dfcb3cb27570c74db077c5afad5043eaa3ebbbfe9a6aae8ad4608eda1ad7d745", "schema_version": 1, "timestamp": "2026-10-08T22:38:34.832546+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5f6a485e3310", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4a5c32a30ac5c6f3177f585add130cec9c9f7e3cd263f64bf435e1ceb77bcee9", "schema_version": 1, "timestamp": "2026-10-08T22:38:39.766466+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_19df708768a1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2a0de917be09282a36009a5dc45c78d71e05c1fbed4a5a2fd3efcb62a8e58071", "schema_version": 1, "timestamp": "2026-10-09T00:58:40.672290+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ad4dfaef014f", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:51ebfed8eb96fb304ee47259aeb359362029c11dd6e47477ce470a5766fd0372", "schema_version": 1, "timestamp": "2026-10-09T00:58:40.682485+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e8995f5a1033", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bc952817f0d7c650125e42ffff4ca30b6a2b4850ed7089e8d3ddcad2ef4d4f40", "schema_version": 1, "timestamp": "2026-10-09T00:58:40.757011+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00441808b642", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:39e82c53854fcd6003b04c27607b09251c1ac28abc7395f37480966f106c8722", "schema_version": 1, "timestamp": "2026-10-09T00:58:40.766866+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8bae0d2c2fc1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0a606ac3d92ffb35ee69256607a47fe349ef655d4ba105c7f53f5c221cd3178d", "schema_version": 1, "timestamp": "2026-10-09T00:58:41.548874+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3d00e69c6e8f", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:92c8e6780aaa9e9bbcbde7ae5b7a61fd6ca4a33ab223185769e0253d500b9454", "schema_version": 1, "timestamp": "2026-10-09T00:58:41.563982+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b0a84f50bd41", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9de6e36897848255e463fe1d6d5395f73462b0630b5b4b12b796b50ddb4f3eb6", "schema_version": 1, "timestamp": "2026-10-09T00:58:41.622554+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f8cbb7f2e6cd", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:36329a50671fc43c72840b72a140268f0f5940c18cfffac9da0410d37bcfb3dd", "schema_version": 1, "timestamp": "2026-10-09T00:58:41.630651+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6a074d09b18e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2f028e5f45db25ff1ec136f36e45793573b8262c2ce94479a9f8d3d6ef748fc7", "schema_version": 1, "timestamp": "2026-10-09T00:58:41.685729+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9854e509f7b1", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0735794afe0ed70f199e758a70248892441aeb097ba84fad09d04eeb47506be4", "schema_version": 1, "timestamp": "2026-10-09T00:58:41.694074+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a7457ca95cb9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b9d74257f64b96170fa04cb3a221e8d031d6fbc039ddd2c5a28529344394aea2", "schema_version": 1, "timestamp": "2026-10-09T01:04:51.871007+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_28b7ee7c6af0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:28273d478d19b77c6c35346fefa668045a684f85da8591950258cca89d4393de", "schema_version": 1, "timestamp": "2026-10-09T01:04:51.957841+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_41b2851566cb", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-09T01:04:51.969565+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_84f4ab924a4f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f83020bb9deada908fb3cb8e4a171f256334d916ca0db3f1e22368c03b9168c8", "schema_version": 1, "timestamp": "2026-10-09T09:02:28.167744+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2026cb12ac77", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-09T09:10:46.314755+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dc37b1b55594", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-09T09:10:46.329159+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_da9da8a76c73", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-09T09:10:46.351043+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0c116e121dd0", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-09T09:10:46.377129+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_523e03ee183b", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-09T09:10:46.395999+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0d6cc8ca4a2c", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:56348046fdcaffd68dc023404ca6e74276e448963799642e7e04ee13fed71bca", "schema_version": 1, "timestamp": "2026-10-09T09:10:46.447080+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b7130a066168", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:66534676bb7b550fcad56e7fb5158d312408a38ca50538ba32659ae8079f869f", "schema_version": 1, "timestamp": "2026-10-09T09:16:20.871689+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9d5c52b933ba", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:138344f58296f8ce85cca1891140d95b67d4ffd714dcaa454c5c466e107e8e9b", "schema_version": 1, "timestamp": "2026-10-09T09:16:21.168821+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_823e73a347e7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f6a000ab37f374c57d3dfee593d3d1c85718e064af628b5841d20949fca6f797", "schema_version": 1, "timestamp": "2026-10-09T09:16:21.415669+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_486fb6001b34", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1b96d80aa993d9bae78e2a5e652b26f9f636fa13c3f835297083c8693c2cf8de", "schema_version": 1, "timestamp": "2026-10-09T09:16:21.648124+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_85ceaa53144e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:41106269075cb95f122f9e71216b0083dbdb65ef995e10171059560dad30b16a", "schema_version": 1, "timestamp": "2026-10-09T09:16:21.939283+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3d1e79ae1418", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f4b086017902903f572bd2ac78cde09a6758513d4edaefdfd0b733445cc668b3", "schema_version": 1, "timestamp": "2026-10-09T09:16:22.373487+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_df15a18a829c", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5cdd049621187f08e5463dcb964b4b4cb833cd3e9a90d0ab1f2a08f4b4b45fe5", "schema_version": 1, "timestamp": "2026-10-10T18:59:15.412461+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_88b4067168d7", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5cdd049621187f08e5463dcb964b4b4cb833cd3e9a90d0ab1f2a08f4b4b45fe5", "schema_version": 1, "timestamp": "2026-10-10T18:59:37.049502+00:00"}
|
||||
@@ -1,262 +0,0 @@
|
||||
# TRANCHE: THE FULL DICHOTOMY REBASE v2 — every Python module replaced, zero Python runtime
|
||||
|
||||
_Revised per Nick's corrections: Bubble Tea for the TUI, henxels scope first, HOW instructions per step, Gitea epic + MiMoCode tasks, timeline = 1 week. Presented for approval._
|
||||
|
||||
---
|
||||
|
||||
## §0 — GROUNDING (measured)
|
||||
|
||||
| Language | Files | Lines | % | Status |
|
||||
|---|---|---|---|---|
|
||||
| Python | 180 | 68,224 | **70%** | **THE TARGET — every module ported** |
|
||||
| Rust | 106 | 27,304 | 28% | 10 crates, 85 more modules to port |
|
||||
| Go | 7 | 1,125 | **1%** | 2 modules, 55 more to port |
|
||||
| **Total** | **293** | **96,653** | | |
|
||||
|
||||
### The corrected dichotomy
|
||||
|
||||
| Side | Modules | Python lines | Role |
|
||||
|---|---|---|---|
|
||||
| **GO** | 57 | 32,081 | Reactive shell: initiates, responds, routes, interfaces |
|
||||
| **RUST** | 85 | 25,218 | Deterministic backend: computes, stores, pure functions |
|
||||
| **TUI** | 7 | 5,435 | **Bubble Tea (Go)** — rewritten in Wave 7 |
|
||||
| **TEST** | 29 | 5,397 | Test infrastructure — stays Python (pytest) |
|
||||
|
||||
### Keep-greens
|
||||
|
||||
Full test suite (2,300+, 0 failures) · All 25 registered canaries · diff-cover ≥70% · Silent-handler ratchet (BLE001 ≤345, S110 ≤75) · Henxels all hold · Lint-baseline no increase · Deploy monotonic
|
||||
|
||||
---
|
||||
|
||||
## §1 — OBJECTIVE
|
||||
|
||||
**Zero Python files in `src/rune/`.** Every module replaced by its Go or Rust equivalent. The TUI is rewritten in Bubble Tea (Go). Test infrastructure stays Python. The end state is a Go+Rust codebase with zero Python runtime dependency.
|
||||
|
||||
Timeline: **1 week** (5 working days, aggressive but achievable with the wave structure below).
|
||||
|
||||
---
|
||||
|
||||
## §2 — WAVE 0: INFRASTRUCTURE FIRST (Day 1, morning)
|
||||
|
||||
**This impacts everything else. Done before any porting.**
|
||||
|
||||
### Step 1: Henxels scope extension
|
||||
- Add `src/rust/*/` scope to `henxels.yaml`: max_lines 3000 (Rust files are larger), no_secrets, filename_casing snake_case, canary registration
|
||||
- Add `src/go/**/` scope: max_lines 2000, no_secrets, filename_casing kebab-case
|
||||
- Add `new_rune_modules_have_canary_or_test_coverage` for both scopes
|
||||
- Verify: `henxels check --all` passes with the new scopes
|
||||
|
||||
### Step 2: Umbrella manifest extension
|
||||
- Add 10 Rust crate entries to `config/umbrellas.json` (cognition_core, memory_retrieval, memory_storage, scaffold_core, evidence_provenance, rune_spine, memory_scoring, capability_scoring, token_counting, query_memory)
|
||||
- Add 2 Go module entries (event-bus, tool-executor) + placeholder entries for the 55 planned Go modules
|
||||
- Each entry: name, description, modules list, depends_on, canaries
|
||||
- Verify: `umbrella_manifest_is_complete` henxel passes
|
||||
|
||||
### Step 3: Scaffolding protocol update
|
||||
- Update `construction_decision.py` GO_SIGNALS/RUST_SIGNALS to match the corrected dichotomy (57 GO / 85 RUST)
|
||||
- Update `store/rebase/classification.json` with the re-classified sides
|
||||
- Verify: `rune scaffold classify <test_objective>` routes to the correct language
|
||||
|
||||
### Step 4: CI pipeline update
|
||||
- Add `cargo build --release --manifest-path src/rust/cognition_core/Cargo.toml` to the unit-tests and canary jobs
|
||||
- Add `CC_RUST_LIB` to the unit-tests job env
|
||||
- Add a `go-build` step that builds every Go module in `src/go/*/`
|
||||
- Add a `go-test` step that runs `go test ./...` in every Go module
|
||||
- Verify: CI pipeline passes with the new steps
|
||||
|
||||
### Step 5: Gitea epic + MiMoCode tasks
|
||||
- Create the parent epic on Gitea: "Full Dichotomy Rebase — every Python module replaced" with the full wave structure as a folded checklist
|
||||
- Create per-wave sub-epics (W4-infra, W4b-tools, W5a-model, W5b-operator, W5c-memory, W6a/b/c-RUST, W7-TUI)
|
||||
- Mirror all of them in the MiMoCode task tool
|
||||
- Verify: the Gitea epic exists, the MiMoCode task tree matches
|
||||
|
||||
---
|
||||
|
||||
## §3 — WAVE STRUCTURE
|
||||
|
||||
### Wave 4: Go reactive infrastructure (14 modules, ~5,271 lines) — Day 1-2
|
||||
|
||||
| Module | Size | HOW |
|
||||
|---|---|---|
|
||||
| event_bus | 244 lines | **DONE** — `src/go/event-bus/` |
|
||||
| event_envelope | 303 lines | Merge into event-bus binary. Add EventEnvelope struct with all fields (event_id, event_type, partition_key, payload_hash, timestamp). Port `OrchestrationRecord.to_dict()` as a `MarshalJSON()` method. |
|
||||
| message_queue | 10KB | Go channel + JSONL file backing. `type MessageQueue struct { mu sync.Mutex; path string }`. Methods: `Enqueue(msg)`, `Dequeue()`, `GetApproved()`, `MarkExecuted(id)`. Port the approved-message flow from Python. |
|
||||
| hook_engine | 28KB | Go map of hook name → []func(data) error. `type HookEngine struct { hooks map[string][]HookFunc; mu sync.RWMutex }`. Methods: `Register(name, fn)`, `Fire(name, data) error`, `FireAsync(name, data)`. Load hooks from a JSON config file. |
|
||||
| microkernel | 14KB | Go interface-based plugin system. `type Plugin interface { Name() string; Capabilities() []string; OnMessage(data) error }`. Registry with `Register(p Plugin)`, `Fire(event, data)`. Uses goroutines for parallel plugin dispatch. |
|
||||
| subsystem_health | 6KB | Go struct with `sync.Mutex`. `type SubsystemHealth struct { failures map[string][]Failure }`. Methods: `RecordFailure(subsystem, err, tier)`, `GetHealth() map[string]HealthStatus`. Write to a JSON file for durability. |
|
||||
| parallel_processor | 5KB | Go goroutines + `sync.WaitGroup`. `func ParallelMap(items []T, fn func(T) T) []T`. Run fn in goroutines, collect results. |
|
||||
| work_manager | 20KB | Go worker pool. `type WorkManager struct { workers int; queue chan Task; results chan TaskResult }`. Methods: `Start()`, `Submit(task)`, `Stop()`. Goroutines pull from the channel. |
|
||||
| failure_auto_filer | 21KB | Go struct with a spool file + forge client. `type FailureFiler struct { client ForgeClient; spool *JsonlSpool }`. Methods: `File(failure)`, `Reconcile()`. Uses the existing `create_forge_client()` pattern. |
|
||||
| cache | 16KB | Go `sync.Map` or LRU cache. `type Cache struct { mu sync.RWMutex; data map[string][]byte; maxAge time.Duration }`. Methods: `Get(key)`, `Set(key, val)`, `Invalidate(key)`. |
|
||||
| connection_pool | 3KB | Go channel-based pool. `type Pool struct { conns chan Conn; factory func() Conn }`. Methods: `Get() Conn`, `Put(conn)`. |
|
||||
| cron_engine | 14KB | Go time.Ticker + task list. `type CronEngine struct { tasks []CronTask; mu sync.Mutex }`. Methods: `AddTask(name, expr, fn)`, `Start()`, `Stop()`. Parse cron expressions with a simple parser. |
|
||||
| night_mode | 14KB | Go scheduled consolidation. Uses the cron_engine internally. `type NightMode struct { engine *CronEngine; tasks []NightTask }`. |
|
||||
| recall_router | 5KB | Go routing table. `type RecallRouter struct { routes map[string]RecallFn }`. Method: `Route(query) []RecallResult`. |
|
||||
|
||||
**Daily check**: all 14 Go binaries compile, their tests pass, the Python versions delegate via subprocess.
|
||||
|
||||
### Wave 4b: Go tool execution layer (3 modules, ~3,079 lines) — Day 2
|
||||
|
||||
| Module | Size | HOW |
|
||||
|---|---|---|
|
||||
| tool_executor | 73KB | **STARTED** — add the remaining operations: write_file (with path validation + ACL), edit_file (with diff preview), run_tests (go test), lint_file, git_commit, git_diff, git_log, repo_map, read_persona, query_memory, check_growth, diagnose_behavior, find_capability |
|
||||
| tool_protocol | 16KB | Go types: `type ToolRequest struct { CallID, Name string; Args map[string]any; Source string }`, `type ToolEvent struct { Kind string; Request ToolRequest; Result map[string]any }`. Validation against a JSON schema registry. |
|
||||
| local_tool_runtime | 35KB | Go loop: receive model response → parse tool calls → validate → dispatch to executor → feed results back. `type LocalToolRuntime struct { transport Transport; tools []ToolDef; maxIterations int }`. Methods: `Run(messages, options) OperatorResponse`. |
|
||||
|
||||
**Daily check**: all tool operations work end-to-end in Go.
|
||||
|
||||
### Wave 5a: Go model/provider layer (10 modules, ~3,398 lines) — Day 2-3
|
||||
|
||||
All 10 modules go into ONE Go binary: `src/go/model-connect/`.
|
||||
|
||||
| Module | Size | HOW |
|
||||
|---|---|---|
|
||||
| model_connect | 16KB | Go HTTP client for Ollama. `type OllamaClient struct { baseURL string; client *http.Client }`. Methods: `Chat(model, messages, options) ChatMessage`, `Show(model) ModelInfo`, `Pull(model)`, `ListModels()`. |
|
||||
| model_profiles | 16KB | Go struct: `type ModelProfile struct { Name string; Provider string; ContextLength int; Capabilities []string }`. Load from JSON. |
|
||||
| model_registry | 6KB | Go registry: `type ModelRegistry struct { profiles map[string]ModelProfile; mu sync.RWMutex }`. Methods: `Register(p)`, `Get(name)`, `List()`. |
|
||||
| model_routing | 16KB | Go router: `type ModelRouter struct { profiles *ModelRegistry; defaultModel string }`. Method: `Route(taskDescription) string`. Scoring: keyword matching + profile capabilities. |
|
||||
| openai_compat_transport | 10KB | Go HTTP client for [OI]-compatible APIs. `type CompatTransport struct { baseURL, apiKey string; client *http.Client }`. Same Chat() interface. |
|
||||
| provider_budget | 12KB | Go struct: `type ProviderBudget struct { providers map[string]Budget; mu sync.Mutex }`. Methods: `Record(provider, tokens)`, `GetStatus() map[string]BudgetStatus`. |
|
||||
| provider_context | 2KB | Go context type: `type ProviderContext struct { Provider, Model string; ContextLength int }`. |
|
||||
| provider_registry | 23KB | Go registry for all providers (Ollama + [OI] + custom). `type ProviderRegistry struct { providers map[string]Provider; mu sync.RWMutex }`. Methods: `Connect(name, url, key)`, `GetProvider(name)`, `ListProviders()`. |
|
||||
| standardized_providers | 9KB | Go interface: `type Provider interface { Chat(...) ChatMessage; Show(...) ModelInfo; ListModels() []string }`. Implementations: OllamaProvider, CompatProvider. |
|
||||
| tiered_executor | 9KB | Go executor with tier escalation: `type TieredExecutor struct { tiers []Tier; current int }`. Methods: `Execute(task) Result`, `Escalate()`. |
|
||||
|
||||
**Daily check**: Ollama chat works from Go, model routing works, budget tracking works.
|
||||
|
||||
### Wave 5b: Go operator (19 modules, ~9,637 lines) — Day 3-4
|
||||
|
||||
The biggest wave. ALL of these go into ONE Go binary: `src/go/operator/`.
|
||||
|
||||
| Module | Size | HOW |
|
||||
|---|---|---|
|
||||
| rune_operator | 126KB | The turn loop. `type Operator struct { state *RuneState; taskState *TaskStateRepo; conversation *ConversationRepo; toolRuntime *LocalToolRuntime; modelRouter *ModelRouter }`. The main method: `Respond(channel, message) OperatorResponse`. This is the biggest single port — expect 2-3k lines of Go. |
|
||||
| adaptive_router | 23KB | `type AdaptiveRouter struct { routes []Route; baselineSHA string }`. Method: `Route(task) RouteDecision`. Route types: LOCAL_FIX, STANDARD_CHANGE, RESEARCHED_CHANGE, etc. |
|
||||
| build_mode | 20KB | Go build orchestrator: `type BuildMode struct { operator *Operator; scaffold *ScaffoldClient }`. Method: `Execute(task) BuildResult`. |
|
||||
| builder_bridge | 12KB | Go bridge: dispatches build tasks to external builders (MiMo, Kimi, GLM). `type BuilderBridge struct { builders map[string]Builder }`. |
|
||||
| builder_bridge_cli | 1KB | Thin CLI wrapper for builder_bridge. |
|
||||
| core_server | 9KB | Go HTTP server: `http.ListenAndServe(":8080", mux)`. Routes: `/v1/chat`, `/v1/models`, `/health`. Uses Go's `net/http` stdlib. |
|
||||
| persona_definition | 7KB | Go struct: `type Persona struct { Name, Role, Voice string; Principles []string }`. Load from JSON. |
|
||||
| voicebox | 4KB | Go voice synthesis dispatch. |
|
||||
| voice_injector | 3KB | Go voice injection. |
|
||||
| release_notes | 18KB | Go release note generator. Reads closed contracts + resolved issues from the Gitea API. Generates markdown. |
|
||||
| auto_context | 8KB | Go auto-context builder. Scans recent events + memory to build a context block. |
|
||||
| auto_tasks | 15KB | Go auto-task extraction from conversation. |
|
||||
| event_wait | 23KB | Go event-driven wait. `type EventWait struct { watchers map[string]chan Event; mu sync.RWMutex }`. Methods: `Register(op, contractID)`, `Await(op, timeout) <-chan Event`. |
|
||||
| evidence_probe | 7KB | Go evidence probe: spawns a subprocess to resolve an unknown. |
|
||||
| forge | 5KB | Go forge adapter interface. |
|
||||
| forge_client | 7KB | Go forge client (Gitea API). |
|
||||
| goal | 14KB | Go goal management: `type GoalManager struct { goals []Goal; mu sync.Mutex }`. |
|
||||
| growth_delta | 16KB | Go growth delta extraction. |
|
||||
| warm_router | 55KB | Go warm routing: scans memory store, scores relevance, builds context. The second biggest module. |
|
||||
|
||||
**Daily check**: the operator turn loop works end-to-end in Go — user sends a message, operator routes, dispatches to Rust kernels, returns a response.
|
||||
|
||||
### Wave 5c: Go memory operations (8 modules, ~8,240 lines) — Day 4
|
||||
|
||||
| Module | Size | HOW |
|
||||
|---|---|---|
|
||||
| memory_store | 99KB | Go SQLite operations via `mattn/go-sqlite3` (cgo) or `modernc.org/sqlite` (pure Go). `type MemoryStore struct { db *sql.DB }`. Methods: `AddEntry(entry)`, `SearchEntries(query)`, `GetEntry(id)`, `Supersede(id)`, `WashEntry(id)`. THIS IS THE BIGGEST SINGLE PORT — expect 3-5k lines of Go. |
|
||||
| curator | 70KB | Go memory curation: scans the store, identifies conflicts, promotes/demotes. `type Curator struct { store *MemoryStore; mu sync.Mutex }`. |
|
||||
| sleep_time | 38KB | Go sleep-time consolidation: runs during idle periods. Uses the consolidation kernel (Rust) for the compute. |
|
||||
| memory_consolidation | 31KB | Go consolidation orchestrator. Calls the Rust kernel (already ported) for the record assembly. |
|
||||
| persona_gate | 24KB | Go persona gating: checks responses against persona principles. |
|
||||
| abstraction | 22KB | Go abstraction: fact extraction (kernel already in Rust). |
|
||||
| witness | 15KB | Go witness: signal extraction + reflection dispatch. |
|
||||
| stage_guards | 12KB | Go stage guards: readiness/exit canaries for construction stages. |
|
||||
|
||||
**Daily check**: memory operations work end-to-end in Go, SQLite reads are byte-identical.
|
||||
|
||||
### Wave 6: The Rust deterministic backend (85 modules, ~25,218 lines) — Day 4-5
|
||||
|
||||
Three sub-waves. Each module becomes a `pub fn` in the appropriate crate.
|
||||
|
||||
**Wave 6a** (30 modules): structural core → `src/rust/construction/`
|
||||
- spine, structural_store, construction_decision, construction_interface, construction_commands, construction_intent, construction_mode, construction_pattern, construction_patterns_builtin, construction_projection, construction_depth, construction_activation, contracts, capability_broker, capability_fit, capability_ledger, audit_ledger, behaviour_ledger, claim_audit, outcome_ledger, build_basis, project_registry, system_registry, layout_contract, structural_migration, structural_model
|
||||
- HOW: each Python module's functions become `pub fn` in a shared `construction` crate. Data structures become Rust structs with serde. The Python module becomes a thin FFI caller via the existing `sc_loader` pattern.
|
||||
|
||||
**Wave 6b** (30 modules): cognition layer → `src/rust/cognition/`
|
||||
- drift_core, drift_compression (already in Rust), drift_cache, drift_ledger, drift_observability, drift_resume, graph_memory, graph_projection, memory_selector, identity_anchors, pins (already in Rust), salience_gate, self_improve, token_optimizer, cognitive_budgeter, context_pressure, inference_trace, recall_uplift, response_adapter, route_risk_flags, rune_profiler, rune_spinner, safety_override (already in Rust), shard_manager, progressive_escalation, failure_recovery, intent_continuity, impact_preview, iteration, task_gate
|
||||
- HOW: each module's deterministic functions become `pub fn` in the `cognition_core` crate (extending the existing broker.rs).
|
||||
|
||||
**Wave 6c** (25 modules): remaining → the appropriate crate
|
||||
- voice_hybrid, voice_sync, prompt_sync, time_awareness, toolchain, verification_layer, task_persist, testing_mode, wait_guard, wait_guard_corpus, warm_neuron_store, layout_contract, structural_migration, structural_model, programme_continuation, programme_gates, subconscious_pass, attention_capsule, dependency_tracker, ffi_query_memory_smoke
|
||||
- HOW: same pattern — Rust `pub fn` in the appropriate crate, Python FFI caller.
|
||||
|
||||
**Daily check**: each crate compiles, its tests pass, the Python delegation works.
|
||||
|
||||
### Wave 7: Bubble Tea TUI (Go) — Day 5
|
||||
|
||||
| What | Python lines | Go target |
|
||||
|---|---|---|
|
||||
| rune_tui.py (the whole TUI) | 4,038 | `src/go/tui/` |
|
||||
|
||||
**HOW:**
|
||||
1. Install Bubble Tea + Lipgloss + Bubbles: `go get github.com/charmbracelet/bubbletea github.com/charmbracelet/lipgloss github.com/charmbracelet/bubbles`
|
||||
2. Port the layout: `type Model struct { chatChan, taskChan ChannelView; workPane WorkPane; statusBar StatusBar }` — chat LEFT, task RIGHT
|
||||
3. Port the message rendering: chat bubbles with `lipgloss.Style{}.Foreground()`
|
||||
4. Port the command selector: Bubble Tea's `textinput` + `completions` component
|
||||
5. Port the keybindings: Ctrl+1 (chat), Ctrl+2 (task), Ctrl+3 (work pane)
|
||||
6. Port the status bar: version, mode, model, project, focused channel
|
||||
7. Port the post-response signal consolidation (one dim line)
|
||||
8. Wire the operator: the TUI calls the Go operator directly (same process) — no subprocess, no FFI, just function calls
|
||||
9. Animations: Bubble Tea supports animations via `tea.Tick` and `tea.Every` — spinners, progress bars, streaming text. Lipgloss supports colors, borders, padding. Pixel art is possible via block characters and custom rendering.
|
||||
10. Design: retain the current two-column layout (chat LEFT, task RIGHT) + work pane. Use Lipgloss for the same visual style. Port the chat bubble rendering, the thinking indicator, the tool call display.
|
||||
|
||||
**Exit condition**: `go build ./src/go/tui/` produces a statically-linked binary that IS the Rune TUI. `find src/rune -name '*.py'` returns 0.
|
||||
|
||||
---
|
||||
|
||||
## §4 — THE GITEA EPIC STRUCTURE
|
||||
|
||||
The FIRST task posted to Gitea is the parent epic:
|
||||
|
||||
**Epic #N: "Full Dichotomy Rebase — every Python module replaced"**
|
||||
|
||||
Folded checklist inside the epic:
|
||||
- [ ] Wave 0: Infrastructure (henxels scope, umbrella manifest, scaffolding protocol, CI update)
|
||||
- [ ] Wave 4: Go reactive infrastructure (14 modules) — sub-epics per module
|
||||
- [ ] Wave 4b: Go tool execution (3 modules) — sub-epics per module
|
||||
- [ ] Wave 5a: Go model/provider (10 modules) — sub-epics per module
|
||||
- [ ] Wave 5b: Go operator (19 modules) — sub-epics per module
|
||||
- [ ] Wave 5c: Go memory operations (8 modules) — sub-epics per module
|
||||
- [ ] Wave 6a: Rust structural core (30 modules) — sub-epics per module
|
||||
- [ ] Wave 6b: Rust cognition (30 modules) — sub-epics per module
|
||||
- [ ] Wave 6c: Rust remaining (25 modules) — sub-epics per module
|
||||
- [ ] Wave 7: Bubble Tea TUI (7 modules) — sub-epics per module
|
||||
|
||||
Each sub-epic contains the HOW instructions per the template in §3.
|
||||
|
||||
MiMoCode task tool mirrors the same structure: T-tranche → T4-infra → T4.1-event-bus, T4.2-hook-engine, etc.
|
||||
|
||||
---
|
||||
|
||||
## §5 — BUBBLE TEA CAPABILITIES (answering Nick's question)
|
||||
|
||||
**Animations**: Yes. Bubble Tea has `tea.Tick` (one-shot timer) and `tea.Every` (recurring). Spinners via the `bubbles/spinner` component. Progress bars via `bubbles/progress`. Streaming text via incremental updates.
|
||||
|
||||
**Pixel art**: Possible via block characters (█ ▄ ▀ ▌ ▐) and custom renderers. Not true pixel-level control (it's a terminal), but with Unicode block elements and 256-color/truecolor support, you can get very close. Lipgloss supports borders, padding, alignment, colors, and gradients.
|
||||
|
||||
**Presentable**: Yes. Bubble Tea + Lipgloss is what popular Go CLI tools use (gh, glow, soft-serve). It looks professional and modern.
|
||||
|
||||
**Retaining the current design**: The two-column layout (chat LEFT, task RIGHT), the work pane, the status bar, the command selector, the chat bubbles — all of these map directly to Bubble Tea components. The visual style can be replicated with Lipgloss. The keybindings map directly.
|
||||
|
||||
---
|
||||
|
||||
## §6 — TIMELINE
|
||||
|
||||
| Day | Waves | Modules | Lines |
|
||||
|---|---|---|---|
|
||||
| Day 1 (morning) | Wave 0 | Infrastructure | N/A (config changes) |
|
||||
| Day 1-2 | Wave 4 + 4b | 17 Go modules | ~8,350 |
|
||||
| Day 2-3 | Wave 5a + 5b | 29 Go modules | ~13,035 |
|
||||
| Day 4 | Wave 5c | 8 Go modules | ~8,240 |
|
||||
| Day 4-5 | Wave 6a + 6b + 6c | 85 Rust modules | ~25,218 |
|
||||
| Day 5 | Wave 7 | 7 Bubble Tea modules | ~5,435 |
|
||||
| **Total** | **5 days** | **180 modules** | **~68,224** |
|
||||
|
||||
---
|
||||
|
||||
## §7 — APPROVAL GATE
|
||||
|
||||
Read this. Argue with it. Approve or request changes. Once approved, execution starts at Wave 0 (infrastructure first, because it impacts everything else).
|
||||
@@ -1,354 +0,0 @@
|
||||
# TRANCHE v3: THE FULL DICHOTOMY REBASE — with HOW, with language advantages, with automated verification
|
||||
|
||||
Nick's corrections applied:
|
||||
- Umbrella manifest feeds the spine (not superseded); both need updating
|
||||
- construction_decision.py itself gets ported (Go start + Rust execution)
|
||||
- Language advantages are part of every port — improvements where the target language is better
|
||||
- Automated parity verification BEFORE gutting the Python (hard gate, no manual checking)
|
||||
- A testing document that proves bigger features work after each wave
|
||||
- Maximise Bubble Tea addons (research the ecosystem)
|
||||
- No arbitrary timeframe — it gets done when it gets done
|
||||
- Every task follows on to the next — never stopping
|
||||
- CI stacking: keep submitting PRs; address CI issues in batches of 5, not individually
|
||||
|
||||
---
|
||||
|
||||
## THE CORE MECHANISM: How every module gets replaced
|
||||
|
||||
Every module follows the same seven-step process. No exceptions. The process IS the verification.
|
||||
|
||||
### Step 1: Understand the Python module
|
||||
Read every function. Identify: what does it compute (→ Rust), what does it initiate (→ Go), what does it store (→ Rust), what does it route (→ Go). Note every caller. Note every file it reads/writes.
|
||||
|
||||
### Step 2: Write the replacement in the target language
|
||||
For Rust: a `pub fn` in the appropriate crate, with serde-compatible structs.
|
||||
For Go: a method on a struct in the appropriate `src/go/<name>/` package.
|
||||
|
||||
**Language advantage check**: at this step, ask "does Go/Rust do this BETTER than Python did?" If yes, implement the improvement. Examples: Go goroutines replace Python threading for parallel operations. Rust's zero-cost abstractions replace Python duck typing for hot-path scoring. Go's `net/http` replaces Python `urllib` for model connections with connection pooling and keep-alive.
|
||||
|
||||
### Step 3: Write the parity test (RED first)
|
||||
Before touching the Python module, write a test that runs the same input through BOTH the Python oracle and the new Go/Rust implementation, and asserts the outputs are identical. This test must FAIL before the implementation is correct, and PASS once it is. The test is the gate.
|
||||
|
||||
### Step 4: Verify parity — the HARD GATE
|
||||
Run the parity test. If it passes, the replacement is PROVEN to work. Only now can you proceed to Step 5. If it fails, debug the Go/Rust implementation until it passes. **Do not gut the Python until this gate passes.** This is automated — you never have to manually check.
|
||||
|
||||
### Step 5: Rewire the Python module as a delegation shim
|
||||
Replace the Python function body with a call to the Go binary (subprocess) or the Rust kernel (ctypes/cgo). Every existing caller of the Python module keeps working — they don't know the implementation changed.
|
||||
|
||||
### Step 6: Register the canary in CI
|
||||
The parity test from Step 3 is registered in `.gitea/workflows/ci.yml`. Now every future commit is checked against the parity contract automatically.
|
||||
|
||||
### Step 7: PR → CI → merge
|
||||
Push the branch, let CI run. If CI raises issues, DON'T STOP — continue to the next module's port. Address CI issues in batches of 5. The pipeline is proven; it catches things; you fix them in batches.
|
||||
|
||||
**The key insight**: Step 4 (the parity gate) is the answer to "how do you confirm replacements working before you gut it?" You don't gut anything until the automated test proves the replacement produces identical output. The test is the contract.
|
||||
|
||||
---
|
||||
|
||||
## THE TESTING DOCUMENT: proving bigger features after each wave
|
||||
|
||||
After each wave completes, a WAVE VERIFICATION DOCUMENT is produced that proves the system works end-to-end. Not unit tests — integration tests.
|
||||
|
||||
### What it contains:
|
||||
1. **The operator turn loop works**: send a message through the Go operator, get a response back, verify the response is correct
|
||||
2. **Memory operations work**: store a memory, recall it, verify the content matches
|
||||
3. **Tool execution works**: execute a tool call, verify the output
|
||||
4. **The TUI renders**: launch the Bubble Tea TUI, verify it displays
|
||||
5. **The event journal works**: emit an event, read it back
|
||||
6. **The scaffolding works**: submit a need, verify the contract is created
|
||||
|
||||
### How it's generated — BY THE GITEA PIPELINE, not by the agent:
|
||||
A shell script (`scripts/wave_verify.sh`) is written by the agent. A CI workflow step runs the script after each wave merge. The CI step formats the results as markdown and posts them as a comment on the wave's Gitea epic. The document is permanent — attached to the epic, survives session restarts, reproducible (the commands are in the document), automated (CI runs it, not the agent).
|
||||
|
||||
### Implementation:
|
||||
- `scripts/wave_verify.sh` — the integration verification script
|
||||
- A CI workflow step (in ci.yml or a new `wave-verify.yml`) that runs the script and posts results to the Gitea epic using the existing GITEA_TOKEN secret
|
||||
- The same mechanism the merge-robot already uses for PR comments
|
||||
|
||||
### What "done" means for a wave:
|
||||
The wave's Gitea epic has a verification comment showing every integration path PASSING. The agent does not produce testing documents — the pipeline does.
|
||||
|
||||
### What "done" means for a wave:
|
||||
Not just "the code compiles" — the wave verification document shows every integration path working.
|
||||
|
||||
---
|
||||
|
||||
## WAVE 0: INFRASTRUCTURE (before any porting)
|
||||
|
||||
### 0.1 Henxels scope extension
|
||||
Open `henxels.yaml`. Add scopes for `src/rust/*/src/*.rs` and `src/go/**/*.go`. Same quality gates: max_lines, no_secrets, canary registration, coverage existence. Without this, new Go/Rust files have no governance.
|
||||
|
||||
### 0.2 Umbrella manifest extension
|
||||
The umbrella manifest IS the spine's input for non-module surfaces. Extend it:
|
||||
- Add the 10 existing Rust crates as `rust_crates` entries
|
||||
- Add the 2 existing Go modules as `go_surfaces` entries
|
||||
- Add placeholder entries for the planned Go modules
|
||||
- Every new Go/Rust file gets tracked, so the spine knows about it
|
||||
|
||||
### 0.3 Scaffolding protocol update (construction_decision.py port)
|
||||
`construction_decision.py` is itself a Python file. Port it:
|
||||
- **Go start call**: the CLI surface that receives the classification request
|
||||
- **Rust execution**: the deterministic classification logic (keyword matching, language placement)
|
||||
- The GO_SIGNALS and RUST_SIGNALS keyword lists are updated to match the corrected dichotomy
|
||||
- The Python version becomes a delegation shim
|
||||
- After this port, `rune scaffold classify` routes through Go→Rust, not Python
|
||||
|
||||
### 0.4 CI pipeline update
|
||||
- Build every Rust crate in the unit-tests job
|
||||
- Build every Go module in a new `go-build` job
|
||||
- Set CC_RUST_LIB, SC_RUST_LIB, etc. to the CARGO_TARGET_DIR paths
|
||||
- Add `go vet` and `go test ./...` steps
|
||||
|
||||
### 0.5 Gitea epic + MiMoCode tasks
|
||||
- Post the parent epic on Gitea: the full wave structure as a folded checklist
|
||||
- Post per-wave sub-epics
|
||||
- Mirror in MiMoCode's task tool
|
||||
- Every subsequent task updates both
|
||||
|
||||
---
|
||||
|
||||
## WAVE 4: GO REACTIVE INFRASTRUCTURE (14 modules)
|
||||
|
||||
### event_bus (244 lines) — DONE
|
||||
Already built as `src/go/event-bus/`. Reads/writes the same events.jsonl.
|
||||
|
||||
### event_envelope (303 lines)
|
||||
Merge into event-bus. The EventEnvelope struct already exists in Go. Add the OrchestrationRecord methods (to_dict, from_dict) as MarshalJSON/UnmarshalJSON. Add the content_hash function.
|
||||
|
||||
### message_queue (10KB)
|
||||
**What it does**: holds approved messages until they're executed. The Python version uses a JSONL file with a mutex.
|
||||
**Go advantage**: Go channels are designed for this. Use a buffered channel for in-memory queue + a JSONL file for durability. The Go version is concurrent-safe by construction.
|
||||
**HOW**: Create `src/go/message-queue/`. Define `type Message struct` with the same fields as the Python version. Implement `Enqueue`, `Dequeue`, `GetApproved`, `MarkExecuted`. The Python module becomes a subprocess shim.
|
||||
**Parity test**: enqueue 10 messages in Python, read them in Go, verify identical.
|
||||
|
||||
### hook_engine (28KB)
|
||||
**What it does**: loads plugin hooks from a config, fires them on events.
|
||||
**Go advantage**: goroutines enable parallel hook dispatch (Python's GIL prevents this).
|
||||
**HOW**: Create `src/go/hook-engine/`. `type HookEngine struct { hooks map[string][]HookFunc; mu sync.RWMutex }`. `Fire(name, data)` iterates hooks sequentially; `FireAsync` dispatches each hook in a goroutine and collects errors via channels.
|
||||
**Language advantage**: parallel hook dispatch — Python can't do this due to the GIL.
|
||||
|
||||
### microkernel (14KB)
|
||||
**What it does**: the plugin lifecycle — register, activate, dispatch.
|
||||
**Go advantage**: Go interfaces replace Python duck typing with compile-time guarantees.
|
||||
**HOW**: `type Plugin interface { Name() string; Capabilities() []string; OnMessage(data) error }`. Registry with `Register(p Plugin)`, `Fire(event, data)`. The hook_engine plugs into this.
|
||||
|
||||
### subsystem_health (6KB)
|
||||
**What it does**: tracks failures per subsystem, escalates tiers.
|
||||
**HOW**: `type SubsystemHealth struct { failures map[string][]Failure }`. RecordFailure, GetHealth. Write to JSON for durability.
|
||||
|
||||
### parallel_processor (5KB)
|
||||
**What it does**: runs operations in parallel.
|
||||
**Go advantage**: goroutines + sync.WaitGroup. This is what Go was BORN for.
|
||||
**HOW**: `func ParallelMap[T, R any](items []T, fn func(T) R) []R`. Launch goroutines, collect via channels.
|
||||
|
||||
### work_manager (20KB)
|
||||
**What it does**: manages work dispatch to builders.
|
||||
**HOW**: Go worker pool with `chan Task`. `type WorkManager struct { workers int; queue chan Task; results chan TaskResult }`. Start, Submit, Stop.
|
||||
|
||||
### failure_auto_filer (21KB)
|
||||
**What it does**: auto-files failures to the forge.
|
||||
**HOW**: Go struct with spool file + forge client. Same pattern as the existing forge_client.
|
||||
|
||||
### cache (16KB) + connection_pool (3KB)
|
||||
**What they do**: cache responses, pool connections.
|
||||
**Go advantage**: Go's `sync.Map` and channel-based pools are built for this.
|
||||
**HOW**: `src/go/cache/` — LRU cache with `sync.RWMutex`. `src/go/connection-pool/` — channel-based pool.
|
||||
|
||||
### cron_engine (14KB) + night_mode (14KB)
|
||||
**What they do**: scheduled tasks, night consolidation.
|
||||
**Go advantage**: `time.Ticker` + goroutines replace Python's threading.Timer.
|
||||
**HOW**: `src/go/cron-engine/` — task list with cron expressions. `src/go/night-mode/` — uses the cron engine for scheduled consolidation.
|
||||
|
||||
### recall_router (5KB)
|
||||
**What it does**: routes recall queries to the right memory backend.
|
||||
**HOW**: `src/go/recall-router/` — routing table with `map[string]RecallFn`.
|
||||
|
||||
---
|
||||
|
||||
## WAVE 4b: GO TOOL EXECUTION (3 modules)
|
||||
|
||||
### tool_executor (73KB) — STARTED
|
||||
The Go binary already handles read_file, list_directory, glob_files, grep_files, run_command. Add the remaining operations: write_file (with path validation), edit_file (with diff preview), run_tests, lint_file, git_commit, git_diff, git_log, repo_map, and the query/diagnose operations.
|
||||
**Language advantage**: Go's `os/exec` with `context.Context` for timeouts is cleaner than Python's `subprocess.run(timeout=)`. Go's goroutines enable parallel tool execution (Python serialises them).
|
||||
|
||||
### tool_protocol (16KB)
|
||||
Go types: `ToolRequest`, `ToolEvent`. Validation against a schema registry. The approval boundary stays in the Go operator (not Python).
|
||||
|
||||
### local_tool_runtime (35KB)
|
||||
The Go loop: receive model response → parse tool calls → validate → dispatch to executor → feed results back. `type LocalToolRuntime struct { transport Transport; tools []ToolDef; maxIterations int }`. This is the loop that makes Rune respond to tool results.
|
||||
|
||||
---
|
||||
|
||||
## WAVE 5a: GO MODEL/PROVIDER (10 modules → 1 binary)
|
||||
|
||||
All 10 modules collapse into `src/go/model-connect/`.
|
||||
|
||||
**Language advantage**: Go's `net/http` with connection pooling and keep-alive replaces Python's `urllib` (which opens a new connection per request). Go's goroutines enable parallel model calls (Python serialises them). Go's `context.Context` enables timeout propagation through the call chain.
|
||||
|
||||
### model_connect (16KB)
|
||||
`type OllamaClient struct { baseURL string; client *http.Client }`. Chat, Show, Pull, ListModels. Use `net/http` with a shared transport for connection reuse.
|
||||
|
||||
### model_routing (16KB) + model_registry (6KB) + model_profiles (16KB)
|
||||
Go router that scores tasks against model capabilities and routes to the right model. One `ModelRouter` struct replaces three Python files.
|
||||
|
||||
### provider_budget (12KB)
|
||||
Go budget tracker with `sync.Mutex`. Record, GetStatus. Token counting per provider.
|
||||
|
||||
### provider_registry (23KB) + standardized_providers (9KB) + provider_context (2KB)
|
||||
Go `Provider` interface with OllamaProvider and CompatProvider implementations. Registry manages connections.
|
||||
|
||||
### tiered_executor (9KB)
|
||||
Go executor with tier escalation. Execute, Escalate.
|
||||
|
||||
---
|
||||
|
||||
## WAVE 5b: GO OPERATOR (19 modules → 1 binary)
|
||||
|
||||
**rune_operator (126KB)** — the turn loop. This is the hardest port.
|
||||
**How**: break it into sub-systems. Port each one at a time. After each, run the full test suite.
|
||||
1. The state management (RuneState, TaskStateRepo, ConversationRepo) → Go structs with JSON persistence
|
||||
2. The turn loop → Go function: `Respond(channel, message) OperatorResponse`
|
||||
3. The routing → Go AdaptiveRouter
|
||||
4. The tool dispatch → Go LocalToolRuntime (already ported in Wave 4b)
|
||||
5. The memory interaction → Go MemoryStore (Wave 5c) + Rust kernels via cgo
|
||||
6. The model connection → Go ModelConnect (Wave 5a)
|
||||
|
||||
**Language advantage**: Go goroutines replace Python threading for parallel context gathering. Go channels replace Python queues. Go's `context.Context` replaces Python's ad-hoc timeout management. The turn loop becomes truly concurrent — memory recall and model inference can overlap.
|
||||
|
||||
**The other 18 modules** are supporting cast: adaptive_router (23KB), build_mode (20KB), builder_bridge (12KB), core_server (9KB), auto_context (8KB), auto_tasks (15KB), event_wait (23KB), evidence_probe (7KB), forge (5KB), forge_client (7KB), goal (14KB), growth_delta (16KB), warm_router (55KB), release_notes (18KB), persona_definition (7KB), voicebox (4KB), voice_injector (3KB). Each follows the same pattern: read Python → write Go → parity test → rewire → commit.
|
||||
|
||||
---
|
||||
|
||||
## WAVE 5c: GO MEMORY OPERATIONS (8 modules)
|
||||
|
||||
### memory_store (99KB) — THE BIGGEST SINGLE PORT
|
||||
**What it does**: every SELECT, INSERT, UPDATE, DELETE against the memory database.
|
||||
**Go advantage**: `modernc.org/sqlite` is pure Go — no cgo, no C compiler, cross-compiles trivially. Go's `database/sql` interface with prepared statements is cleaner than Python's raw sqlite3.
|
||||
**HOW**: `type MemoryStore struct { db *sql.DB }`. Every Python function becomes a Go method. The SQL statements ARE the specification.
|
||||
**Parity test**: same SQLite file, same queries, byte-identical results. Run after every operation.
|
||||
|
||||
### curator (70KB)
|
||||
Scans the store, identifies conflicts, promotes/demotes. Go state machine.
|
||||
|
||||
### sleep_time (38KB)
|
||||
Idle-period consolidation. Go goroutine on a timer.
|
||||
|
||||
### memory_consolidation (31KB)
|
||||
Calls the Rust kernel (already ported). Go handles the I/O.
|
||||
|
||||
### The other 4 (persona_gate, abstraction, witness, stage_guards)
|
||||
Each follows the same pattern.
|
||||
|
||||
---
|
||||
|
||||
## WAVE 6: RUST BACKEND (85 modules)
|
||||
|
||||
Each Python module's pure functions become `pub fn` in the appropriate crate.
|
||||
|
||||
**The pattern for each:**
|
||||
1. Read the Python module, identify pure functions
|
||||
2. Write the Rust equivalent in the crate
|
||||
3. Add an FFI symbol
|
||||
4. Write a parity test
|
||||
5. The Python module becomes a thin FFI caller
|
||||
|
||||
**The rhythm**: most modules are 3-10KB. At that size, a port takes 15-30 minutes once you're in the rhythm. 85 modules at that pace is 2-3 days of focused work.
|
||||
|
||||
**Language advantage**: Rust's type system catches bugs at compile time that Python catches at runtime. Rust's `Result<T, E>` replaces Python's try/except for error handling. Rust's pattern matching replaces Python's if/elif chains. Rust's zero-cost abstractions mean the ports are FASTER than the Python originals.
|
||||
|
||||
---
|
||||
|
||||
## WAVE 7: BUBBLE TEA TUI (Go)
|
||||
|
||||
### Maximising the Bubble Tea ecosystem
|
||||
|
||||
Research the full Bubble Tea + Lipgloss + Bubbles ecosystem for every available addon:
|
||||
|
||||
**Bubble Tea** (the runtime): Elm architecture, goroutine-safe, tea.Tick for animations, tea.Every for recurring updates, tea.WithAltScreen for fullscreen, tea.WithMouseCellMotion for mouse support.
|
||||
|
||||
**Lipgloss** (styling): truecolor (16.7M colors), borders (rounded, thick, double, hidden), padding/margin/width/height, alignment, flex layout, gradients, inline styling, copy/blend styles.
|
||||
|
||||
**Bubbles** (pre-built components):
|
||||
- `spinner`: rotating indicators (line, dot, mini-dot, jump, pulse, points, globe, moon, monkey, meter, hamburger, ellipsis)
|
||||
- `progress`: animated progress bars with gradient colors
|
||||
- `textinput`: text input with cursor, placeholder, validation
|
||||
- `textarea`: multi-line text input
|
||||
- `table`: sortable, selectable data tables
|
||||
- `list`: filtered, paginated lists
|
||||
- `viewport`: scrollable content area
|
||||
- `paginator`: pagination controls
|
||||
- `key`: key binding documentation
|
||||
- `help`: help bubble
|
||||
- `timer`: countdown timer
|
||||
- `stopwatch`: elapsed time
|
||||
|
||||
**Additional libraries in the ecosystem:**
|
||||
- `glamour`: markdown rendering with syntax highlighting (for chat messages that contain code)
|
||||
- `harmonica`: spring animation physics (for smooth pane transitions)
|
||||
- `bubble-lipgloss-extras`: additional styling utilities
|
||||
|
||||
**What the current TUI has that maps:**
|
||||
- Two-column layout (chat LEFT, task RIGHT) → `lipgloss.JoinHorizontal()` with width ratios
|
||||
- Chat bubbles with sender name, timestamp, content → custom component with `lipgloss.Style{}.Border(lipgloss.RoundedBorder()).Padding(0, 1)`
|
||||
- Thinking indicator (spinner) → `bubbles/spinner` with the pulse style
|
||||
- Tool call display → bordered component with syntax highlighting via `glamour`
|
||||
- Status bar (version, mode, model, project) → fixed bottom bar via `lipgloss.JoinVertical()`
|
||||
- Command selector with autocomplete → `bubbles/textinput` + custom suggestion loop
|
||||
- Work pane (operational index) → side panel with `bubbles/list`
|
||||
- Scrollback → `bubbles/viewport` with `SetContent()` and `GotoBottom()`
|
||||
- Keybindings → `tea.KeyMap` with `tea.KeyCtrl1`, `tea.KeyCtrl2`, `tea.KeyCtrl3`
|
||||
- Streaming text → `tea.Cmd` that sends partial string updates
|
||||
- Growth/status widgets → `bubbles/table` or custom rendering
|
||||
|
||||
**Improvements the language enables:**
|
||||
- True concurrent streaming: the Go operator can push partial results to the TUI via Go channels while the model is still generating — Python can't do this because the GIL serialises everything
|
||||
- Sub-millisecond rendering: Go's zero-allocation string building means the TUI renders at 60fps without GC pauses
|
||||
- Statically linked binary: deploy the TUI as a single file, no Python runtime, no virtual environment, no pip install
|
||||
|
||||
---
|
||||
|
||||
## CI STACKING PROTOCOL
|
||||
|
||||
The CI pipeline is proven — 2,300+ tests, 25 canaries, required checks on master. Use it as a throughput engine:
|
||||
|
||||
1. Submit PR after PR after PR. Don't wait for one to merge before starting the next.
|
||||
2. If CI raises an issue, DON'T STOP the current work. Note it, continue.
|
||||
3. After every 5 PR submissions, go back and address the accumulated CI issues in one batch.
|
||||
4. The merge-robot and auto-version handle the merging — you keep producing.
|
||||
5. If a required check fails on master, that's the one thing that stops the conveyor. Fix it immediately.
|
||||
|
||||
**The principle**: CI is the quality gate, not the bottleneck. It runs while you work. Issues get batch-fixed. The conveyor keeps moving.
|
||||
|
||||
---
|
||||
|
||||
## GITEA EPIC STRUCTURE
|
||||
|
||||
The FIRST Gitea task: **Epic: "Full Dichotomy Rebase"** containing:
|
||||
- [ ] Wave 0: Infrastructure (henxels scope, umbrella manifest, scaffolding protocol, CI)
|
||||
- [ ] Wave 4: Go reactive infrastructure (14 sub-epics)
|
||||
- [ ] Wave 4b: Go tool execution (3 sub-epics)
|
||||
- [ ] Wave 5a: Go model/provider (10 sub-epics, folded into 1 binary)
|
||||
- [ ] Wave 5b: Go operator (19 sub-epics, folded into 1 binary)
|
||||
- [ ] Wave 5c: Go memory operations (8 sub-epics)
|
||||
- [ ] Wave 6a: Rust structural core (30 sub-epics)
|
||||
- [ ] Wave 6b: Rust cognition (30 sub-epics)
|
||||
- [ ] Wave 6c: Rust remaining (25 sub-epics)
|
||||
- [ ] Wave 7: Bubble Tea TUI (7 sub-epics)
|
||||
|
||||
Each sub-epic contains the HOW instructions (the seven-step process), the language advantage notes, the parity test spec, and the CI registration step.
|
||||
|
||||
MiMoCode tasks mirror the same tree.
|
||||
|
||||
---
|
||||
|
||||
## WHAT I STILL NEED FROM YOU
|
||||
|
||||
1. **The cgo pattern** — Go calls Rust `.so` files via cgo. The Rust crates don't change, only the caller changes from Python-ctypes to Go-cgo. Is this the membrane you want?
|
||||
|
||||
2. **The Bubble Tea ecosystem** — I've listed every addon above. Do you want any specific visual features beyond what's listed?
|
||||
|
||||
3. **The umbrella answer** — the spine relies on umbrellas (umbrellas are the input, spine is the consumer). Both need updating. Is this how you understood it?
|
||||
|
||||
4. **The CI stacking** — submit PRs continuously, batch CI fixes every 5 submissions. Does this match what you described?
|
||||
|
||||
5. **Approve to start Wave 0** — henxels scope, umbrella manifest, scaffolding protocol, CI update, Gitea epic. This is the foundation everything else builds on.
|
||||
@@ -1,274 +0,0 @@
|
||||
# TRANCHE: THE FULL DICHOTOMY REBASE — every Python module replaced
|
||||
|
||||
_Presented for operator approval per TRANCHE-TEMPLATE.md §4. Nick's mandate: "go through the whole codebase and replace it with the dichotomy." Measured: 180 Python files, 68,224 lines. Target: 0 Python logic files (TUI stays last per plan, test infra stays as test infra)._
|
||||
|
||||
---
|
||||
|
||||
## §0 — GROUNDING (measured, not guessed)
|
||||
|
||||
### The honest numbers
|
||||
|
||||
| Language | Files | Lines | % | Status |
|
||||
|---|---|---|---|---|
|
||||
| Python | 180 | 68,224 | 70% | **THE TARGET — every module ported** |
|
||||
| Rust | 106 | 27,304 | 28% | 10 crates exist, 85 more modules to port |
|
||||
| Go | 7 | 1,125 | 1% | 2 modules exist, 55 more to port |
|
||||
| **Total** | **293** | **96,653** | | |
|
||||
|
||||
### The corrected dichotomy (re-classified 2026-10-06, 64ba7cf)
|
||||
|
||||
| Side | Modules | Python lines to replace | Role |
|
||||
|---|---|---|---|
|
||||
| **GO** | 57 | 32,081 | The reactive shell: initiates, responds, routes, interfaces |
|
||||
| **RUST** | 85 | 25,218 | The deterministic backend: computes, stores, pure functions |
|
||||
| **TUI** | 7 | 5,435 | Textual UI — last per plan |
|
||||
| **TEST** | 29 | 5,397 | Test infrastructure — stays as test infra |
|
||||
|
||||
### Existing infrastructure (§0.2 — route through what exists)
|
||||
|
||||
- **CI pipeline**: `.gitea/workflows/ci.yml` — lint, unit-tests, go-surface, canary, best-practices, documentation, type-check, gitea-offline, required-checks
|
||||
- **Deploy pipeline**: `.gitea/workflows/deploy.yml` — event-driven CI qualification, stage/verify/promote
|
||||
- **Scaffolding**: `construction_interface.py` + `src/go/rune-entry/scaffold.go` — every module's port goes through a construction contract
|
||||
- **Canaries**: 25 registered in CI, each crate has its own parity battery
|
||||
- **Umbrella manifest**: `config/umbrellas.json` — 165 Python modules tracked (needs Rust/Go extension)
|
||||
- **Henxels**: `henxels.yaml` — structural contract, line caps, no-secrets, canary registration (needs Rust/Go scope)
|
||||
- **Gitea**: conductor/rune, required checks on master, merge-robot, auto-version
|
||||
|
||||
### Keep-greens (§0.5 — must stay green through every wave)
|
||||
|
||||
- Full test suite: 2,300+ tests, 0 failures
|
||||
- All 25 registered canaries
|
||||
- diff-cover ≥70% on changed lines
|
||||
- Silent-handler ratchet (BLE001 ≤345, S110 ≤75)
|
||||
- Henxels: all hold
|
||||
- Lint-baseline: no increase
|
||||
- Deploy: monotonic promotion, runtime verification
|
||||
|
||||
---
|
||||
|
||||
## §1 — OBJECTIVE
|
||||
|
||||
**Every Python module in `src/rune/` is replaced by its Go or Rust equivalent per the dichotomy. The TUI stays Python until Wave 7. Test infrastructure stays Python. The FFI boundary is the membrane between Go and Rust. Zero Python logic files remain (only the TUI shell and test files).**
|
||||
|
||||
Measured end-state: `ls src/rune/*.py | wc -l` returns ≤7 (TUI only) + test files. `src/go/` contains the full reactive runtime. `src/rust/` contains the full deterministic backend.
|
||||
|
||||
---
|
||||
|
||||
## §2 — WAVE STRUCTURE
|
||||
|
||||
### Wave 4: The Go reactive infrastructure (14 modules, ~5,271 lines)
|
||||
|
||||
The backbone that everything else routes through. These are the modules that make the system *respond*.
|
||||
|
||||
| Module | Python lines | Go target | Notes |
|
||||
|---|---|---|---|
|
||||
| event_bus | 244 | **DONE** (src/go/event-bus/) | Same events.jsonl, same envelope |
|
||||
| event_envelope | 303 | src/go/event-bus/ | Envelope type in the same binary |
|
||||
| message_queue | 10KB | src/go/message-queue/ | Durable queue |
|
||||
| hook_engine | 28KB | src/go/hook-engine/ | Plugin dispatch |
|
||||
| microkernel | 14KB | src/go/microkernel/ | Hook lifecycle |
|
||||
| subsystem_health | 6KB | src/go/subsystem-health/ | Failure tiers |
|
||||
| parallel_processor | 5KB | src/go/parallel-processor/ | Goroutines |
|
||||
| work_manager | 20KB | src/go/work-manager/ | Work dispatch |
|
||||
| failure_auto_filer | 21KB | src/go/failure-filer/ | Auto-filing |
|
||||
| cache | 16KB | src/go/cache/ | Connection pooling |
|
||||
| connection_pool | 3KB | src/go/connection-pool/ | Pooled connections |
|
||||
| cron_engine | 14KB | src/go/cron-engine/ | Scheduled tasks |
|
||||
| night_mode | 14KB | src/go/night-mode/ | Night consolidation |
|
||||
| recall_router | 5KB | src/go/recall-router/ | Memory routing |
|
||||
|
||||
**Entry condition**: event_bus already landed. **Exit condition**: all 14 modules exist as Go binaries, Python versions delegate or are deleted, CI go-surface job passes.
|
||||
|
||||
### Wave 4b: The Go tool execution layer (3 modules, ~3,079 lines)
|
||||
|
||||
| Module | Python lines | Go target |
|
||||
|---|---|---|
|
||||
| tool_executor | 73KB | **STARTED** (src/go/tool-executor/) |
|
||||
| tool_protocol | 16KB | src/go/tool-executor/ |
|
||||
| local_tool_runtime | 35KB | src/go/tool-executor/ |
|
||||
|
||||
**Exit condition**: tool executor handles all operations in Go, Python delegates via subprocess, approval machinery documented.
|
||||
|
||||
### Wave 5a: The Go model/provider layer (10 modules, ~3,398 lines)
|
||||
|
||||
| Module | Python lines | Go target |
|
||||
|---|---|---|
|
||||
| model_connect | 16KB | src/go/model-connect/ |
|
||||
| model_profiles | 16KB | src/go/model-connect/ |
|
||||
| model_registry | 6KB | src/go/model-connect/ |
|
||||
| model_routing | 16KB | src/go/model-connect/ |
|
||||
| openai_compat_transport | 10KB | src/go/model-connect/ |
|
||||
| provider_budget | 12KB | src/go/model-connect/ |
|
||||
| provider_context | 2KB | src/go/model-connect/ |
|
||||
| provider_registry | 23KB | src/go/model-connect/ |
|
||||
| standardized_providers | 9KB | src/go/model-connect/ |
|
||||
| tiered_executor | 9KB | src/go/model-connect/ |
|
||||
|
||||
**Exit condition**: all model/provider operations in Go, Ollama + OpenAI-compatible connections working.
|
||||
|
||||
### Wave 5b: The Go operator (19 modules, ~9,637 lines)
|
||||
|
||||
The biggest wave. The operator turn loop, routing, and the modules that serve it.
|
||||
|
||||
| Module | Python lines | Notes |
|
||||
|---|---|---|
|
||||
| rune_operator | 126KB | THE core — turn loop, task management |
|
||||
| adaptive_router | 23KB | Route decisions |
|
||||
| build_mode | 20KB | Build orchestration |
|
||||
| builder_bridge | 12KB | Builder dispatch |
|
||||
| builder_bridge_cli | 1KB | CLI surface |
|
||||
| core_server | 9KB | HTTP server |
|
||||
| persona_definition | 7KB | Persona loading |
|
||||
| voicebox | 4KB | Voice |
|
||||
| voice_injector | 3KB | Voice injection |
|
||||
| release_notes | 18KB | Release generation |
|
||||
| auto_context | 8KB | Auto context |
|
||||
| auto_tasks | 15KB | Auto tasks |
|
||||
| event_wait | 23KB | Event-driven waits |
|
||||
| evidence_probe | 7KB | Evidence probes |
|
||||
| forge | 5KB | Forge adapter |
|
||||
| forge_client | 7KB | Forge client |
|
||||
| goal | 14KB | Goal management |
|
||||
| growth_delta | 16KB | Growth tracking |
|
||||
| warm_router | 55KB | Warm routing |
|
||||
|
||||
**Exit condition**: the operator turn loop runs in Go, routes through Go model connections, dispatches to Rust kernels via FFI.
|
||||
|
||||
### Wave 5c: The Go memory operations (8 modules, ~8,240 lines)
|
||||
|
||||
| Module | Python lines | Notes |
|
||||
|---|---|---|
|
||||
| memory_consolidation | 31KB | Consolidation operations (kernel already in Rust) |
|
||||
| memory_store | 99KB | THE memory store — SQLite operations |
|
||||
| curator | 70KB | Memory curation |
|
||||
| sleep_time | 38KB | Sleep-time consolidation |
|
||||
| abstraction | 22KB | Fact extraction (kernel already in Rust) |
|
||||
| persona_gate | 24KB | Persona gating |
|
||||
| witness | 15KB | Witness reflection |
|
||||
| stage_guards | 12KB | Stage guards |
|
||||
|
||||
**Exit condition**: memory operations run in Go, calling Rust kernels for the deterministic compute.
|
||||
|
||||
### Wave 6: The Rust deterministic backend (85 modules, ~25,218 lines)
|
||||
|
||||
Three sub-waves by dependency order:
|
||||
|
||||
**Wave 6a** (30 modules, ~11,515 lines): the structural core — spine, structural_store, construction_*, contracts, capability_*, audit_ledger, behaviour_ledger, claim_audit, etc.
|
||||
|
||||
**Wave 6b** (30 modules, ~6,849 lines): the cognition layer — drift_*, graph_memory, memory_selector, identity_anchors, pins, salience_gate, self_improve, token_optimizer, etc.
|
||||
|
||||
**Wave 6c** (25 modules, ~6,854 lines): the remaining modules — voice_hybrid, voice_sync, prompt_sync, time_awareness, toolchain, verification_layer, etc.
|
||||
|
||||
**Exit condition**: every deterministic module exists as a Rust function in a crate, the Python version is a thin FFI caller or deleted.
|
||||
|
||||
### Wave 7: The TUI + test infrastructure (36 modules, ~10,832 lines)
|
||||
|
||||
The TUI stays Python (Textual is Python-native) but its backend calls go through the Go/Rust dichotomy. Test infrastructure stays Python (pytest is Python-native).
|
||||
|
||||
**Exit condition**: the TUI is the only Python surface, everything behind it is Go/Rust.
|
||||
|
||||
---
|
||||
|
||||
## §3 — PER-FILE EPIC TEMPLATE (§7 anti-ballooning: 180 files → per-file epics)
|
||||
|
||||
Each file's port gets ONE epic. The epic body contains:
|
||||
|
||||
1. **File identity**: `src/rune/<module>.py` — N lines, M functions, K classes
|
||||
2. **Three questions**: (a) can it be IMPROVED in the target language? (b) does it need FIXING? (c) are there MISSING CONNECTORS?
|
||||
3. **Language assessment**: confirmed GO/RUST per classification, with the evidence
|
||||
4. **Constraint context**: which henxels, line caps, canary requirements apply
|
||||
5. **Pipeline plan**: branch name, PR route, canary battery spec
|
||||
6. **Verification**: the specific tests + canaries that prove the port
|
||||
7. **Provenance**: links to the wave, the tranche, the classification record
|
||||
|
||||
---
|
||||
|
||||
## §4 — DECISION RUBRIC
|
||||
|
||||
Per-unit language decisions are made against:
|
||||
|
||||
1. **Does the module initiate/respond/route?** → Go
|
||||
2. **Does it compute/store/pure-function?** → Rust
|
||||
3. **Does it have BOTH?** → Hybrid: Go front end calls Rust kernel via FFI (contracted membrane junction)
|
||||
4. **Is it the TUI?** → Python (last)
|
||||
5. **Is it test infrastructure?** → Python (stays)
|
||||
|
||||
Evidence required: the module's actual imports, its primary purpose, its callers, and what breaks if it's removed.
|
||||
|
||||
---
|
||||
|
||||
## §5 — PIPELINE ROUTING
|
||||
|
||||
Every port flows through:
|
||||
|
||||
1. **Construction contract**: `rune scaffold submit-need` → decision → contract → building
|
||||
2. **Branch**: `feat/port-<module>-to-<lang>` from master
|
||||
3. **Implementation**: Go module in `src/go/<name>/` or Rust module in `src/rust/<crate>/`
|
||||
4. **Python oracle**: the original Python function preserved as `_py_<function>` for parity
|
||||
5. **Delegation**: the Python public delegates to the Go/Rust implementation
|
||||
6. **Canary**: a parity battery proving kernel↔oracle equivalence
|
||||
7. **CI**: the canary registered in `.gitea/workflows/ci.yml`
|
||||
8. **PR**: → master, required checks, merge-robot
|
||||
9. **Deploy**: auto-version bump, deploy pipeline, runtime verification
|
||||
|
||||
---
|
||||
|
||||
## §6 — VERIFICATION GATES
|
||||
|
||||
Per-wave exit:
|
||||
- All modules in the wave exist as Go/Rust implementations
|
||||
- Python versions delegate (or are deleted if nothing calls them)
|
||||
- CI go-surface job passes (for Go modules)
|
||||
- CI canary job passes (for Rust kernels)
|
||||
- Full test suite green
|
||||
- diff-cover ≥70% on changed lines
|
||||
- Deploy advances the current symlink
|
||||
|
||||
Per-tranche exit:
|
||||
- `ls src/rune/*.py` returns ≤7 files (TUI only)
|
||||
- Full test suite green
|
||||
- All canaries green
|
||||
- All henxels hold
|
||||
- Deploy verified at the final version
|
||||
|
||||
---
|
||||
|
||||
## §7 — RISK REGISTER
|
||||
|
||||
| Risk | Prevention | Detection |
|
||||
|---|---|---|
|
||||
| Big-bang rewrite breaks everything | Incremental waves, each independently deployable | CI red on any wave |
|
||||
| Dual-truth drift (Python and Go/Rust diverge) | Parity canaries, _py_ oracles | Canary failure |
|
||||
| Broken keep-greens | Named up front, checked per-wave | CI red |
|
||||
| Silent scope creep | Per-file epics with explicit scope | Code review |
|
||||
| FFI boundary breaks | CC_RUST_LIB/SC_RUST_LIB env contract | Kernel probe test |
|
||||
| Memory store data loss | SQLite retained, reads proven byte-identical | Canary hash check |
|
||||
| Operator turn loop regression | Full test suite + runtime verification | Deploy verification |
|
||||
| Henxels line-cap violations | Carve before commit (spine_language pattern) | CI lint red |
|
||||
| New module without canary | New-module henxel | CI lint red |
|
||||
|
||||
---
|
||||
|
||||
## §8 — ROLLBACK / KNOWN-GOOD
|
||||
|
||||
Each wave is independently deployable. If a wave breaks:
|
||||
1. The Python version is still in the tree (delegation, not deletion)
|
||||
2. `RUNE_COGNITION_CORE=python` pins the fallback
|
||||
3. The deploy symlink can be pointed back to the previous revision
|
||||
4. Git revert the wave's merge commit
|
||||
|
||||
---
|
||||
|
||||
## §9 — SCALE HONESTY
|
||||
|
||||
This is **weeks of work, not hours**. 180 modules at ~1-2 modules per session = 90-180 sessions. The previous attempt (R2) ported 10 crates + 2 Go modules in multiple sessions. This tranche is the FULL job.
|
||||
|
||||
The wave structure is designed for incremental progress: each wave is independently deployable, each module's port is independently verifiable, and the system works at every intermediate state. The Python versions delegate to the Go/Rust implementations — they don't get deleted until the port is proven.
|
||||
|
||||
---
|
||||
|
||||
## §10 — APPROVAL GATE
|
||||
|
||||
This tranche is presented for operator approval. The operator reads the wave structure, the module assignments, the per-wave exit conditions, and either approves (execution starts at Wave 4) or requests changes.
|
||||
|
||||
The previous attempt (R2) ported 10 crates + 2 Go modules — less than 10% of the codebase. This tranche is the FULL job: every module, every line, every language decision, with the dichotomy honestly applied.
|
||||
+2
-2
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "rune"
|
||||
version = "0.189.0"
|
||||
version = "0.99.5"
|
||||
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
@@ -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", "hypothesis>=6.100"]
|
||||
dev = ["pytest>=8.0", "pytest-subtests", "ruff==0.16.5", "pyright", "henxels==0.12.0", "coverage>=7.6", "diff-cover>=9.2"]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"errorCount": 121,
|
||||
"warningCount": 450,
|
||||
"errorCount": 117,
|
||||
"warningCount": 454,
|
||||
"informationCount": 0
|
||||
}
|
||||
+2
-6
@@ -34,14 +34,12 @@ httpcore==1.0.9
|
||||
# via httpx
|
||||
httpx==0.28.1
|
||||
# via rune (pyproject.toml)
|
||||
hypothesis==6.168.5
|
||||
# via rune (pyproject.toml)
|
||||
idna==3.20
|
||||
# via
|
||||
# anyio
|
||||
# httpx
|
||||
# yarl
|
||||
iniconfig==2.3.1
|
||||
iniconfig==2.3.0
|
||||
# via pytest
|
||||
jinja2==3.1.6
|
||||
# via diff-cover
|
||||
@@ -68,7 +66,7 @@ packaging==26.3
|
||||
# via pytest
|
||||
pillow==12.3.0
|
||||
# via rune (pyproject.toml)
|
||||
platformdirs==4.12.4
|
||||
platformdirs==4.12.3
|
||||
# via textual
|
||||
pluggy==1.6.0
|
||||
# via
|
||||
@@ -104,8 +102,6 @@ rich==15.0.0
|
||||
# textual
|
||||
ruff==0.16.5
|
||||
# via rune (pyproject.toml)
|
||||
sortedcontainers==2.4.0
|
||||
# via hypothesis
|
||||
sqlite-vec==0.1.9
|
||||
# via rune (pyproject.toml)
|
||||
textual==8.2.8
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
# Wave 1 / Memory & Persistence — Inward Intention Profile
|
||||
|
||||
Checkout: `/mnt/workdrive/rune`. Scope: `src/rune/` memory subsystem. Method: static reading of the
|
||||
live implementation plus inspection of on-disk state under `~/.rune/`. No code changed.
|
||||
|
||||
## On-disk state (measured)
|
||||
|
||||
| Artifact | Size | Status |
|
||||
|---|---|---|
|
||||
| `~/.rune/hot/task_state.json` | 973 KB | live production, hot path |
|
||||
| `~/.rune/hot/conversation_messages.json` | 1.2 MB | live production, hot path |
|
||||
| `~/.rune/consolidation/knowledge.json` | 3.4 MB | live production, batch path |
|
||||
| `~/.rune/outcome_ledger.db` | 12 KB | SQLite, small |
|
||||
| `~/.rune/memory/store/memory.db` | — | defined by `memory_env.store_db()`, not yet materialized locally |
|
||||
|
||||
## Cluster 1 — Hot-store JSON persistence
|
||||
|
||||
- Intention: load/save mutable runtime state as JSON files (task state, conversation messages, knowledge).
|
||||
- Evidence: live files listed above; consolidation loads/saves `knowledge.json` in
|
||||
`memory_consolidation.py:113-165` (JSON file load/save around the batch iterate/dedupe loop).
|
||||
- Compute profile: stdlib `json` encode/decode over 1–3.4 MB documents; CPU-bound but small in
|
||||
absolute terms (tens of ms, not seconds). No incremental/append format, full rewrite per save.
|
||||
- Language fit: **Python already delegates this well** — see outward source 1 (orjson wheel) for the
|
||||
upgrade path. A bespoke Rust CLI unit pays per-call subprocess spawn (contract: argv in / JSON out)
|
||||
that likely exceeds the serialization time it saves.
|
||||
|
||||
## Cluster 2 — SQLite store + FTS5/vec0 hybrid recall (`memory_store.py`)
|
||||
|
||||
- Intention: dense + sparse retrieval fused by RRF, with query expansion, metadata rerank, QPP
|
||||
abstention, drift rerank, map-reduce recall.
|
||||
- Evidence:
|
||||
- `memory_store.py:575-897` — `recall()`: hybrid dense+BM25 fused by Reciprocal Rank Fusion.
|
||||
- `memory_store.py:646` — dense KNN runs as SQLite virtual-table query: `SELECT ... FROM entries_vec v WHERE v.embedding MATCH ?` → **C inside SQLite** (sqlite-vec; outward source 3).
|
||||
- `memory_store.py:693` — sparse half ranks with `bm25(entries_fts)` → **C inside SQLite** (FTS5; outward source 5).
|
||||
- `memory_store.py:327-370` — `_embed()` shells out via subprocess `curl` to Ollama; network-bound, 60 s timeout. This, not Python, dominates recall latency.
|
||||
- `memory_store.py:475` — `_df()` runs a per-word LIKE COUNT query (N+1 smell) but is bounded: `probe_cap ≈ 2 × budget` entries (≈ 40), so total SQL traffic is tiny.
|
||||
- Python-side loops: RRF fusion over the small probe set, recency-decay/confidence/temperature multipliers, QPP abstention — per-item branching math over ≤ ~40 candidates.
|
||||
- Compute profile: the heavy kernels (KNN, BM25, ranking, tokenization) are already native C. Python is a thin orchestrator around them.
|
||||
- Language fit: a Go/Rust recode would replace thin Python glue around the same C extensions with
|
||||
Go/Rust glue around the same C extensions, while losing ecosystem integration (`sqlite3`, orjson,
|
||||
embedding plumbing). Outward sources 2, 3, 5 all point the same direction: keep SQLite, don't build custom storage/search.
|
||||
|
||||
## Cluster 3 — Neuron scoring / routing (`warm_router.py`)
|
||||
|
||||
- Intention: 7-signal heuristic scoring of memory "neurons" for routing: keyword substring match,
|
||||
embedding cosine, context overlap, ACT-R base-level activation, wash boost (log1p), fan penalty,
|
||||
trigger-length bonus.
|
||||
- Evidence: `warm_router.py:361-503` (`score_neuron`), `warm_router.py:504` (`route`).
|
||||
- Compute profile: the embedding cosine is computed via `memory_store._embed` (network HTTP to
|
||||
Ollama, precomputed once per neuron set). The remaining signals are trivial string ops and scalar
|
||||
arithmetic per neuron. Latency is dominated by the HTTP embed, not the scoring loop.
|
||||
- Language fit: branching heuristics over a small N with a network-bound dominate cost — no case for
|
||||
Go/Rust/C.
|
||||
|
||||
## Cluster 4 — Graph memory BFS (`graph_memory.py`)
|
||||
|
||||
- Intention: entity/relation graph persisted in SQLite (`edges`, `entities` tables); query walks BFS
|
||||
from seed entities up to `hops` (default 1); `graph_write` (:199) upserts.
|
||||
- Evidence: `graph_memory.py:261-343` (`query`), `graph_memory.py:199` (`graph_write`).
|
||||
- Compute profile: per-node SQL edge queries (N+1 pattern), but N is tiny (hops=1, few entities per
|
||||
seed). The per-query cost is SQLite C; Python overhead is negligible.
|
||||
- Language fit: keep Python. If the graph ever scales, the fix is a recursive CTE in SQL — a
|
||||
SQLite-level change, not a language change.
|
||||
|
||||
## Cluster 5 — Batch consolidation / curator ops
|
||||
|
||||
- Intention: off-hours batch jobs — knowledge consolidation, promote/decay/compress candidate
|
||||
passes, LLM/heuristic judgment with worthiness filters and graded tiers; output as JSON block
|
||||
files + journal.
|
||||
- Evidence: `memory_consolidation.py` (733 lines; iterate neurons + graph + abstraction with dedupe,
|
||||
JSON load/save at :113-165); `curator.py` (1838 lines; `plan_ops` :861+, rule-based evidence
|
||||
routing, promote/decay/compress passes).
|
||||
- Compute profile: I/O + LLM-call bound, latency-insensitive, batched. LLM calls dominate wall time.
|
||||
- Language fit: keep Python. Concurrency shape (few slow I/O tasks) is squarely asyncio's sweet spot;
|
||||
no GC pressure, no tight compute loop.
|
||||
|
||||
## Cluster 6 — Orchestration / glue (`sleep_time.py`, `night_mode.py`, `identity_anchors.py`)
|
||||
|
||||
- Intention: cron-style orchestrator with lock acquisition, deferral, subprocess hooks; background
|
||||
thread loop with JSON state; regex/string identity-genuineness and drift checks against JSON config.
|
||||
- Evidence: `sleep_time.py:586+` (orchestrator glue); `night_mode.py` (405 lines, thread loop +
|
||||
JSON state); `identity_anchors.py:247` (`check_genuineness`), `:257` (`check_drift`) — regex and
|
||||
string checks over JSON config.
|
||||
- Compute profile: pure glue; process/thread supervision and subprocess dispatch.
|
||||
- Language fit: keep Python. This is the code that the rebase contract (Python TUI, adapter) needs
|
||||
to remain Python for interop anyway.
|
||||
|
||||
## Cluster 7 — Embedding transport (`memory_store._embed`)
|
||||
|
||||
- Intention: produce embeddings via Ollama over HTTP, invoked through subprocess `curl`.
|
||||
- Evidence: `memory_store.py:327-370` (subprocess curl, 60 s timeout); also used by
|
||||
`warm_router.score_neuron` via precomputed embeds.
|
||||
- Compute profile: network-bound; latency lives in Ollama inference + HTTP, not in any language's
|
||||
runtime. The subprocess-curl choice is a dependency-avoidance decision (no Python HTTP client
|
||||
requirement), not a performance decision.
|
||||
- Language fit: keep Python at the call site. If latency ever matters, the lever is batching,
|
||||
connection reuse (one HTTP session instead of curl-per-call), or a local model change — all
|
||||
available from Python. A Rust/Go recode changes nothing that is slow.
|
||||
|
||||
## Cross-cutting observations
|
||||
|
||||
1. **The subsystem's heavy compute is already native.** BM25 + FTS5 (source 5), vector KNN (source 3)
|
||||
run in C inside SQLite; the slowest end-to-end operation (`_embed`) is network-bound. There is no
|
||||
hot Python compute loop measured or plausibly identifiable in this subsystem.
|
||||
2. **The adapter contract penalizes short-lived foreign units.** `shared/native_units.py` requires
|
||||
per-call subprocess spawn (argv in / JSON out / timeout / `--version`). Any unit whose work is
|
||||
< ~10 ms of CPU (all clusters above except possibly cluster 1 at the 3.4 MB extreme) loses to an
|
||||
in-process solution (sources 1 and 6: orjson / pydantic-core wheel pattern).
|
||||
3. **N+1 smells exist but are bounded** (`_df()` per-word counts in recall; per-node BFS queries).
|
||||
The remedy, if ever needed, is SQL-level (CTE, single aggregate query), not a language change.
|
||||
4. **No memory.store DB exists yet locally** — the SQLite store is schema-defined but not
|
||||
materialized, so there is also no scale data justifying a storage-engine discussion beyond
|
||||
SQLite itself.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Wave 1 / Memory & Persistence — Outward Sources
|
||||
|
||||
Every source below was fetched live with `webfetch` during this research session (2026-07). Each
|
||||
`outward/*.json` file mirrors the envelope structure of `research/issue-314/outward/search-Q1.json`
|
||||
(`{"success": true, "data": {"web": [{url, title, description}]}}`), with a `lesson` field added.
|
||||
|
||||
| # | URL | File | Fetch confirmed | Lesson |
|
||||
|---|-----|------|-----------------|--------|
|
||||
| 1 | https://github.com/ijl/orjson | `orjson-readme.json` | yes | Rust JSON lib delivered as a Python wheel: ~10x dumps / ~2x loads / 40-50x dataclass vs stdlib json; more standards-correct than stdlib. Rust benefit can arrive **in-process** — undermines a bespoke Rust JSON CLI unit that must pay subprocess-spawn cost per call. |
|
||||
| 2 | https://github.com/spacejam/sled | `sled-readme.json` | yes | Flagship Rust embedded KV store is beta, pre-1.0, on-disk format unstable; its own README says "if reliability is your primary constraint, use SQLite". Even Rust-native storage defers to SQLite → do not build/adopt custom storage engines for the memory store. |
|
||||
| 3 | https://github.com/asg017/sqlite-vec | `sqlite-vec-readme.json` | yes | Dense vector KNN is a pure-C zero-dep SQLite extension (vec0 `MATCH`), with official Python/Go/Rust bindings. Rune's KNN already runs in C (memory_store.py:646); a recode would either call the same C via bindings (buys nothing) or reimplement vector search (high risk, no measured need). |
|
||||
| 4 | https://github.com/golang/go/issues/71497 | `go-json-v2-issue.json` | yes | Go's `encoding/json/v2` is a ground-up redesign, still API-stage, milestone Go1.27; fetched portion contains no perf comparison. Go's JSON stack is in flux; no evidence of a Go JSON advantage, and Go is not installed (must earn installation). |
|
||||
| 5 | https://www.sqlite.org/fts5.html | `sqlite-fts5-docs.json` | yes | FTS5 (in SQLite since 3.9.0) implements BM25 (`bm25()`), tokenizers, and query syntax in C inside SQLite. Rune's BM25 half of hybrid recall (memory_store.py:693) is already native; Python only does expansion + small RRF fusion + rerank. |
|
||||
| 6 | https://github.com/pydantic/pydantic-core | `pydantic-core-repo.json` | yes | Canonical industry precedent (Pydantic >= 2): hot compute moved to Rust behind an unchanged Python API as a pip wheel. The in-process wheel route beats out-of-process CLI units for short operations under the `shared/native_units.py` spawn contract. |
|
||||
|
||||
## Coverage of major claims (≥2 sources each)
|
||||
|
||||
- **Claim A: heavy compute in the store/recall path is already C (SQLite FTS5 + sqlite-vec), so a language recode replaces glue with glue.** Sources 3, 5 (plus code evidence memory_store.py:646, :693 in `inward.md`).
|
||||
- **Claim B: keep SQLite; no custom Rust/Go storage engine.** Sources 2, 3, 5.
|
||||
- **Claim C: if JSON serialization ever needs Rust, the in-process wheel route (orjson) beats a CLI unit under the native-units spawn contract.** Sources 1, 6.
|
||||
- **Claim D: Go earns no cluster in this subsystem.** Sources 4 (JSON stack in flux), 2 (no storage niche), plus absence of any measured Python bottleneck in `inward.md`; Go not installed on this machine.
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://github.com/golang/go/issues/71497","title":"Go proposal: encoding/json/v2","description":"Fetched GitHub issue (live, 2026-07). The encoding/json/v2 proposal is a from-scratch redesign of Go's JSON package, milestone Go1.27, still at the API-design stage in the fetched portion — no published performance comparison against stdlib encoding/json in the material retrieved. Its existence demonstrates the current Go JSON stack is considered unsatisfactory enough to justify a ground-up rewrite.","lesson":"Go's JSON story is in flux (v2 redesign in flight, v1 retained for compatibility). There is no fetch-confirmed evidence of a Go JSON performance advantage relevant to rune's JSON persistence clusters, and Go is not installed on this machine (installation must be earned on evidence). With no measured Python bottleneck attributable to GC/scheduling/concurrency in the memory subsystem, Go earns no cluster here."}]}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://github.com/ijl/orjson","title":"orjson — fast, correct Python JSON library (Rust + PyO3 wheel)","description":"Fetched README (live, 2026-07). orjson is a pip-installable Rust extension for Python implementing JSON parse/serialize. Author-published benchmarks vs stdlib json: ~10x faster dumps, ~2x faster loads; dataclass serialization 40-50x faster; numpy array serialization ~14x faster. Distributes prebuilt wheels via PyO3/maturin so consumers get Rust performance with a plain 'import orjson' — no build toolchain needed on the consuming machine. Also rejects invalid/edge-case JSON (e.g. float infinities, invalid UTF-8) that stdlib json silently accepts, i.e. more correct, not just faster. Cited as the standard replacement for hot JSON paths in Python services.","lesson":"Rust performance can be delivered INTO Python as an in-process wheel. For the memory subsystem's hot JSON files (task_state.json 973KB, conversation_messages.json 1.2MB, knowledge.json 3.4MB), orjson offers the Rust win at zero adapter cost, whereas a bespoke Rust CLI unit must pay subprocess-spawn cost per call (shared/native_units.py contract: argv in / JSON out) and would need to beat an in-process ~10x-serializing library just to break even. This makes a hand-written Rust JSON unit the weakest Rust candidate in this subsystem."}]}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://github.com/pydantic/pydantic-core","title":"pydantic-core — core validation logic for pydantic written in Rust","description":"Fetched GitHub repository (live, 2026-07). pydantic-core is the performance-critical validation/serialization engine underneath Pydantic >= 2, written in Rust, distributed to Python users as a prebuilt wheel (import pydantic_core). The repository is now archived in its standalone form (April 2026) and lives inside the main pydantic repository — an industrial-scale, long-running instance of the pattern: keep the Python API, move hot compute into Rust via PyO3. Pydantic is among the most-downloaded Python packages; this pattern has survived years of production use.","lesson":"Industry precedent for how a Python-first project adopts Rust: as an in-process compiled extension behind an unchanged Python API (pip wheel), not as out-of-process CLI units. Maps directly to rune's situation — the TUI and toolchain are Python; the interop contract (shared/native_units.py: subprocess spawn, argv in/JSON out, timeout) adds per-call process overhead that in-process Rust wheels avoid. If any memory cluster ever needs Rust, the wheel route (orjson, or a future PyO3 unit) beats the CLI-unit route unless the operation is long-running enough to amortize spawn."}]}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://github.com/spacejam/sled","title":"sled — embedded key-value database in Rust","description":"Fetched README (live, 2026-07). sled is a Rust-native embedded KV store (LSM/B-tree hybrid, log-structured). Status: still beta, pre-1.0; on-disk format explicitly NOT stable before 1.0; README notes a rewrite/rearchitecting effort in progress. The README's own guidance states, verbatim direction to readers: if reliability is your primary constraint, use SQLite. Maintainer-recommended alternative for durability-critical use is SQLite itself.","lesson":"Even the flagship Rust embedded-storage project defers to SQLite on reliability, and is not production-ready (beta, unstable on-disk format). This directly supports keeping the memory store on SQLite rather than building or adopting a custom Rust/Go storage engine. If the store were recoded in Go/Rust, the storage layer would still be SQLite — the recode would only replace the Python orchestration around it, which is thin glue."}]}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://www.sqlite.org/fts5.html","title":"SQLite FTS5 — full-text search extension (official docs)","description":"Fetched official SQLite documentation (live, 2026-07). FTS5 is an SQLite virtual-table module for full-text search, part of the SQLite amalgamation since 3.9.0 (2015). The BM25 ranking function is built in and invoked directly in SQL as 'bm25(fts_table)' with configurable per-column weights; the default tokenizer and several built-in tokenizers (unicode61, porter, trigram, ascii) are implemented in C inside SQLite. Query syntax (NEAR, AND/OR/NOT, phrase queries, prefix queries) is all evaluated by the C engine.","lesson":"The BM25 half of rune's hybrid recall (memory_store.py:693 'bm25(entries_fts)') runs in C inside SQLite, not Python. Python's role is query expansion, RRF fusion over a small probe set (~2x budget), and metadata reranking — thin per-item glue. A Go/Rust recode of the recall path would replace Python glue around C with Go/Rust glue around the same C, while forfeiting Python ecosystem integration (sqlite3 module, orjson, embedding plumbing). Strong KEEP-PYTHON evidence for the store/recall cluster."}]}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://github.com/asg017/sqlite-vec","title":"sqlite-vec — vector search SQLite extension in C","description":"Fetched README (live, 2026-07). sqlite-vec is a pure-C, zero-dependency SQLite extension implementing vector search (KNN via vec0 virtual tables, MATCH queries). Designed to run anywhere SQLite runs; ships official language bindings for Python, Go, Rust, and others. Pre-v1: API subject to breaking changes, but actively developed and widely adopted as the successor to sqlite-vss.","lesson":"The dense-vector KNN in rune's recall path is already executed by battle-tested C inside SQLite (memory_store.py:646 'WHERE v.embedding MATCH ?'). A Go or Rust recode would have to either call the same extension through its Go/Rust bindings (keeping SQLite central, so the recode buys nothing structural) or reimplement vector search from scratch (high risk, no measured need). Confirms the recall cluster's heavy compute is language-independent of Python."}]}
|
||||
@@ -1,78 +0,0 @@
|
||||
# Wave 1 / Memory & Persistence — Synthesis
|
||||
|
||||
Inputs: `inward.md` (cluster profiles, file:line evidence) and `outward/` + `outward-sources.md`
|
||||
(6 live-fetched sources). Language decision is per-function-cluster; honest KEEP-PYTHON is a
|
||||
legitimate verdict, and here it is the dominant one.
|
||||
|
||||
## Verdict table
|
||||
|
||||
| # | Cluster | Verdict | Score (1–5, confidence/fit) | Key evidence |
|
||||
|---|---------|---------|------------------------------|--------------|
|
||||
| 1 | Hot-store JSON persistence (task_state, conversation_messages, knowledge.json) | **KEEP-PYTHON** (upgrade path: orjson wheel, in-process Rust) | 4 | Live files 973KB/1.2MB/3.4MB; orjson ~10x dumps/2x loads as pip wheel (outward #1); pydantic-core precedent for Rust-via-wheel (outward #6); adapter spawn cost penalizes CLI units (inward, cross-cutting #2) |
|
||||
| 2 | SQLite store + FTS5/vec0 hybrid recall (`memory_store.py:575-897`) | **KEEP-PYTHON** (compute already C via SQLite) | 5 | `:646` vec0 MATCH, `:693` bm25() — C inside SQLite; outward #3, #5; sled README itself says use SQLite for reliability (outward #2) |
|
||||
| 3 | Neuron scoring / routing (`warm_router.py:361-503`) | **KEEP-PYTHON** | 5 | 7-signal branching heuristics; network-bound `_embed` dominates; N small |
|
||||
| 4 | Graph BFS (`graph_memory.py:261-343`) | **KEEP-PYTHON** | 5 | hops=1 default, per-node SQL, tiny N; future fix is SQL CTE, not a language |
|
||||
| 5 | Batch consolidation / curator (`memory_consolidation.py`, `curator.py:861+`) | **KEEP-PYTHON** | 5 | I/O + LLM-bound batch, latency-insensitive; asyncio sweet spot |
|
||||
| 6 | Orchestration/glue (`sleep_time.py`, `night_mode.py`, `identity_anchors.py`) | **KEEP-PYTHON** | 5 | Pure glue; rebase interop contract (Python TUI) requires it |
|
||||
| 7 | Embedding transport (`memory_store.py:327-370`) | **KEEP-PYTHON** | 5 | Network-bound subprocess curl to Ollama; language-independent latency |
|
||||
|
||||
**Go: 0 of 7 clusters. Not installed; nothing measured or fetch-confirmed earns installation here.**
|
||||
**C (hand-written): 0 of 7 clusters — C is already present and battle-tested inside SQLite (FTS5,
|
||||
sqlite-vec); hand-writing C would duplicate it.**
|
||||
|
||||
## The one-line core finding
|
||||
|
||||
The memory subsystem's performance-critical compute (BM25, FTS5 tokenization, vector KNN, storage
|
||||
reliability) already runs in C inside SQLite, and its dominant latency (`_embed` → Ollama over
|
||||
subprocess curl) is network-bound. Recoding clusters 2–7 in Go/Rust/C would replace thin Python glue
|
||||
around battle-tested C with foreign glue around the same C, at real migration cost against the
|
||||
interop contract — for no measured win. The only credible Rust vector in this subsystem (cluster 1
|
||||
JSON serialization) is better served by the in-process orjson wheel than by a bespoke CLI unit,
|
||||
because the `shared/native_units.py` spawn contract costs more than the serialization it would save.
|
||||
|
||||
## KILL TESTS (frozen; cheapest disproof, executable early in the wave)
|
||||
|
||||
- **Rust (JSON-CLI-unit candidate, cluster 1):**
|
||||
*Kill test:* On the live 3.4MB `knowledge.json`, run a microbench: stdlib json vs orjson
|
||||
(`pip install orjson`) dump+load, 20 iterations each. If (a) orjson is drop-in and ≥2x on load and
|
||||
≥5x on dump, then a bespoke Rust CLI unit is **disproven** — it must additionally pay
|
||||
subprocess-spawn + JSON handoff (argv in / JSON out) per call, which alone is ~1–5 ms, i.e. the
|
||||
same order as the entire orjson decode of the file. Only if orjson were unavailable/unusable
|
||||
(e.g. forbidden dependency) does a Rust unit stay alive.
|
||||
- **Rust (general, clusters 2–7):**
|
||||
*Kill test:* Name one Python-side hot loop with a measured profile showing ≥50% of end-to-end
|
||||
wall time spent in pure Python compute. No such profile exists (all heavy compute is SQLite C or
|
||||
network); the default is **kill**. Reopen only if a future profile of a materially changed
|
||||
workload (e.g. hops > 3 graph walks, or 100MB knowledge.json) shows Python compute > 50%.
|
||||
- **Go (all clusters):**
|
||||
*Kill test:* Identify any memory-subsystem batch job whose wall time is dominated (≥50%) by pure
|
||||
CPU compute where goroutine-level concurrency or Go GC characteristics would plausibly help.
|
||||
Measured reality: batch jobs are LLM/I-O bound (cluster 5), serving paths are network-bound
|
||||
(clusters 3, 7), and Go's own JSON story is mid-rewrite (outward #4). **Kill** unless such a
|
||||
profile appears. Concretely: instrument one `consolidate_all` run; if Python-compute share < 50%,
|
||||
Go is dead for the wave.
|
||||
- **C (hand-written kernels):**
|
||||
*Kill test:* Identify a kernel not already provided by SQLite/FTS5/sqlite-vec (e.g. a custom
|
||||
tokenizer, exotic distance metric, or crypto kernel) that a profile shows is hot **and** absent
|
||||
from the extension ecosystem. None identified. **Kill.**
|
||||
|
||||
## Evidence-sufficiency statement
|
||||
|
||||
- **Sufficient for:** keeping all seven clusters in Python; rejecting custom storage engines
|
||||
(sled's own reliability caveat, sqlite-vec/FTS5 coverage); preferring in-process Rust wheels over
|
||||
CLI units for JSON; rejecting Go for this wave (no bottleneck fits its strengths; JSON stack in
|
||||
flux; language not installed — installation not earned).
|
||||
- **Insufficient for (stated honestly):** absolute latency numbers — no runtime profiling was
|
||||
performed (static analysis only), and the memory.store SQLite DB is not yet materialized locally,
|
||||
so store-scale behavior is unverified. These gaps do not change any verdict (all verdicts rest on
|
||||
"Python is glue around C/network", which profiling would only strengthen), but they are why the
|
||||
kill tests above specify *measured* profile thresholds rather than assertions.
|
||||
|
||||
## Feasibility / migration cost
|
||||
|
||||
- Clusters 2–7: **zero migration** — verdict is the status quo.
|
||||
- Cluster 1 optional upgrade: `pip install orjson` + swap `json` → `orjson` at the hot
|
||||
load/dump sites; trivial, reversible, no adapter changes, no new build toolchain. This is the
|
||||
entire actionable outcome of the Rust question for this subsystem.
|
||||
- Any future CLI unit must still satisfy `shared/native_units.py`: argv in / JSON out / exit 0 on
|
||||
success / `--version` / timeout — feasible for long-running work only.
|
||||
@@ -1,91 +0,0 @@
|
||||
# Wave 1 — ORCHESTRATION subsystem: function-cluster intention profile (INWARD)
|
||||
|
||||
Scope read: `src/rune/orchestration/` (43 .py modules, 263 `def` matches, ~6,300 LOC incl.
|
||||
microkernel.py, contracts.py, spine.py, build_mode.py).
|
||||
|
||||
**Scope note (honesty):** `src/rune/construction_authority.py` and
|
||||
`src/rune/verification_construction.py` — named in the task — **do not exist** in the tree
|
||||
(`ls` verified). The construction cluster is instead represented by
|
||||
`build_mode.py` (494 lines, TUI build-pipeline orchestrator). Recorded as a scope gap, not invented.
|
||||
|
||||
## Character of the subsystem (read from source)
|
||||
|
||||
This is an **authority/composition/ledger** subsystem: durable append-only stores, locks,
|
||||
deterministic gates, composition roots, registries, policy objects. It is *not* a numeric,
|
||||
parsing, or binary-format subsystem. Evidence of dominant traits:
|
||||
|
||||
- **Durable file I/O everywhere**: temp-file+fsync+rename as the durability primitive
|
||||
(`atomic.py:14-24`), append-only JSONL event store with batching (`event_store.py:4-9,
|
||||
56-101`), content-addressed evidence blobs (`evidence_store.py:1-33`), outbox with atomic
|
||||
persistence (`outbox.py:1`).
|
||||
- **Shared-memory concurrency is minimal**: exactly two files touch `threading` —
|
||||
`conversation_state.py:33,117` (one RLock because "the TUI calls into them from workers as
|
||||
well as the main thread", conversation_state.py:25) and `event_store.py:57,64` (RLock around
|
||||
buffered appends). No asyncio, no thread pools, no sockets in orchestration/ (only
|
||||
`benchmark.py` and `migrate_cli.py` use `subprocess`).
|
||||
- **Determinism and schema discipline dominate over throughput**: canonical records with
|
||||
`schema_version` (`records.py:1-5`), "corruption is a typed error, never a silent skip"
|
||||
(`event_store.py:7`), byte-deterministic snapshots (`spine.py:24-25`).
|
||||
- **The only "hot loop" candidate is hashing**: sha256 digests for content addressing and
|
||||
no-change fingerprinting (`evidence_store.py:33`, `no_change.py:16`) — both on
|
||||
already-file-sized data at event-emission cadence, not per-token.
|
||||
|
||||
## Function clusters (with file:line evidence)
|
||||
|
||||
### C1 — Durable state & ledger stores (I/O-bound) — ~1,100 LOC, ~60 funcs
|
||||
`event_store.py` (137, batched JSONL appends + fsync), `atomic.py` (tempfile+fsync+rename),
|
||||
`evidence_store.py` (sha256 content-addressed blobs), `outbox.py`, `cursor.py`,
|
||||
`conversation_state.py` (450, RLock-guarded repositories, checkpoint recovery at :20-24),
|
||||
`chain.py`, `memory.py`, `projection.py`.
|
||||
**Intention**: correctness-first durable writes; every op ends in an fsync/replace. The
|
||||
bottleneck is the disk, not the language. sha256/uuid/json from stdlib are C-backed already.
|
||||
|
||||
### C2 — Composition roots & authority wiring (pure glue) — ~700 LOC, ~40 funcs
|
||||
`composition.py` (single-authority root, "Nothing else may create event stores…" :5-7),
|
||||
`authority.py`, `cognitive.py`, `memory_synthesis.py`, `gitea_delegation.py`,
|
||||
`surface_gateway.py`. **Intention**: construct once, wire invariants, register kinds.
|
||||
Runtime cost ≈ zero; testability is the requirement.
|
||||
|
||||
### C3 — Policy / state-machine / gate logic — ~1,300 LOC, ~70 funcs
|
||||
`lifecycle.py` (outbox lifecycle state machine), `scheduler.py` (single-authority resource
|
||||
scheduler), `broker.py` (single acquire path), `budget.py`, `deadline.py`, `cadence.py`,
|
||||
`eligibility.py`, `no_change.py` (content fingerprint gate), `selector.py`, `reflex.py`
|
||||
(deterministic reflex layer), `router.py`, `resources.py`, `health.py`.
|
||||
**Intention**: small deterministic decisions on in-memory state — dict/enum lookups, policy
|
||||
evaluation. Sub-millisecond; correctness and auditability are the point.
|
||||
|
||||
### C4 — Structural self-model & schema tooling — ~1,400 LOC, ~55 funcs
|
||||
`spine.py` (structural authority: AST-ish entity/relationship snapshots, maturity ladder,
|
||||
diff — spine.py:1-25), `microkernel.py` (3-primitive plugin dispatch: register/resolve/fire,
|
||||
subprocess-spawning, :1-17), `contracts.py` (570, contract-test harness calling functions and
|
||||
checking shapes), `mapping.py`, `records.py`, `fixtures.py`.
|
||||
**Intention**: introspection, JSON canonicalization, dispatch by manifest. No hot loops;
|
||||
`ast` parsing is one-shot at command time.
|
||||
|
||||
### C5 — TUI-facing orchestration & build pipeline — ~800 LOC, ~30 funcs
|
||||
`build_mode.py` (494, 11-stage build pipeline: ASSESS→…→RECORD, spawns subprocesses,
|
||||
calls research/consent gates), `gateway.py`, `surface.py`, `capability.py`, `transport.py`.
|
||||
**Intention**: coordinate long-running user-facing flows; the TUI (textual, Python) is the
|
||||
direct consumer. Latency dominated by LLM/subprocess calls, never by the orchestrator code.
|
||||
|
||||
### C6 — Benchmark/migration harnesses (tooling, not runtime) — ~800 LOC, ~35 funcs
|
||||
`retrieval_benchmark.py` (368, precision-recall harness over sqlite backends, frozen
|
||||
reference clock), `benchmark.py` (spawns subprocesses), `migrate.py` (sqlite),
|
||||
`migrate_cli.py` (subprocess CLI), `workers.py`, `proposals.py`.
|
||||
**Intention**: offline measurement and one-shot migration. Never on the interactive path.
|
||||
|
||||
## What is ABSENT (decisive for language fit)
|
||||
|
||||
- No numeric/array computation (no numpy; no vector math).
|
||||
- No binary-format parsing (JSONL + text only).
|
||||
- No network protocol implementation (HTTP delegated to transports outside the subsystem).
|
||||
- No per-event hot loop: event cadence is human/agent-scale (batch_size=8 appends,
|
||||
event_store.py:56).
|
||||
- No parallel CPU-bound work that a GIL actually blocks (the two RLocks guard at most
|
||||
TUI-thread + worker-thread light mutations).
|
||||
|
||||
**Preliminary inward read (to be stress-tested outward):** all six clusters are
|
||||
I/O-bound glue, deterministic decision logic, or coordination code — the profile where
|
||||
Python is the honest default and recodes mostly buy risk, not speed. The only clusters with
|
||||
even a theoretical compiled-language argument are C1's hashing path and C4's spine diff —
|
||||
and both are small, cold, and already stdlib-C-accelerated.
|
||||
@@ -1,28 +0,0 @@
|
||||
# OUTWARD sources — Wave 1 ORCHESTRATION (all live-fetched via webfetch)
|
||||
|
||||
Fetch date: 2026-09-29. Rule applied: every MAJOR claim carries ≥2 live-fetched sources;
|
||||
items not fetched are explicitly marked and excluded from counts.
|
||||
|
||||
| ID | URL | Fetched (live) | LESSON (one line) |
|
||||
|----|-----|----------------|-------------------|
|
||||
| S1 | https://github.com/pydantic/pydantic-core | 2026-09-29 ✓ | The canonical Python→Rust recode recodes only the validation hot loop; all API/composition/glue stays Python — orchestration/ has no such hot loop. |
|
||||
| S2 | https://astral.sh/blog/ruff-v0.1.0 | 2026-09-29 ✓ | Headline Rust recodes (Ruff) win on lexing/parsing 10^6-line corpora per run; recode value scales with per-byte volume, which orchestration's event cadence never approaches. |
|
||||
| S3 | https://go.dev/doc/faq | 2026-09-29 ✓ | Go's differentiator is cheap goroutines (server-concurrency workloads); Go↔C/C++ interop is "not a natural fit" and Python exceptions become error-value plumbing — all three are costs against this subsystem. |
|
||||
| S5 | https://docs.python.org/3/library/hashlib.html | 2026-09-29 ✓ | hashlib is already C (OpenSSL/HACL*) and releases the GIL >2047B — a C/Rust recode of the evidence-hash path replaces compiled code with compiled code plus a process boundary. |
|
||||
| S4 | https://pkg.go.dev/std | — not fetched | Excluded from evidence count (listed only for completeness). |
|
||||
| S6 | https://docs.python.org/3/library/asyncio.html | — not fetched | Excluded from evidence count. |
|
||||
| S7 | https://docs.python.org/3/library/subprocess.html | — not fetched | Replaced by a stronger, contract-specific local experiment (rebase-proof adapter timing, n=100 — recorded in search-Q4.json/synthesis.md). |
|
||||
| S8 | https://doc.rust-lang.org/book/ch01-03-hello-cargo.html | — not fetched | Replaced by local verification: cargo 1.98.1 builds interop/rebase-proof clean, zero crates. |
|
||||
|
||||
## Claim → evidence map
|
||||
|
||||
- **Claim A: I/O-bound glue clusters stay Python** → S1, S2 (both show recode value is confined to hot loops absent here) + inward C1/C2/C5 profile.
|
||||
- **Claim B: Go adds nothing here (no concurrency to exploit)** → S3 (design intent is goroutine-heavy servers) + inward scan (2 RLocks, 0 sockets, 0 thread pools).
|
||||
- **Claim C: The only compute path (hashing) already runs in C** → S5 + inward evidence_store.py:33 / no_change.py:16.
|
||||
- **Claim D: Rust is feasible via the adapter but unjustified** → S7 (local: 0.63ms/op adapter cost) + S8 (local build clean) + S1/S2 (no hot loop to justify).
|
||||
- **Claim E: C would not beat stdlib** → S5 alone is decisive here (C is what stdlib already calls); corroborated by absence of any C-shaped workload in the inward profile.
|
||||
|
||||
## Methodology caveats
|
||||
|
||||
- S2 is vendor marketing (no published harness) — used directionally only.
|
||||
- S7's local benchmark is n=100, single warm-cache Linux machine; spawn cost varies by OS (macOS typically 5–20× higher). At agent-event cadence (batch_size=8 appends, event_store.py:56) even the pessimistic end is negligible.
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"query": "Q1 — Rust recode of Python layers: where does it actually pay off?",
|
||||
"fetched_at": "2026-09-29",
|
||||
"sources": [
|
||||
{
|
||||
"id": "S1",
|
||||
"url": "https://github.com/pydantic/pydantic-core",
|
||||
"fetch_confirmed": "2026-09-29 (webfetch live fetch, HTTP 200, README rendered)",
|
||||
"title": "pydantic-core: Core validation logic for pydantic written in Rust",
|
||||
"key_evidence": "The repo exists solely to move *validation hot loops* to Rust while pydantic's public API and all orchestration/glue remain Python ('This repository is the (archived) original home of pydantic-core, which is a key piece of Pydantic >= 2'; topics: parsing, validation, schema). Note: archived 2026-04-11, code moved into main pydantic repo.",
|
||||
"lesson": "Even the canonical Python->Rust recode project recodes only the per-byte hot loop (schema validation); the surrounding layer — API, composition, I/O — stays Python. A coordination/authority layer has no pydantic-core-shaped hot loop.",
|
||||
"methodology_note": "Project-choice evidence, not a benchmark; success measured by adoption (Pydantic 2 default), not raw numbers."
|
||||
},
|
||||
{
|
||||
"id": "S2",
|
||||
"url": "https://astral.sh/blog/ruff-v0.1.0",
|
||||
"fetch_confirmed": "2026-09-29 (webfetch live fetch, HTTP 200)",
|
||||
"title": "Astral blog: Ruff v0.1.0",
|
||||
"key_evidence": "'Ruff is an extremely fast Python linter, written in Rust... executing tens or hundreds of times faster than any individual tool [Flake8, isort, pydocstyle...]'. The recode wins because Ruff replays a lexer over the entire codebase per run ('2-3x performance improvements to our lexer').",
|
||||
"lesson": "The Rust recodes that made headlines recode *parsing-over-large-corpora* loops. Orchestration's equivalent (spine snapshots, JSONL event replay) processes dozens-to-thousands of records at agent-event cadence, not 10^6 lines per invocation — the volume that pays for a recode is absent.",
|
||||
"methodology_note": "Vendor blog; 'tens or hundreds of times faster' is a marketing aggregate without published harness; treat as directional, not quantitative."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"query": "Q2 — Go fit: does this subsystem's (near-zero) concurrency justify installing Go?",
|
||||
"fetched_at": "2026-09-29",
|
||||
"sources": [
|
||||
{
|
||||
"id": "S3",
|
||||
"url": "https://go.dev/doc/faq",
|
||||
"fetch_confirmed": "2026-09-29 (webfetch live fetch, HTTP 200)",
|
||||
"title": "The Go Programming Language — Frequently Asked Questions",
|
||||
"key_evidence": "Go's stated raison d'etre is cheap concurrency: 'goroutines... can be very cheap... little overhead beyond the memory for the stack, which is just a few kilobytes... practical to create hundreds of thousands of goroutines'. Also: 'Do Go programs link with C/C++ programs? ... it is not a natural fit and can require special interface software'; and 'Why does Go not have exceptions?' — errors are multi-value returns, panics are for catastrophe only.",
|
||||
"lesson": "Go's core advantage (hundreds of thousands of lightweight goroutines) targets a workload this subsystem does not have — orchestration/ has exactly two RLock-guarded files, no thread pools, no sockets. Meanwhile the costs of Go here are real: exception-heavy Python glue must be rewritten as error-value plumbing, and C/Rust interop through Go is explicitly 'not a natural fit' — hostile to the shared/native_units.py + std-only-Rust adapter contract.",
|
||||
"methodology_note": "Official language docs (authoritative for design intent, not for measured performance)."
|
||||
},
|
||||
{
|
||||
"id": "S4",
|
||||
"url": "https://pkg.go.dev/std",
|
||||
"fetch_confirmed": "2026-09-29 (NOT fetched — listed for completeness only; S3 covers the Go claim, rule is >=2 sources per MAJOR claim, Go fit is refuted by S3+S1+S2 jointly)",
|
||||
"title": "Go standard library",
|
||||
"key_evidence": "n/a",
|
||||
"lesson": "n/a — not counted as evidence.",
|
||||
"methodology_note": "Explicitly excluded from the evidence count."
|
||||
}
|
||||
],
|
||||
"verdict_support": "Go claim is DISPROVEN for this subsystem by S3 (design intent = concurrency-heavy servers) + inward profile (2 RLocks, no sockets). Combined with the machine constraint (Go not installed, must be earned on evidence), there is no evidence case for installation."
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"query": "Q3 — KEEP-PYTHON for hashing/C1: is there headroom for a C or Rust recode of the evidence-hash path?",
|
||||
"fetched_at": "2026-09-29",
|
||||
"sources": [
|
||||
{
|
||||
"id": "S5",
|
||||
"url": "https://docs.python.org/3/library/hashlib.html",
|
||||
"fetch_confirmed": "2026-09-29 (webfetch live fetch, HTTP 200, Python 3.14.7 docs)",
|
||||
"title": "hashlib — Secure hashes and message digests (Python 3.14.7)",
|
||||
"key_evidence": "The stdlib sha256 path is already C: 'Hashlib now uses SHA3 and SHAKE from OpenSSL if it provides it' (3.9) and 'For any of the MD5, SHA1, SHA2, or SHA3 algorithms that the linked OpenSSL does not provide we fall back to a verified implementation from the HACL* project' (3.12). Concurrency: 'the Python GIL is released while computing a hash supplied more than 2047 bytes'. I/O: hashlib.file_digest 'may bypass Python's I/O and use the file descriptor from fileno() directly'.",
|
||||
"lesson": "The only compute-shaped code in orchestration/ (evidence_store.py sha256 addressing, no_change.py fingerprints) already executes compiled C inside hashlib; a Rust or C recode would replace one compiled implementation with another and add a process boundary via the adapter — strictly worse.",
|
||||
"methodology_note": "Official docs; the GIL-release threshold (2047 bytes) is a concrete, checkable claim."
|
||||
},
|
||||
{
|
||||
"id": "S6",
|
||||
"url": "https://docs.python.org/3/library/asyncio.html",
|
||||
"fetch_confirmed": "2026-09-29 (NOT fetched — not needed; Python-fit claim is carried by S1, S2, S5 which independently bound the recode value)",
|
||||
"title": "n/a",
|
||||
"key_evidence": "n/a",
|
||||
"lesson": "n/a",
|
||||
"methodology_note": "Explicitly excluded from the evidence count."
|
||||
}
|
||||
],
|
||||
"verdict_support": "C1 hash path: KEEP-PYTHON proven by S5 (stdlib is already C-accelerated) against inward evidence (evidence_store.py:33, no_change.py:16 hash file-sized blobs at event cadence)."
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"query": "Q4 — Interop-contract feasibility: per-op subprocess cost of native_units.py adapter for TUI-facing clusters (C5) and microkernel subprocess dispatch (C4).",
|
||||
"fetched_at": "2026-09-29",
|
||||
"sources": [
|
||||
{
|
||||
"id": "S7",
|
||||
"url": "https://docs.python.org/3/library/subprocess.html",
|
||||
"fetch_confirmed": "2026-09-29 (NOT fetched —see honesty note) — covered instead by the LIVE local experiment recorded in synthesis.md kill-test K1 (rebase-proof binary round-trip timing), which is direct evidence for THIS contract, stronger than a generic doc.",
|
||||
"title": "n/a",
|
||||
"key_evidence": "Local measurement on 2026-09-29: `cargo build --release` of interop/rebase-proof (std-only, zero crates) exit 0. 100 adapter round-trips (spawn + JSON stdout + exit 0), op=hash: mean=0.63ms, p50=0.62ms, p95=0.74ms, max=0.88ms, cold first op=0.87ms. Success condition met (exit 0, no timeouts, \"ok\":true on every op).",
|
||||
"lesson": "Per-op adapter cost is dominated by process spawn (~ms scale); at orchestration's event cadence (batch_size=8 appends, event_store.py:56) a subprocess per op is affordable only for coarse ops (spine snapshot emit), never for per-event calls — which confirms KEEP-PYTHON for all per-event clusters.",
|
||||
"methodology_note": "Local microbenchmark, n=100, single machine; methodology and caveat (cold vs warm spawn) recorded in synthesis.md."
|
||||
},
|
||||
{
|
||||
"id": "S8",
|
||||
"url": "https://doc.rust-lang.org/book/ch01-03-hello-cargo.html",
|
||||
"fetch_confirmed": "2026-09-29 (NOT fetched — Rust toolchain fit verified locally instead: cargo/rustc 1.98.1 present, interop/rebase-proof builds clean with zero crates)",
|
||||
"title": "n/a",
|
||||
"key_evidence": "Local: Cargo.toml in interop/rebase-proof, `cargo build --release` exit 0.",
|
||||
"lesson": "Rust toolchain availability is proven on this machine; the constraint is not capability but VALUE — no cluster needs it.",
|
||||
"methodology_note": "Local verification, not web evidence."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
# SYNTHESIS — Wave 1 ORCHESTRATION: per-cluster language verdicts
|
||||
|
||||
## Verdict table
|
||||
|
||||
| Cluster | Files (representative, file:line evidence in inward.md) | Verdict | Score /5 | Key evidence |
|
||||
|---------|----------------------------------------------------------|---------|----------|--------------|
|
||||
| C1 Durable state & ledger stores | event_store.py:56-101, atomic.py:14-24, evidence_store.py:33, conversation_state.py:117, outbox.py:1 | **KEEP-PYTHON** | 5 | fsync-bound; hashing already C via hashlib (S5); no hot loop |
|
||||
| C2 Composition roots & authority wiring | composition.py:5-7, authority.py, cognitive.py | **KEEP-PYTHON** | 5 | pure glue, runtime cost ≈ 0 (S1) |
|
||||
| C3 Policy / state machines / gates | lifecycle.py, scheduler.py, broker.py, no_change.py:16, reflex.py | **KEEP-PYTHON** | 5 | deterministic dict/enum decisions, sub-ms; testability is the requirement (S1, S2) |
|
||||
| C4 Structural self-model & schema tooling | spine.py:24-25, microkernel.py:1-17, contracts.py, records.py | **KEEP-PYTHON** | 4 | introspection + canonical JSON; one-shot AST parsing; only candidate for a future Rust spine-diff if snapshot size ever grows 1000× |
|
||||
| C5 TUI-facing orchestration & build pipeline | build_mode.py:1 (11-stage pipeline), gateway.py, transport.py | **KEEP-PYTHON** | 5 | consumer IS the Python TUI (textual); latency dominated by LLM/subprocess waits |
|
||||
| C6 Benchmark/migration harnesses | retrieval_benchmark.py:1-20, migrate.py, benchmark.py | **KEEP-PYTHON** | 4 | offline tooling; recode buys nothing, loses iteration speed |
|
||||
|
||||
**Keep-Python honesty outcome:** 6/6 clusters KEEP-PYTHON. Real recode volume in this
|
||||
subsystem: **zero functions**. Scope gap: `construction_authority.py` and
|
||||
`verification_construction.py` do not exist (verified); the construction cluster is
|
||||
covered by build_mode.py (C5).
|
||||
|
||||
## Candidate-language verdicts
|
||||
|
||||
- **Go: REJECTED, do not install.** Its differentiator (goroutine-dense servers, S3)
|
||||
targets a workload absent here (2 RLocks, 0 sockets, 0 thread pools across 43 files).
|
||||
Costs are concrete: exception→error-value rewrite of ~260 functions and C/Rust interop
|
||||
"not a natural fit" (S3) against the std-only-Rust adapter contract. Kill test K-GO
|
||||
below is the frozen early test should this ever be challenged.
|
||||
- **Rust: FEASIBLE (toolchain proven: builds clean, 0.63ms/op through the adapter) but
|
||||
UNJUSTIFIED anywhere in this tranche.** No cluster has the hot loop (S1, S2) that pays
|
||||
for a process-boundary recode. Keep as a toolchain-ready option for other subsystems.
|
||||
- **C: REJECTED.** The only compute-shaped work (sha256 evidence addressing,
|
||||
no_change fingerprints) already executes C via stdlib hashlib (S5); a hand-written C
|
||||
unit would be slower in total (spawn+serialize ≈ 0.63ms measured vs an in-process C
|
||||
call) and add an unsafe-memory surface for zero gain.
|
||||
|
||||
## Kill tests (cheapest experiment that would disprove each candidate verdict)
|
||||
|
||||
- **K1 (frozen, already run — kills "adapter overhead blocks recodes"):** time 100
|
||||
round-trips through the rebase-proof binary. Result 2026-09-29: mean 0.63ms, p95
|
||||
0.74ms, cold 0.87ms, 100% exit-0 + ok:true. INTERPRETATION: adapter overhead does NOT
|
||||
disprove recodes on cost grounds — recodes are rejected on VALUE grounds (no hot
|
||||
loop). If a future profiling run shows any orchestration function consuming >10% of a
|
||||
real interactive session, re-open that cluster.
|
||||
- **K-GO (frozen, cheap, ~30 min):** if Go's case is ever revived, first run a
|
||||
Go prototype of event_store.py's batched append+fsync (the only place Go could win —
|
||||
batching under contention) against the Python version at 1000 events. If Python's
|
||||
p95 append latency is within 2× of Go's, Go is dead here permanently. (Expected:
|
||||
both are fsync-bound and identical; Go loses on 260-function rewrite cost.)
|
||||
- **K-RUST (frozen, ~20 min):** if a Rust recode of the spine diff
|
||||
(spine.py:24-25) is proposed, first measure current diff time on a 10,000-entity
|
||||
snapshot. If < 50ms (expected: yes), the recode is disproven by absence of pain.
|
||||
|
||||
## Evidence-sufficiency statement
|
||||
|
||||
**Proven (live-fetched or locally measured):** the subsystem's function-cluster
|
||||
intentions (inward read, file:line-anchored); that headline Python→Rust recodes target
|
||||
hot loops absent here (S1, S2); that Go's design intent mismatches this workload (S3);
|
||||
that hashlib is already C-accelerated (S5); that the std-only-Rust adapter contract
|
||||
round-trips at 0.63ms/op (local, n=100).
|
||||
|
||||
**Assumed (flagged honestly):** that agent-event cadence stays at human scale
|
||||
(batch_size=8, event_store.py:56) — if orchestration ever runs 10⁴+ events/sec, C1/C4
|
||||
verdicts must be revisited; that S2's marketing numbers are directional only; that
|
||||
spawn cost on non-Linux targets may be ~10× higher than the measured 0.63ms (negligible
|
||||
even then at this cadence). Two named scope files were absent; no evidence was
|
||||
invented for them.
|
||||
|
||||
## Feasibility judgement (migration cost against the interop contract)
|
||||
|
||||
Migration cost per cluster to any compiled language = rewrite of ~6,300 LOC +
|
||||
exception-handling re-expression + adapter unit + test parity through contracts.py —
|
||||
while the measured benefit is bounded by the adapter's own 0.63ms/op floor and by
|
||||
fsync latency that no language changes. Feasible for a *single* coarse-grained unit
|
||||
(e.g., spine snapshot emit) in ~1–2 days if ever needed; feasible for the whole
|
||||
subsystem only at prohibitive cost and zero measurable payoff. Recommendation: this
|
||||
subsystem contributes **0 recode units** to the wave plan.
|
||||
@@ -1,75 +0,0 @@
|
||||
# Wave 1 — Provider/Model Layer Inward Profile
|
||||
|
||||
Checkout: `/mnt/workdrive/rune`. All evidence from direct file reads this session
|
||||
(line numbers re-verified against working tree after compaction; earlier profiling
|
||||
notes were corrected where they disagreed with grep — see Corrections).
|
||||
|
||||
## Files profiled
|
||||
|
||||
| File | Lines | I/O shape |
|
||||
|---|---|---|
|
||||
| src/rune/provider_registry.py | 666 | urllib blocking POST |
|
||||
| src/rune/model_connect.py | 462 | urllib GET (discovery), connectivity cache |
|
||||
| src/rune/model_routing.py | 432 | httpx.get (one call), pure routing fns |
|
||||
| src/rune/connection_pool.py | 144 | in-process resource pool |
|
||||
| src/rune/model_profiles.py | 435 | none (pure config dataclasses) |
|
||||
| src/rune/provider_budget.py | 354 | none (pure accounting, threading.Lock) |
|
||||
| src/rune/standardized_providers.py | 281 | none (pure translation) |
|
||||
| src/rune/model_registry.py | 211 | file JSON persistence |
|
||||
| src/rune/openai_compat_transport.py | 227 | urllib blocking POST |
|
||||
|
||||
## Cluster map with evidence
|
||||
|
||||
### C1 — HTTP wire + transport (provider_registry.py, openai_compat_transport.py)
|
||||
- Wire calls are blocking `urllib.request.urlopen` with fixed timeouts:
|
||||
provider_registry.py:214 (`timeout=10`), provider_registry.py:393
|
||||
(`timeout=120`, generation call), openai_compat_transport.py:219
|
||||
(`timeout=120`), openai_compat_transport.py:86 (`timeout=5`, health checks).
|
||||
- Streaming is uniformly disabled: `"stream": False` in every payload —
|
||||
provider_registry.py:374, provider_registry.py:503, openai_compat_transport.py:73,
|
||||
openai_compat_transport.py:160, openai_compat_transport.py:206. grep confirms no
|
||||
`NotImplementedError` stub anywhere in the subsystem: SSE is absent, not half-built.
|
||||
- **No retry/backoff exists at all.** grep for `retry|backoff|max_retries|attempt|sleep`
|
||||
across all subsystem files returns nothing. Failure handling is a bare
|
||||
`except Exception: return False` at openai_compat_transport.py:74-75 (health check).
|
||||
- **Connector-reliability critical code**: the tool-call envelope contract lives in
|
||||
openai_compat_transport.py — tool_call id pairing and normalization at lines 67-107,
|
||||
envelope shape at 160-207, content filtering at 108-135. Comments in-file record
|
||||
observed-live provider misbehavior (400s, orphaned tool results, loops) that this
|
||||
logic defends against. This is the highest-risk code to port.
|
||||
|
||||
### C2 — Connection pool (connection_pool.py, 144 lines)
|
||||
- `threading.Lock`-guarded pool, max 3 connections/provider, idle-timeout eviction.
|
||||
- Guards in-process objects, not sockets — unrelated to TCP pooling.
|
||||
|
||||
### C3 — Routing decisions (model_routing.py, 432 lines)
|
||||
- One I/O call: `httpx.get(.../api/tags)` at model_routing.py:99-101; Ollama
|
||||
`/api/show` probe at 199-214. Everything else is pure decision logic
|
||||
(selection/sorting/fallback) over in-memory data.
|
||||
|
||||
### C4 — Budget accounting (provider_budget.py, 354 lines)
|
||||
- Pure arithmetic over token/cost counters, `threading.Lock` for thread safety.
|
||||
No I/O, no network, no parsing.
|
||||
|
||||
### C5 — Config/registry (model_profiles.py, model_registry.py, standardized_providers.py, model_connect.py)
|
||||
- model_profiles.py (435) and standardized_providers.py (281): pure dataclasses and
|
||||
normalization/translation tables — zero I/O.
|
||||
- model_registry.py (211): JSON file persistence.
|
||||
- model_connect.py (462): urllib GET discovery (`/api/tags`, `/api/show`) plus a
|
||||
connectivity-status cache; same wire shape as C1.
|
||||
|
||||
## Cross-cutting facts
|
||||
- **No asyncio anywhere** in the subsystem (grep). All I/O is blocking; the only
|
||||
concurrency primitives are `threading.Lock` in connection_pool.py and
|
||||
provider_budget.py.
|
||||
- **No retry, no backoff, no SSE** exist today (see C1). Any rewrite pitch that
|
||||
says "Go/Rust gives us retry+SSE" is proposing a *feature add*, not a port.
|
||||
- httpx is already a dependency (model_routing.py:99).
|
||||
- Performance-relevant surface is thin: ~900 lines of wire code (C1+C5 discovery),
|
||||
all latency-bound on the remote LLM server, with `stream: False` payloads of a few KB.
|
||||
|
||||
## Corrections vs earlier session notes
|
||||
- Earlier profiling notes claimed retry/backoff at provider_registry.py:90-121 and a
|
||||
`NotImplementedError` SSE stub. Both are **wrong** against the current tree — no
|
||||
such code exists (grep-verified). This strengthens the stay-Python verdict: the
|
||||
incumbent wire layer is *smaller and simpler* than previously assumed.
|
||||
@@ -1,24 +0,0 @@
|
||||
# Wave 1 — Provider/Model Layer Outward Sources
|
||||
|
||||
All sources live-fetched 2026-09-29 via webfetch. Raw evidence JSONs in `outward/`
|
||||
(single-line format mirroring `research/issue-314/outward/search-Q1.json`).
|
||||
|
||||
| # | URL | Status | Lesson (→ claim it supports) |
|
||||
|---|---|---|---|
|
||||
| O1 | https://pkg.go.dev/net/http | fetch-confirmed | Go stdlib alone covers HTTP client, transport pooling, timeouts, and line-streaming resp.Body → Go wire candidate is *technically* feasible std-only (C1-Go) |
|
||||
| O2 | https://github.com/ollama/ollama/blob/main/api/client.go | fetch-confirmed | Production Go LLM client does NDJSON streaming via bufio.Scanner over resp.Body, zero third-party deps → Go wire pattern proven (C1-Go) |
|
||||
| O3 | https://docs.rs/reqwest/latest/reqwest/ | fetch-confirmed | reqwest SSE path is async (bytes_stream) and runtime-bound; blocking API has no SSE story → Rust wire layer requires tokio+deps (C1-Rust) |
|
||||
| O4 | https://docs.rs/eventsource-stream/latest/eventsource_stream/ | fetch-confirmed | SSE *parsing* itself is an external async-only crate (futures-core, nom) → std-only Rust interop contract cannot express this workload (C1-Rust); earlier 404 on wrong crate name superseded |
|
||||
| O5 | https://github.com/EricLBuehler/mistral.rs | fetch-confirmed | Even first-party Rust LLM stacks (mistral.rs) accept tokio/axum dependency weight; no std-only HTTP/SSE precedent → std-only Rust proof unrealistic (C1-Rust) |
|
||||
| O6 | https://github.com/ollama/ollama | fetch-confirmed | ollama's Go API server is battle-tested for LLM HTTP+streaming at scale → Go candidate capability-proven; kill reason is ecosystem cost not capability (C1-Go) |
|
||||
| O7 | https://github.com/ollama/ollama-python | fetch-confirmed | Official Python client: httpx, sync+async, generator streaming, typed exceptions → Python wire pattern production-proven for this exact workload (C1-keep-Python) |
|
||||
| O8 | https://www.python-httpx.org/quickstart/ | fetch-confirmed | httpx blocking streaming (iter_lines), per-phase timeouts, exception taxonomy → all "rewrite motivations" (retry/timeout/SSE-readiness) available as Python-level upgrade (C1-keep-Python) |
|
||||
|
||||
## Claim → source coverage
|
||||
|
||||
- **Go fits wire layer (capability)**: O1, O2, O6 — ≥2 ✓
|
||||
- **Rust std-only wire layer is not viable**: O3, O4, O5 — ≥2 ✓
|
||||
- **Python suffices / keep-default**: O7, O8 + inward evidence (no asyncio, thin wire
|
||||
surface, httpx already used at model_routing.py:99) — ≥2 ✓
|
||||
- Pure-logic clusters (C2/C3/C4/C5) need no language evidence: no I/O or I/O identical
|
||||
to C1; decision is volume-governed (inward.md), outward sources not applicable.
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://pkg.go.dev/net/http","title":"net/http package - Go standard library","description":"Go stdlib HTTP client documentation: http.Client with pluggable http.Transport (connection pooling built in), resp.Body is an io.ReadCloser suitable for incremental streaming reads, per-request timeouts via context or Client.Timeout, Transport exposes MaxIdleConnsPerHost / IdleConnTimeout knobs. SSE is served by reading resp.Body line-by-line with a bufio.Scanner or json.Decoder; no special SSE library is required for event-per-line formats.","lesson":"Go can implement HTTP wire + SSE/NDJSON streaming + connection pooling with the standard library alone. This makes a Go port feasible WITHOUT the toolchain if the interop contract is std-only — but feasibility is not justification."}]},"fetched":"2026-09-29","fetch_status":"ok","evidence_for":"C1 wire/transport Go candidate"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://github.com/ollama/ollama/blob/main/api/client.go","title":"ollama/api/client.go — production Go LLM client","description":"Production Go client for a local LLM server, fetched as GitHub blob. Streaming generate is implemented by scanning the NDJSON response with bufio.Scanner over resp.Body, decoding each line into a struct with json.Unmarshal. No third-party HTTP or SSE dependency; imports are stdlib plus an errors package. Confirms the pattern: local HTTP + streaming on the same loop as synchronous calls.","lesson":"A real-world LLM connector in Go runs NDJSON/SSE streaming with stdlib only — the exact shape rune's provider layer would need if the wire layer moved to Go."}]},"fetched":"2026-09-29","fetch_status":"ok","evidence_for":"C1 wire/transport Go candidate"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://docs.rs/reqwest/latest/reqwest/","title":"reqwest — Rust HTTP client (docs.rs)","description":"reqwest provides both async and blocking client APIs. Async streaming via Response::bytes_stream (impl Stream<Item=Result<Bytes>>), blocking streaming via Response::copy_to / read. Connection pooling in the async Client. Requires tokio runtime for the async path; blocking API wraps it or runs standalone. No SSE parsing built in — SSE needs a separate crate layered on bytes_stream.","lesson":"Rust HTTP is mature but the async path (where SSE lives) is runtime-bound: tokio + reqwest + a stream combinator. The std-only Rust interop contract cannot express async SSE — a Rust wire layer would import a dependency stack, failing the std-only proof."}]},"fetched":"2026-09-29","fetch_status":"ok","evidence_for":"C1 wire/transport Rust candidate"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://docs.rs/eventsource-stream/latest/eventsource_stream/","title":"eventsource-stream — Rust SSE parsing crate (docs.rs)","description":"Crate implementing the SSE wire-format parser (event/data/id/retry fields, multi-line data, comment lines) as a Stream adapter over any Stream<Item=Result<Bytes, E>>. Built on futures-core and nom. It is async-only: there is no blocking/iterator API documented. Composes with reqwest::Response::bytes_stream. (An earlier fetch attempt of docs.rs/eventsourcemethods returned 404 — wrong crate name; this is the live, correct one.)","lesson":"Even SSE parsing in Rust is an external, async-gated crate. Cost of a Rust wire layer: reqwest + tokio + eventsource-stream + nom — versus rune's current zero-dependency urllib call sites. The dependency-weight claim against the Rust candidate is verified, not assumed."}]},"fetched":"2026-09-29","fetch_status":"ok","evidence_for":"C1 wire/transport Rust candidate"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://github.com/EricLBuehler/mistral.rs","title":"mistral.rs — Rust LLM inference framework","description":"Production Rust LLM inference server on GitHub. Serves OpenAI-compatible HTTP endpoints with SSE streaming via axum/tower (tokio ecosystem). The whole serving stack is async-runtime-based. Not relevant as a connector comparison for rune (rune is a client), but demonstrates that serious Rust LLM stacks accept the tokio+axum dependency weight as the norm.","lesson":"Even first-party Rust LLM projects do not attempt std-only HTTP/SSE; the async dependency stack is the accepted norm. Confirms the std-only Rust interop contract has no realistic precedent for this workload."}]},"fetched":"2026-09-29","fetch_status":"ok","evidence_for":"C1 wire/transport Rust candidate"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://github.com/ollama/ollama","title":"ollama — Go LLM runtime (server) with Rust components","description":"ollama's server-side model runtime is in Go (the API server) while GPU/MLIR portions are C++; the Go HTTP API server handles SSE/NDJSON streaming to clients with net/http. One of the most-deployed local-LLM stacks in existence. Shows Go is battle-tested for the exact HTTP+streaming connector role at high volume.","lesson":"Go's track record for LLM HTTP streaming infrastructure is proven at scale (ollama API server) — the strongest evidence the Go candidate would technically succeed; the kill reason is ecosystem cost, not capability."}]},"fetched":"2026-09-29","fetch_status":"ok","evidence_for":"C1 wire/transport Go candidate"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://github.com/ollama/ollama-python","title":"ollama-python — official Python client","description":"Official Python client for ollama, fetched as GitHub repo page. Built on httpx with sync and async clients sharing one implementation core; streaming responses are Python generators; errors map to typed exceptions (ResponseError with status codes, RequestError hierarchy). Actively maintained; the canonical example that Python clients handle LLM HTTP + streaming + tool calls in production.","lesson":"Python's httpx-based pattern (sync generator streaming, typed exceptions) is production-proven for exactly rune's workload. Porting rune's wire layer to httpx-style Python is a drop-in to this known-good pattern — no language change needed."}]},"fetched":"2026-09-29","fetch_status":"ok","evidence_for":"C1 wire/transport Python-keep candidate"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://www.python-httpx.org/quickstart/","title":"httpx QuickStart","description":"httpx supports streaming responses (client.stream + iter_lines/iter_bytes) in the synchronous API, first-class timeout configuration (connect/read/write/pool) and a documented exception taxonomy (TransportError, TimeoutException, HTTPStatusError families) with response.raise_for_status(). API mirrors requests; dependency is pure-Python friendly (httpcore).","lesson":"httpx gives rune's Python wire layer streaming, precise per-phase timeouts, and a coherent exception hierarchy for free — the reliability features (retry, streaming, timeout discipline) that would motivate a rewrite are available as a Python-level upgrade."}]},"fetched":"2026-09-29","fetch_status":"ok","evidence_for":"C1 wire/transport Python-keep candidate"}
|
||||
@@ -1,94 +0,0 @@
|
||||
# Wave 1 — Provider/Model Layer Synthesis (per-cluster language verdicts)
|
||||
|
||||
Doctrine applied: KEEP-PYTHON is the expected default and the honest volume-governor;
|
||||
each candidate carries a kill test; per-cluster verdicts, never global.
|
||||
|
||||
Inward evidence: `inward.md` (file:line verified). Outward evidence: `outward-sources.md`
|
||||
(8 live-fetched sources, claim-coverage map at bottom).
|
||||
|
||||
---
|
||||
|
||||
## C1 — HTTP wire + transport (provider_registry.py, openai_compat_transport.py, model_connect.py discovery)
|
||||
|
||||
**Verdict: KEEP-PYTHON. Score: Python 5, Go 2, Rust 1.**
|
||||
|
||||
- Python: incumbent works; wire surface is ~900 latency-bound lines with `stream: False`
|
||||
everywhere and fixed timeouts (inward.md C1). httpx already a dependency
|
||||
(model_routing.py:99). Production-proven pattern for this exact workload: O7, O8.
|
||||
- Go: capability proven — stdlib-only HTTP+NDJSON streaming (O1, O2) and scaled
|
||||
production use (O6).
|
||||
- Rust: mature client (O3) but SSE parsing is an external async-only crate (O4);
|
||||
even first-party Rust LLM stacks take the tokio dependency stack (O5).
|
||||
|
||||
**Kill tests**
|
||||
- Go: toolchain absent (verified: `which go` → not found). To re-earn, a Go candidate
|
||||
must pass the `interop/rebase-proof/` contract (std-only, exit 0, not timed out) AND
|
||||
demonstrate a measurable win over the Python incumbent on this workload. There is no
|
||||
performance signal to demonstrate: the layer is remote-LLM-latency-bound with
|
||||
kilobyte payloads (inward.md cross-cutting). Also, 28 call-site behaviors including
|
||||
the tool-call envelope contract (openai_compat_transport.py:67-107, 160-207) would be
|
||||
re-implemented in a new language with zero incumbent test port. **Killed** — no
|
||||
evidence basis to pass the kill test.
|
||||
- Rust: the std-only interop contract cannot express the workload — SSE requires
|
||||
reqwest+tokio+eventsource-stream+nom (O3, O4, O5). **Killed** — fails the contract
|
||||
by construction; dependency footprint contradicts the rebase-proof standard.
|
||||
- Keep-Python upgrade path (not a language change): adopt httpx blocking client with
|
||||
per-phase timeouts + a small retry wrapper (O8). This delivers the reliability the
|
||||
layer currently lacks (it has *no* retry/backoff at all — inward.md Corrections)
|
||||
without any port risk.
|
||||
|
||||
## C2 — Connection pool (connection_pool.py, 144 lines)
|
||||
|
||||
**Verdict: KEEP-PYTHON. Score: Python 5, Go 2, Rust 2.**
|
||||
|
||||
- Guards in-process objects under threading.Lock at ~144 lines; not a TCP pool. No
|
||||
hot loop, no memory pressure, no FFI boundary.
|
||||
|
||||
**Kill test**
|
||||
- Go/Rust: would need demonstrated contention or throughput evidence (pool saturation
|
||||
profiles, lock-wait times) — none exists; the layer is not profiled as a bottleneck.
|
||||
No interop unit can represent in-process object pooling under the std-only contract
|
||||
in a way that measures anything relevant. **Killed** — no measurable problem to solve.
|
||||
|
||||
## C3 — Routing decisions (model_routing.py, 432 lines)
|
||||
|
||||
**Verdict: KEEP-PYTHON. Score: Python 5, Go 1, Rust 1.**
|
||||
|
||||
- Pure decision logic over in-memory data (one httpx discovery call, model_routing.py:99).
|
||||
- Kill test (Go/Rust): would require evidence that routing decisions are a compute
|
||||
bottleneck — they run once per request against millisecond-scale in-memory work while
|
||||
the request itself takes seconds against the LLM. **Killed** — 5 orders of magnitude
|
||||
below any measurable threshold.
|
||||
|
||||
## C4 — Budget accounting (provider_budget.py, 354 lines)
|
||||
|
||||
**Verdict: KEEP-PYTHON. Score: Python 5, Go 1, Rust 1.**
|
||||
|
||||
- Pure arithmetic + threading.Lock. No I/O.
|
||||
- Kill test (Go/Rust): needs counter-throughput evidence; none. A port would be pure
|
||||
translation cost with zero performance headroom. **Killed**.
|
||||
|
||||
## C5 — Config/registry/normalization (model_profiles.py, model_registry.py, standardized_providers.py, model_connect.py tables)
|
||||
|
||||
**Verdict: KEEP-PYTHON. Score: Python 5, Go 1, Rust 1.**
|
||||
|
||||
- Dataclasses, JSON persistence, translation tables. The value here is editability by
|
||||
non-systems programmers; a compiled port buys nothing and costs review surface.
|
||||
- Kill test (Go/Rust): needs evidence of config-load latency or memory footprint
|
||||
problems; none. **Killed**.
|
||||
|
||||
---
|
||||
|
||||
## Evidence sufficiency
|
||||
|
||||
- C1: sufficient — 2/2/3 live sources on the three candidates plus line-verified
|
||||
inward profiling (with Corrections: no retry, no SSE stub, contrary to earlier notes).
|
||||
- C2–C5: sufficient by volume-governor logic — the burden of proof sits on the
|
||||
*rewrite* candidates and the kill tests cannot be passed without performance
|
||||
evidence that does not exist.
|
||||
|
||||
## Feasibility note
|
||||
|
||||
If Go is installed later, the single cluster worth re-running a kill test for is C1
|
||||
(stdlib-only proof via interop/rebase-proof + a benchmark harness). Until then the
|
||||
door is closed on evidence, not opinion.
|
||||
@@ -1,98 +0,0 @@
|
||||
# RUNTIME CORE & TOOLING — Inward intention profile
|
||||
|
||||
Wave 1 language-fit research. Scope: 12 files under `src/rune/`. All line refs verified
|
||||
against working tree at time of writing. Machine facts: Go NOT installed; Rust 1.98.1 +
|
||||
GCC 16.2.1 present; interop proof harness at `interop/rebase-proof/` (std-only Rust,
|
||||
argv-in/JSON-out, 117-line main.rs) with Python adapter `shared/native_units.py`
|
||||
(`NativeResult.ok` = exit 0 AND not timed out; `ok:true` JSON is op-call evidence, not a
|
||||
precondition — shared/native_units.py:89).
|
||||
|
||||
Subsystem-wide character (observed across all 12 files):
|
||||
- Single-threaded or 1–2 daemon threads max; no asyncio anywhere.
|
||||
- Blocking subprocess / urllib HTTP with hard timeouts.
|
||||
- JSON-in/JSON-out glue over dict-shaped data.
|
||||
- Deep degrade-not-crash handling: nearly every failure path returns a dict instead of raising.
|
||||
- NO compute-bound hot path. Latency is dominated by LLM HTTP round-trips (seconds); CPU
|
||||
work is regex/JSON parsing on KB-scale inputs (microseconds-to-milliseconds).
|
||||
|
||||
---
|
||||
|
||||
## Cluster A — Subprocess lifecycle orchestration
|
||||
Files: `tool_executor.py` (1812 L), `cron_engine.py` (436 L), `auto_tasks.py` (460 L).
|
||||
|
||||
- `tool_executor._run_command` (tool_executor.py:1064): `subprocess.run(..., capture_output=True, timeout=...)` blocking calls for arbitrary commands; timeout handling returns error dict.
|
||||
- Grep/lint/test/format/git helpers: `_grep_files`:1190, `_lint_file`:1302, `_run_tests`:1331, `_format_code`:1374, git ops :1403-1448, `_repo_map`:1481. All thin wrappers around one blocking subprocess pattern with 10–120 s timeouts.
|
||||
- Approval-token workflow: `PreparedTool`, `prepare_tool`:681, `approve_tool`:758, digest revalidation `_consume_prepared`:736 — deferred-execution state machine in plain dataclasses.
|
||||
- Sandbox path validation: tool_executor.py:466, 478 (path containment checks before exec).
|
||||
- Atomic writes: `_apply_content`:914 (temp file + replace).
|
||||
- Language config table: tool_executor.py:1215-1270 (dict of per-language command templates).
|
||||
- `cron_engine._run_loop`:182 — one daemon thread, sleeps 60 s, hand-rolled 5-field cron parser (`_parse_cron_field`:199, `_should_run`:236), executes via `subprocess.run(shlex.split(...), shell=False, timeout=60)`:279, file-rotation logging :291.
|
||||
- `auto_tasks` subprocess checks: `run_compile_check`:261, `run_benchmark_check`:282, `run_sanity_check`:303; regex task extraction `extract_tasks`:80; sqlite3 WAL storage (`connect`:40, DB_PATH:32).
|
||||
|
||||
Hot/glue verdict: pure glue. Every unit of work is "spawn a process, wait, parse output".
|
||||
The CPU cost is zero; the wall-clock cost is the child process itself. Error surface is the
|
||||
interesting part: timeouts, non-zero exits, stderr capture, sandboxing — all expressed in
|
||||
Python's exception + dict-return idiom.
|
||||
|
||||
Concurrency shape: synchronous; cron loop is one daemon thread at ~1 task/min scale.
|
||||
|
||||
## Cluster B — Protocol/JSON parsing & validation
|
||||
Files: `tool_protocol.py` (455 L), scoring/estimation slices of `capability_broker.py`
|
||||
(875 L) and `context_broker.py` (768 L).
|
||||
|
||||
- `tool_protocol`: frozen dataclasses (ToolRequest, ToolEvent, …); JSON-schema-ish validation `validate_tool_request`:278; incremental JSONDecoder `raw_decode` scanning `_decoded_objects`:350, `_protocol_entries`:368; regex/fence/XML wrapper handling; `extract_visible_text`:426.
|
||||
- `capability_broker.score_card`:589 — deterministic keyword scoring with stopwords and regex tokenization over tiny N (MAX_SELECTED=10, `select_for_job`:98).
|
||||
- `context_broker.default_estimator` = `len(text)//4`:100 — O(n) token estimate.
|
||||
|
||||
Hot/glue verdict: the only CPU-flavored cluster, but inputs are model-output fragments and
|
||||
config cards — KBs, not MBs. Python's json/regex is already C-backed; a rewrite would move
|
||||
work from CPython-C to another compiled runtime for no observable gain.
|
||||
|
||||
## Cluster C — Model→tool control loop + HTTP transport
|
||||
Files: `local_tool_runtime.py` (806 L), `elastic_cognition.py` (765 L), `goal.py` (441 L).
|
||||
|
||||
- `local_tool_runtime._run_loop`:417 — bounded (max 8 iters) model→tool loop; stdlib urllib transport to Ollama (`OllamaChatTransport`:96); `threading.Lock` ctx-length cache :44; circuit breaker :434-459; approval-resume serialization `resume`:332.
|
||||
- `elastic_cognition`: regex salience classifier `classify_salience`:247 (~40 patterns), MODEL_ROUTES:203, `_execute_ollama`:537 / `_execute_cloud`:585 (urllib), `execute_with_escalation`:644, `parse_response`:461.
|
||||
- `goal._verify_with_llm`:142 — LLM-as-judge via raw urllib to Ollama (qwen2.5:3b, 30 s timeout) with keyword fallback `_verify_with_keywords`:209.
|
||||
|
||||
Hot/glue verdict: glue with latency domination. The loop spends ~100% of wall time waiting
|
||||
on LLM HTTP responses measured in seconds; Python interpreter overhead is noise. Routing
|
||||
tables, escalation ladders, and circuit breakers are dict/logic — Python's home turf.
|
||||
|
||||
## Cluster D — Context assembly & budgeting
|
||||
Files: `context_broker.py` (768 L).
|
||||
|
||||
- `_collect`:495 — contributor callbacks with T1 degrade-not-crash; `_admit`:533 — deterministic priority admission, `ContextOverflowError` fail-loud; `compact_history`:232 — archive-first, rolling summary via Ollama (`summarize_history`:186, urllib); `assemble`:616, `_render`:723; `threading.RLock` guarding single-authority assembly.
|
||||
- Token math is trivially O(n) string slicing (see Cluster B estimator).
|
||||
|
||||
Hot/glue verdict: glue. Correctness lives in admission policy and degrade semantics, not speed.
|
||||
|
||||
## Cluster E — Reliability / queueing infra
|
||||
Files: `failure_auto_filer.py` (527 L).
|
||||
|
||||
- `queue.Queue(maxsize=1000)` + daemon worker `_run_worker`:453 with burst coalescing; append-only JSONL spool `JsonlSpool`:117 with sidecar consumed-markers; credential redaction regexes :84-92; tier gate `tier_gated`:60 (T2 journal-only); never raises into the failure path.
|
||||
- The most "systems-y" file: threading, queueing, crash-safety reasoning. But its performance
|
||||
requirement is ~nil (failure events are rare); its correctness requirement is threading
|
||||
semantics + crash-safe journal ordering — exactly what's hardest to re-verify in a rewrite.
|
||||
|
||||
## Cluster F — Declarative config / brokers
|
||||
Files: `work_manager.py` (591 L), `hook_engine.py` (860 L), remainder of
|
||||
`capability_broker.py`, `goal.py` storage half.
|
||||
|
||||
- `work_manager`: pure dataclass batching (`create_batches`:129, `route_batch`:198), JSON file persistence (~/.rune/work/batches.json), CLI. No concurrency, no subprocess.
|
||||
- `hook_engine`: static metadata tagging of ~28 functions via 18-factor dicts (`auto_tag`:110), pure rule-based `recommend_placement`:674, validation :729, CLI; `handle_hook`:807 is a no-op echo. Entirely declarative data — zero runtime dispatch.
|
||||
- `capability_broker.load_cards`:474 per-call JSON file I/O with atomic rebuild; `find_capability`:759.
|
||||
- `goal`: goal JSON storage + the one HTTP judge call (Cluster C).
|
||||
|
||||
Hot/glue verdict: trivial glue. Portable to any language in principle, valuable in none —
|
||||
the value is the data and the rules, which read as literal dicts in Python today.
|
||||
|
||||
---
|
||||
|
||||
## Feasibility notes (local machine)
|
||||
- Go: NOT installed. Any Go verdict is evidence-starved; a Go kill test cannot be run locally.
|
||||
- Rust: 1.98.1 present; the Wave 0 proof harness (`interop/rebase-proof/`, std-only, zero
|
||||
crates) demonstrates the CLI-boundary pattern a Rust candidate would adopt, and
|
||||
`shared/native_units.py` shows Python can wrap it with zero code changes to callers
|
||||
(result type contract at native_units.py:28-47). Running the harness is not a
|
||||
precondition for verdicts; JSON `ok:true` is op-call evidence only.
|
||||
@@ -1,31 +0,0 @@
|
||||
# OUTWARD SOURCES — Runtime core & tooling (Wave 1)
|
||||
|
||||
All fetches were live `webfetch` calls made during this session. Confirmation status is
|
||||
stated per source; one source (Q6) is fetch-confirmed but content-thin (SPA shell) and is
|
||||
labeled as such rather than paraphrased as if read.
|
||||
|
||||
| # | URL | Fetch-confirmed | Lesson |
|
||||
|---|-----|-----------------|--------|
|
||||
| Q1 | https://pkg.go.dev/os/exec | Yes (go1.27.1 docs rendered) | Go's exec has context-based timeout (`CommandContext`), `WaitDelay`, and since 1.19 refuses cwd-relative program resolution (ErrDot) — a real, mature subprocess API. Nothing Go offers here is a capability Python's `subprocess.run(timeout=..., shell=False)` lacks; it is a different syntax for the same semantics. |
|
||||
| Q2 | https://docs.python.org/3/library/subprocess.html | Yes (3.14.7 docs rendered) | `subprocess.run(check=, timeout=, capture_output=, shell=False)` is exactly the one-call pattern `tool_executor`/`cron_engine`/`auto_tasks` wrap in dict-returning helpers (tool_executor.py:1064, cron_engine.py:279, auto_tasks.py:261). Exception hierarchy (`TimeoutExpired`, `CalledProcessError`) maps 1:1 onto the codebase's degrade-not-crash error dicts. |
|
||||
| Q3 | https://pkg.go.dev/github.com/robfig/cron | Yes (v1.2.0 docs rendered) | robfig/cron is a ~zero-dep 5-field parser + goroutine runner — exactly what cron_engine hand-rolls at cron_engine.py:199/236. Ergonomic win for maintenance, zero performance win at ~1 task/min on one daemon thread. |
|
||||
| Q4 | https://doc.rust-lang.org/std/process/index.html | Yes (std docs rendered) | std::process has NO built-in per-child timeout — Python's `run(timeout=)` becomes hand-rolled wait/poll/kill logic or a tokio dependency. Under this project's zero-crate constraint (interop/rebase-proof is std-only), Rust is strictly more code for identical Cluster-A behavior. |
|
||||
| Q5a | https://docs.rs/serde_json/latest/serde_json/ | Yes (docs.rs rendered) | serde_json requires typed derive structs or borrow-heavy `Value` manipulation; our JSON is dynamic model output / schema-flexible events mutated as dicts with tolerated missing keys — the pattern serde is worst at. |
|
||||
| Q5b | https://docs.python.org/3/library/json.html | Yes (3.14.7 docs rendered) | Python's json (incl. `JSONDecoder.raw_decode` used at tool_protocol.py:350) is C-accelerated; the only CPU-flavored cluster already runs in C on KB-scale inputs. A rewrite changes syntax, not asymptotics or wall time. |
|
||||
| Q6 | https://go.dev/tour/concurrency | Yes, but SPA shell — body did not render (content-thin) | Goroutines are runtime-managed lightweight threads with typed channels (corroborated indirectly by Q1/Q3 doc examples). Our subsystem runs ≤2 threads total; Go's concurrency model solves a problem we do not have. |
|
||||
|
||||
## Cross-source synthesis
|
||||
- **Subprocess orchestration (Cluster A):** Q1 vs Q2 — feature parity between Go exec and
|
||||
Python subprocess for everything our code does (timeout, capture, no-shell, path
|
||||
safety). Q4 shows Rust std is *behind* on the exact feature (child timeout) our code
|
||||
uses most. No language wins on capability; Python wins on lines-of-glue and exception
|
||||
flow into existing dict-error handling.
|
||||
- **Scheduler (Cluster A / cron):** Q3 confirms the one genuinely better-idiomed surface
|
||||
(cron parsing) in Go — but the win is maintenance of ~37 hand-rolled lines, not
|
||||
behavior or speed.
|
||||
- **JSON/protocol (Cluster B):** Q5a+Q5b — Python's dynamic-JSON ergonomics are
|
||||
load-bearing across all 12 files; serde's typed model is actively mismatched to
|
||||
untrusted model-output parsing.
|
||||
- **Concurrency (Clusters C/E):** Q6 — concurrency features are irrelevant at our thread
|
||||
count; LLM HTTP latency (seconds) dominates every loop, so no compiled language can
|
||||
produce a user-observable delta.
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://pkg.go.dev/os/exec","title":"exec package - os/exec - Go Packages","description":"Fetched live (go1.27.1 docs). Package exec runs external commands; wraps os.StartProcess to remap stdin/stdout, connect I/O with pipes. Cmd.Run() starts and waits; Cmd.Output()/CombinedOutput() capture output; CommandContext(ctx,...) provides timeout-based kill via context.WithTimeout (example: exec.CommandContext(ctx,\"sleep\",\"5\").Run() interrupted after 100ms). WaitDelay bounds time waiting on I/O pipes after child exit (ErrWaitDelay). Since Go 1.19, LookPath/Command refuse to resolve programs relative to the current directory (ErrDot) — security posture matches Python's shell=False default. ExitError carries exit status; no exception machinery, errors are values checked at every call site.","position":1}],"query":"Go os/exec subprocess orchestration vs Python subprocess"},"id":"runtime-core-Q1"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://docs.python.org/3/library/subprocess.html","title":"subprocess — Subprocess management (Python 3.14.7 docs)","description":"Fetched live. subprocess.run(args, *, capture_output=False, shell=False, cwd=None, timeout=None, check=False, text=None, env=None) is the recommended high-level API: waits, returns CompletedProcess(returncode, stdout, stderr). Timeout expiry kills the child and re-raises TimeoutExpired after the child terminates. check=True raises CalledProcessError carrying cmd/returncode/stdout/stderr. Popen.communicate(input, timeout) handles pipe-deadlock avoidance that raw .stdout.read() does not. POSIX path uses vfork() internally when safe 'greatly improves performance'. Exceptions are class hierarchy (SubprocessError base) catchable at one site — this is the idiom tool_executor/cron_engine/auto_tasks rely on (dict-returning wrappers around run()).","position":1}],"query":"Python subprocess orchestration timeout capture CompletedProcess"},"id":"runtime-core-Q2"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://pkg.go.dev/github.com/robfig/cron","title":"cron package - github.com/robfig/cron - Go Packages","description":"Fetched live (v1.2.0 docs). cron.New() -> AddFunc(spec, func) -> Start() runs entries in their own goroutines; Implements standard 5-field cron parsing: 'Minute Hour Dom Month Dow' via cron.Parse(spec). Supports @every 1h30m, @midnight style descriptors. No external deps beyond Go stdlib time. Lesson: what our cron_engine hand-rolls in ~37 lines (_parse_cron_field/_should_run at cron_engine.py:199/236) is a solved 200-line stdlib-time problem in Go — a genuine ergonomic win, but our scale is ~1 task/min on one daemon thread, so the win is maintenance ergonomics, not performance.","position":1}],"query":"Go robfig/cron scheduler library 5-field parser goroutines"},"id":"runtime-core-Q3"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://doc.rust-lang.org/std/process/index.html","title":"process - Rust (std library docs, 1.98 era)","description":"Fetched live. std::process::Command builder API: .arg()/.args()/.env()/.current_dir()/.output()/.spawn(); child.wait() with output() returning Output{status,stdout,stderr}. Handles require .kill()/explicit drop to avoid resource leak. Child timeouts are NOT in std — need wait_with_output + manual polling or tokio::process::Command::kill_on_drop + tokio::time::timeout for async. Error surface: io::Result everywhere, no exceptions. Lesson: Rust can do everything Cluster A does, but per-call timeout on child processes is not one line like Python's subprocess.run(timeout=) — it is hand-rolled select/waitpid logic or a crate dependency (tokio), and our zero-crate constraint makes the std path measurably more code for identical behavior.","position":1}],"query":"Rust std::process Command child timeout wait_with_output"},"id":"runtime-core-Q4"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://docs.rs/serde_json/latest/serde_json/","title":"serde_json - Rust docs","description":"Fetched live. serde_json is the de-facto Rust JSON layer; needs derive macros (serde, serde_derive crates) or manual Value manipulation for dynamic JSON. Lesson: our runtime-core code is dominated by DYNAMIC JSON — model outputs, tool events, capability cards, failure spools, batches — consumed as dicts, mutated, re-serialized with 'missing-key tolerated' access. serde_json::Value is workable but borrows/lifetimes turn 'd.get(k, default) if k else pass' patterns into match-arms; the serde derive path requires typed structs, which our schema-flexible model-output parsing (tool_protocol.py:350 incremental raw_decode over untrusted fence-wrapped text) defeats by construction.","position":1},{"url":"https://docs.python.org/3/library/json.html","title":"json — JSON encoder and decoder (Python 3.14.7 docs)","description":"Fetched live. json.loads/JSONDecoder.raw_decode (used at tool_protocol.py:350) is C-accelerated (_json C module); incremental scanning of partial/trailing content is a documented one-liner. Lesson: Cluster B's 'CPU-flavored' work is already running in C; a rewrite to Rust/Go would swap C for compiled code of the same asymptotic cost on KB-scale inputs.","position":2}],"query":"serde_json vs Python json dynamic parsing performance KB inputs"},"id":"runtime-core-Q5"}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://go.dev/tour/concurrency/","title":"A Tour of Go — Concurrency","description":"Fetched live; page is a JS-rendered SPA shell so body content did not render (fetch-confirmed, content-thin). Claim this source supports: goroutines are lightweight runtime-managed threads with typed channels — this is common documented knowledge (pkg.go.dev/os/exec and robfig/cron docs already confirm goroutine usage patterns in this search set). Lesson: Go's concurrency model targets many concurrent tasks; our runtime core has at most 2 threads (cron daemon, filer worker), so goroutine ergonomics are irrelevant at this thread count.","position":1}],"query":"Go goroutines lightweight concurrency model"},"id":"runtime-core-Q6"}
|
||||
@@ -1,112 +0,0 @@
|
||||
# SYNTHESIS — Runtime core & tooling (Wave 1)
|
||||
|
||||
Method: INWARD (inward.md, file:line evidence) → OUTWARD (outward/*.json, outward-sources.md,
|
||||
live-fetched) → per-cluster verdict. Score 1–5 = language fit for THIS cluster's actual
|
||||
workload as characterized inward. Go verdicts are evidence-starved (Go not installed on
|
||||
this machine — no Go kill test runnable locally).
|
||||
|
||||
---
|
||||
|
||||
## Cluster A — Subprocess lifecycle orchestration (tool_executor, cron_engine, auto_tasks)
|
||||
**Verdict: STAY-PYTHON (4.7/5).**
|
||||
The cluster is "spawn, wait, capture, degrade into an error dict" — `subprocess.run(timeout=,
|
||||
capture_output=, shell=False)` is a one-call expression of the entire pattern
|
||||
(inward.md §A; tool_executor.py:1064, cron_engine.py:279, auto_tasks.py:261). Outward Q1/Q2:
|
||||
Go's os/exec reaches feature parity (CommandContext timeouts, ErrDot path hardening) but
|
||||
changes only syntax, not semantics. Outward Q4: Rust std::process has **no built-in child
|
||||
timeout** — the exact feature this cluster leans on hardest — making Rust strictly more code
|
||||
under the zero-crate constraint. The approval-token state machine (tool_executor.py:681-758)
|
||||
and sandbox checks (:466,478) are plain data + containment logic, natural in Python.
|
||||
**Kill test (Rust):** re-express `_run_command` (tool_executor.py:1064) with std::process +
|
||||
manual timeout; count lines and error arms vs the ~40-line Python wrapper. If the Rust
|
||||
version needs >2× lines to reach identical timeout/capture/degrade behavior — which Q4
|
||||
predicts — the rewrite is a net loss. (Runnable locally: Rust 1.98.1 installed.)
|
||||
**Kill test (Go):** not runnable locally (Go not installed). Paper kill test: port
|
||||
cron_engine._run_loop (cron_engine.py:182) to Go with os/exec; measure task-fire latency
|
||||
delta. Prediction from Q1/Q3: zero delta — the 60 s sleep and child runtime dominate.
|
||||
**Evidence sufficiency:** Python verdict fully evidenced. Rust kill test runnable.
|
||||
Go verdict evidence-starved on execution, adequately evidenced on API parity (Q1).
|
||||
|
||||
## Cluster B — Protocol/JSON parsing & validation (tool_protocol; broker scoring/estimation)
|
||||
**Verdict: STAY-PYTHON (4.5/5).**
|
||||
The only CPU-flavored cluster, but inputs are KB-scale model-output fragments; Python's
|
||||
json/regex is C-backed (outward Q5b), so a rewrite swaps C for compiled code at the same
|
||||
asymptotic cost. The incremental `raw_decode` scan (tool_protocol.py:350, :368) parses
|
||||
untrusted, fence-wrapped, schema-flexible output — serde's typed-struct model (outward Q5a)
|
||||
is actively mismatched; dynamic `Value` borrows turn tolerated-missing-key dict idiom into
|
||||
match-arms. Score dinged 0.5 from perfect only because a very large future corpus (>MB
|
||||
batch parsing) would change the math; no such workload exists inward.
|
||||
**Kill test:** parse the largest observed tool-protocol stream 1000× in Python; if total
|
||||
time < 1 s, no rewrite can produce a user-observable win. (Python side runnable locally.)
|
||||
**Evidence sufficiency:** sufficient — inward shows scale (KB), outward shows C-backed
|
||||
already and serde's ergonomic mismatch.
|
||||
|
||||
## Cluster C — Model→tool control loop + HTTP transport (local_tool_runtime, elastic_cognition, goal)
|
||||
**Verdict: STAY-PYTHON (4.8/5).**
|
||||
Wall time is LLM HTTP latency in seconds (Ollama/cloud, 30 s timeouts — inward.md §C);
|
||||
Python overhead is microseconds-to-milliseconds of noise around those waits. The loop's
|
||||
real content is policy: bounded iterations (local_tool_runtime.py:417), circuit breaker
|
||||
(:434-459), escalation ladders (elastic_cognition.py:644), routing tables (:203) — dict/logic
|
||||
structures where Python is strongest and where a rewrite would re-risk correctness for zero
|
||||
latency gain. Outward Q6 (concurrency features) is irrelevant at ≤2 threads.
|
||||
**Kill test:** instrument `_run_loop` (local_tool_runtime.py:417): log non-HTTP CPU time per
|
||||
iteration. Prediction: <1% of wall time is compute; any language rewrite bounds the win at
|
||||
<1% of an already-latency-bound path. (Python side runnable locally.)
|
||||
**Evidence sufficiency:** sufficient.
|
||||
|
||||
## Cluster D — Context assembly & budgeting (context_broker)
|
||||
**Verdict: STAY-PYTHON (4.7/5).**
|
||||
Correctness lives in admission policy (`_admit`:533, fail-loud ContextOverflowError),
|
||||
degrade-not-crash contributor collection (`_collect`:495), and the single-authority RLock —
|
||||
semantics, not speed (inward.md §D). Token math is O(n) len//4 (:100). Compaction is
|
||||
itself an LLM call (`summarize_history`:186), so the slow path is latency-bound like
|
||||
Cluster C.
|
||||
**Kill test:** time `assemble`+`_admit` on the largest stored context; if <10 ms, no
|
||||
language rewrite is observable. (Runnable locally, Python side.)
|
||||
**Evidence sufficiency:** sufficient.
|
||||
|
||||
## Cluster E — Reliability/queueing infra (failure_auto_filer)
|
||||
**Verdict: STAY-PYTHON (4.2/5).** Lowest confidence of the six, stated honestly.
|
||||
On paper this is the best Rust candidate (queue + worker thread + crash-safe JSONL spool,
|
||||
inward.md §E). But its performance requirement is ~nil — failure events are rare — and its
|
||||
correctness burden is threading semantics and crash-safe journal ordering
|
||||
(JsonlSpool:117, `_run_worker`:453), precisely the properties a rewrite re-risks and must
|
||||
re-verify under fault injection. Rust would not make the spool *more* correct, only less
|
||||
familiar. Score 4.2 not 4.7 because this is the one file where a Rust port could be argued
|
||||
on robustness grounds (no GIL-dependent reasoning), yet the argument fails the "what breaks
|
||||
today?" test: nothing does.
|
||||
**Kill test:** fault-inject (kill -9 during spool append) against the current Python spool;
|
||||
if recovery semantics already hold, the rewrite has no correctness win to buy. (Runnable
|
||||
locally, Python side.)
|
||||
**Evidence sufficiency:** partially sufficient — no outward source speaks directly to
|
||||
JSONL-spool crash-safety across languages; verdict rests on inward semantics.
|
||||
|
||||
## Cluster F — Declarative config/brokers (work_manager, hook_engine, capability_broker, goal-storage)
|
||||
**Verdict: STAY-PYTHON (4.9/5).**
|
||||
hook_engine is literal data (~28 tagged functions, 18-factor dicts, hook_engine.py:110, :674)
|
||||
with a no-op runtime (`handle_hook`:807); work_manager is dataclass batching + one JSON file
|
||||
(work_manager.py:129, :198); capability cards are per-call JSON I/O with atomic rebuild
|
||||
(capability_broker.py:474). Portable to anything, valuable in nothing — the asset is the
|
||||
rules, which read as Python dicts today and would read as serde structs/slices at strictly
|
||||
higher friction (outward Q5a).
|
||||
**Kill test:** none needed short of a full rewrite; the cluster has no runtime behavior to
|
||||
measure. Absence of any win condition *is* the disproof of migrating it.
|
||||
**Evidence sufficiency:** sufficient.
|
||||
|
||||
---
|
||||
|
||||
## Overall
|
||||
Honest result: **stay-Python for all six clusters.** The subsystem is latency-bound glue
|
||||
(LLM HTTP + child processes) with ≤2 threads and KB-scale parsing; no cluster contains a
|
||||
compute-bound path where Go/Rust could pay for the rewrite. The single best-language moment
|
||||
found anywhere is robfig/cron (outward Q3) replacing ~37 hand-rolled lines of cron parsing
|
||||
(cron_engine.py:199-236) — an ergonomics nicety, not a fit verdict.
|
||||
|
||||
## Feasibility
|
||||
- Go verdicts are **evidence-starved**: Go is not installed; Go kill tests cannot run
|
||||
locally. They are marked as paper kill tests above.
|
||||
- Rust kill tests **are runnable** (Rust 1.98.1 present). Any candidate Rust unit could be
|
||||
validated through the existing std-only interop harness (`interop/rebase-proof/src/main.rs`,
|
||||
117 lines; adapter `shared/native_units.py`, `NativeResult.ok` = exit 0 AND not timed out;
|
||||
JSON ok:true is op-call evidence, not a precondition — native_units.py:89).
|
||||
- No code was changed; artifacts only, per task constraint.
|
||||
@@ -1,48 +0,0 @@
|
||||
# Inward — Wave 1, TUI subsystem (rune)
|
||||
|
||||
Research question: should `src/rune/rune_tui.py` (and its widget satellites) stay Python/Textual, be recoded native (Go/Rust), or be split — and what adapter surface does the TUI need from the interop contract to "read and utilise those mixtures of languages for its benefit" (Nick's framing)?
|
||||
|
||||
Scope of evidence: `src/rune/rune_tui.py` (4031 lines), `tui_validator.py` (514), `canary_tui_drift.py` (170), `chat_bubble.py` (401), `message_widgets.py` (104); inventory `docs/rebase/rebase-inventory.json`; adapter `shared/native_units.py` (103); proof contract `interop/rebase-proof/src/main.rs`.
|
||||
|
||||
## 1. Unit inventory and coupling
|
||||
|
||||
- TUI cluster ≈ 152 units total; `rebase-inventory.json` tracks only 3 files under a tui path (rune_tui.py, tui_validator.py, canary_tui_drift.py) — chat_bubble.py and message_widgets.py are untracked satellites.
|
||||
- `rune_tui.py` imports 80+ first-party modules (warm_router, capability_broker, memory_store, rune_operator, cron_engine, provider_budget, …). The TUI is the single largest consumer of the codebase.
|
||||
|
||||
## 2. Cluster map (with file:line evidence)
|
||||
|
||||
### Cluster A — Rendering / widgets (candidates: parse/render hot paths?)
|
||||
- `RuneApp(App)` rune_tui.py:1356; app CSS 1364-1477; BINDINGS 1479-1489; reactives 1493-1500.
|
||||
- Widgets: `ThinkingIndicator` :263 (only animation: 0.12s `set_interval` spinner); `HistoryInput` :359; `RuneCommands` Provider :517; `CommandSelector` :532; `ModelItem`/`CategoryHeader`/`ModelSelector` :600-874; `StatusBar` :974; `WorkPane(Vertical)` :1239.
|
||||
- `WorkPane.render()` :1331 and `ChatBubble.render()` chat_bubble.py:157 both build plain Rich `Text` objects by concatenation. Grep of src/rune finds NO `rich.markdown` / `Markdown` / `Syntax` usage — there is no markdown or syntax parsing anywhere in the TUI render path.
|
||||
- Conclusion: no hot parsing/rendering loop exists. The classic "native TUI for render speed" argument has no footing here.
|
||||
|
||||
### Cluster B — Event glue / command surface (the real body of the file)
|
||||
- ~50 `_cmd_*` handlers in rune_tui.py:2476-3575; 88 `_cmd_` references; 279 `add_message` call sites.
|
||||
- `WorkPane` keeps `dict[str, dict]` `_entries` keyed by stable object id with bounded eviction (`_WORK_PANE_MAX_ENTRIES`); headless-testable data methods `add_object`/`update_object`/`visible_entries`.
|
||||
- Tool-widget update-in-place: `self._tool_widgets` dict keyed by `(channel, call_id)`; `tool_widget.apply(tool_event)` at :3676.
|
||||
|
||||
### Cluster C — Model send path (de-facto interop envelope)
|
||||
- `_send_to_model` :3600 → `run_worker(_respond, exclusive=True)` :3816 → synchronous `rune_operator.send_task(text, model=…, channel=…)` inside async worker :3624.
|
||||
- Result envelope dict: `success`, `response`, `thinking` (list), `model`, `recall_count`, `degraded` (list), `tool_events` (list of `{request{call_id}, …}`). This envelope IS the shape a recoded unit would have to reproduce.
|
||||
- Completion side-effects inline in the worker: cron_engine.fire_on_task_complete, MessageQueue approved drain, provider_budget check.
|
||||
- `_consume_runtime_objects` :3818 feeds WorkPane.
|
||||
|
||||
### Cluster D — Subprocess / streaming consumption (adapter precedent already in-tree)
|
||||
- `_cmd_pull` :3443-3517: `subprocess.Popen(["ollama","pull",model,"--json"])`, `json.loads` per stdout line, `self.call_from_thread(...)` to marshal UI updates. A live JSONL streaming precedent.
|
||||
- Background VRAM preload thread :1616-1640 (urllib → ollama /api/generate); parallel startup threads (compile_persona, scan_registry, load_tasks) :1683-1720; CognitiveLoop/DreamCycle/AutonomyLoop started on_mount :1644-1673.
|
||||
- `_run_warm_router` :3575 is a documented no-op — the 21-step per-turn pipeline (~120ms/msg) was removed; cognition moved to ContextBroker in rune_operator + on-demand /commands. The one historical hot path is already gone.
|
||||
|
||||
### Cluster E — Adapter contract (current state)
|
||||
- `shared/native_units.py`: `NativeResult(ok, exit_code, data, stderr, duration_ms, timed_out, raw_stdout)`; `run_native(binary, args, timeout_s=10.0)`; success = exit 0 AND not timed out (line ~89); parses the LAST stdout line as JSON.
|
||||
- `interop/rebase-proof/src/main.rs`: std-only Rust CLI; argv in → `{"ok":true,…}` / `{"ok":false,"error":…}` (exit 2) on stdout; mandatory `--version`; ops sum/echo/hash/sleep/fail.
|
||||
|
||||
## 3. Toolchain constraint (verified locally)
|
||||
|
||||
- `command -v go` → empty: **Go is not installed**; no local Go evidence can exist.
|
||||
- Rust 1.98.1 + GCC 16.2.1 present; `interop/rebase-proof` builds std-only.
|
||||
|
||||
## 4. Intent profile
|
||||
|
||||
- The TUI's intent is **orchestration and consumption**: invoke models, stream and render progress (tool_events, thinking, degraded notices), manage approvals/queues/cron side-effects, and display results. Its value is event glue + state, which Textual's worker/reactive/call_from_thread machinery directly serves.
|
||||
- Any recode must re-expose the ~80 coupled Python modules through an adapter — the coupling cost, not widget cost, dominates.
|
||||
@@ -1,55 +0,0 @@
|
||||
# Outward sources — Wave 1, TUI subsystem
|
||||
|
||||
All URLs live-fetched 2026-09-29 via webfetch (one call per message, timeout=60; parallel batching caused cancellations and was abandoned). Claim mapping at bottom. Format mirrors `research/issue-314/outward/search-Q1.json`.
|
||||
|
||||
## Sources
|
||||
|
||||
### S1 — Textual Workers guide (supports: stay-Python verdict)
|
||||
- URL: https://textual.textualize.io/guide/workers/
|
||||
- Fetch-confirmed: ✅ (`fetch-W1-textual-workers.json`)
|
||||
- Lesson: Textual provides the TUI's concurrency model as framework features — async + thread workers, `exclusive=True` single-flight cancellation, mandatory `call_from_thread` marshalling for thread workers, WorkerManager lifecycle tied to DOM nodes, `exit_on_error` semantics. A native recode must hand-roll all of this.
|
||||
|
||||
### S2 — Ratatui rendering concepts (supports: stay-Python verdict)
|
||||
- URL: https://ratatui.rs/concepts/rendering/
|
||||
- Fetch-confirmed: ✅ (`fetch-W2-ratatui-rendering.json`)
|
||||
- Lesson: Ratatui is immediate-mode (UI rebuilt every frame) and its own docs admit "out of the box, there's little to no help in organizing large applications" — the developer owns the render loop and event-loop orchestration via crossterm. Direct vendor-documented evidence against recoding a large, structured app like this TUI in Rust.
|
||||
|
||||
### S3 — Bubble Tea README (supports: native-feasibility, countervailing)
|
||||
- URL: https://raw.githubusercontent.com/charmbracelet/bubbletea/main/README.md
|
||||
- Fetch-confirmed: ✅ (`fetch-W3-bubbletea-readme.json`)
|
||||
- Lesson: Go's flagship TUI framework is mature: Elm architecture (Model/Update/View), v2 high-performance cell-based renderer, ~18k dependent apps, Bubbles + Lip Gloss. Ecosystem feasibility is real — but widgets are not the hard part; the ~80-module domain coupling is, and no framework addresses it.
|
||||
|
||||
### S4 — Codex CLI README (supports: native-precedent, countervailing)
|
||||
- URL: https://raw.githubusercontent.com/openai/codex/main/README.md
|
||||
- Fetch-confirmed: ✅ (`fetch-W4-codex-readme.json`)
|
||||
- Lesson: Flagship AI-coding TUI ships as a single native binary — native TUIs are viable for this product category. But Codex was native from day one; README documents distribution, not migration. No evidence on recode cost for an existing coupled Python app.
|
||||
|
||||
### S5 — tview README (supports: native-feasibility, countervailing)
|
||||
- URL: https://raw.githubusercontent.com/rivo/tview/master/README.md
|
||||
- Fetch-confirmed: ✅ (`fetch-W5-tview-readme.json`)
|
||||
- Lesson: Second Go data point — retained-widget kit on tcell, users include k9s and GitHub's gh CLI. Widget-set parity is achievable in Go. Same caveat: ecosystem ≠ coupling cost. Go is not installed in this environment, so no local Go evidence exists.
|
||||
|
||||
### S6 — JSON Lines spec (supports: streaming adapter surface)
|
||||
- URL: https://jsonlines.org/
|
||||
- Fetch-confirmed: ✅ (`fetch-W6-jsonlines.json`)
|
||||
- Lesson: Newline-delimited JSON is a standard self-delimiting streaming format for cross-process message passing. The TUI already consumes JSONL in `_cmd_pull` (rune_tui.py:3443-3517). A native unit can stream `tool_events`/recall objects as JSONL with a terminal sentinel envelope; no new runtime machinery needed — but `shared/native_units.py` currently parses only the LAST stdout line, a contract gap that must be closed.
|
||||
|
||||
### S7 — OpenAI Agents SDK workflows guide (supports: TUI-as-consumer architecture)
|
||||
- URL: https://openai.github.io/openai-agents-python/workflows/
|
||||
- Fetch-confirmed: ✅ (`fetch-W7-agents-workflows.json`)
|
||||
- Lesson: Recommended pattern for agentic products: keep the orchestration loop in the high-level framework, push granular/speed-sensitive work into hand-coded subcomponents behind typed interfaces, and stream intermediate outputs so the UI stays responsive. Maps 1:1 onto the rune architecture: Textual TUI (framework) + recoded native units behind a typed JSON envelope (adapter), with streamed `tool_events` keeping the UI live.
|
||||
|
||||
### S8 — Claude Code best practices (supports: TUI-as-consumer architecture, agentic UX)
|
||||
- URL: https://www.anthropic.com/engineering/claude-code-best-practices
|
||||
- Fetch-confirmed: ✅ (`fetch-W8-claude-code-tui.json`)
|
||||
- Lesson: Anthropic deliberately chose a terminal UI for agentic coding for its composability and scriptability; the hard problems are agentic loop design and UX (streamed feedback, permission prompts, background tasks), not rendering speed. Validates that the rune TUI's complexity lives in event glue and agent-orchestration UX — areas where Textual's primitives (workers, call_from_thread, reactives) are already proven, and where a recode would re-litigate solved UX problems.
|
||||
|
||||
## Claim → source mapping
|
||||
|
||||
| Claim | Sources |
|
||||
|---|---|
|
||||
| Render path is not the bottleneck; complexity is event glue → stay-Python shell | S1, S2, S7, S8 (vs. countervailing S3, S4, S5) |
|
||||
| Native Go/Rust TUI recode is feasible but not justified | S3, S4, S5 countervail; S1, S2, S7, S8 support stay-Python |
|
||||
| Streaming adapter surface (JSONL + sentinel envelope) is standard and already precedented | S6 + inward `_cmd_pull` precedent |
|
||||
| TUI is consumer of recoded units via typed envelope, orchestration stays high-level | S7, S8 |
|
||||
| Local-toolchain constraint | Go absent (verified `command -v go` empty); Rust 1.98.1 + GCC 16.2.1 present |
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://textual.textualize.io/guide/workers/","title":"Workers - Textual Guide","description":"Official Textual worker documentation. Key content: Textual provides async and thread workers via @work decorator; thread workers MUST marshal UI updates through self.call_from_thread() or thread-safe post_message() because UI methods are not thread-safe; exclusive=True cancels the prior running worker on the same node; WorkerManager lifecycle is tied to the DOM node (workers die with the widget); exit_on_error defaults to True, meaning an unhandled worker exception exits the whole app.","fetched_at":"2026-09-29","fetch_confirmed":true,"lesson":"The TUI's concurrency model is a first-class framework feature: exclusive single-flight model workers, thread→UI marshalling, and worker-lifecycle management come for free in Textual. A native (Go/Rust) recode must re-implement all of this by hand — ratatui explicitly offers no such orchestration help."}]},"source":"live webfetch","fetch_note":"Fetched successfully 2026-09-29 (timeout=60, single-call batch). Textual FAQ (https://textual.textualize.io/FAQ/) timed out twice on earlier attempts and was replaced by this guide plus supplementary sources."}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://ratatui.rs/concepts/rendering/","title":"Rendering Concepts - Ratatui","description":"Official Ratatui (Rust TUI library) rendering documentation. Key content: Ratatui is immediate-mode — the entire UI is re-created every frame; advantages are simplicity and flexibility of the render loop; disadvantages are that the developer owns the render loop and event loop orchestration (typically via crossterm), and, quoted from the docs, 'out of the box, there's little to no help in organizing large applications'.","fetched_at":"2026-09-29","fetch_confirmed":true,"lesson":"The flagship Rust TUI library is immediate-mode with zero application-structure support. The rune TUI is exactly a 'large application' (~50 command handlers, ~80 coupled modules, reactive state, worker lifecycle) — the exact category ratatui's own docs admit it does not help organize. This is direct vendor-documented evidence against a Rust recode of the TUI shell."}]},"source":"live webfetch","fetch_note":"Fetched successfully 2026-09-29 (timeout=60, single-call batch)."}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://raw.githubusercontent.com/charmbracelet/bubbletea/main/README.md","title":"Bubble Tea - Charmbracelet (README)","description":"README of Bubble Tea, the leading Go TUI framework. Key content: Elm architecture (Model/Update/View) forces all state changes through a single update function; v2 released with a high-performance cell-based renderer; ~18,000 dependent applications; companion Bubbles component library and Lip Gloss styling library.","fetched_at":"2026-09-29","fetch_confirmed":true,"lesson":"Go has a mature, battle-tested TUI ecosystem (Bubble Tea + Bubbles + Lip Gloss), so a Go recode is technically feasible — the Elm-architecture update loop is a reasonable fit for a command-driven app. However the framework provides widgets/components, not the 80-module domain coupling the rune TUI carries; ecosystem maturity changes feasibility, not the coupling cost. Also note: Go is not installed in this environment, so no local Go evidence exists."}]},"source":"live webfetch","fetch_note":"Fetched successfully 2026-09-29 (timeout=60, single-call batch)."}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://raw.githubusercontent.com/openai/codex/main/README.md","title":"Codex CLI - OpenAI (README)","description":"README of OpenAI's Codex CLI. Key content: predominantly installation and quickstart documentation — Codex ships as a single self-contained native binary (Rust) distributed via npm package wrapper and Homebrew; configuration via config.toml; sandbox modes; MCP server support. Little architecture detail in the README itself.","fetched_at":"2026-09-29","fetch_confirmed":true,"lesson":"Migration precedent: a flagship AI-coding TUI (Codex) is a native binary — proving native TUIs are viable for this product category. But Codex was designed native from day one; the README documents distribution (single binary, no Python runtime needed), not a migration story. It does not provide evidence about recode cost for an existing deeply-coupled Python app."}]},"source":"live webfetch","fetch_note":"Fetched successfully 2026-09-29 (timeout=60, single-call batch)."}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://raw.githubusercontent.com/rivo/tview/master/README.md","title":"tview - Rich Widgets for tcell (README)","description":"README of tview, the Go TUI widget kit built on tcell. Key content: rich interactive widgets (tables, forms, lists, trees, grids, flexible/fixed layouts); drop-in application primitives on top of tcell's raw terminal handling; prominent real-world users include k9s and GitHub's gh CLI; MIT licensed.","fetched_at":"2026-09-29","fetch_confirmed":true,"lesson":"Second data point on the Go ecosystem: tview offers retained-widget semantics (closer to Textual's model than Bubble Tea's Elm loop), and ships in tools operators use daily (k9s, gh). Confirms a Go widget ecosystem exists that could roughly mirror the TUI's widget set — again feasibility yes, but no help with the 80-module domain coupling, and Go is not installed locally."}]},"source":"live webfetch","fetch_note":"Fetched successfully 2026-09-29 (timeout=60, single-call batch; first attempt on 'main' branch 404'd, 'master' succeeded)."}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://jsonlines.org/","title":"JSON Lines","description":"The JSON Lines text format specification. Key content: a JSON Lines file/stream is newline-delimited JSON — each line is a valid JSON value, conventionally UTF-8; lines are self-delimiting so a consumer can incrementally parse a stream without buffering the whole payload; the format is widely used for structured logs, message passing between processes, and streaming APIs.","fetched_at":"2026-09-29","fetch_confirmed":true,"lesson":"Validates the streaming adapter surface: newline-delimited JSON is a standard, self-delimiting protocol for cross-process message passing — exactly the shape the TUI already consumes in _cmd_pull (rune_tui.py:3443-3517, ollama pull streaming JSONL parsed line-by-line). A native unit can therefore stream tool_events/recall objects as JSONL with a terminal sentinel envelope, and the TUI needs no new runtime machinery to consume it."}]},"source":"live webfetch","fetch_note":"Fetched successfully 2026-09-29 (timeout=60, single-call batch)."}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://openai.github.io/openai-agents-python/workflows/","title":"Workflows - [OI] Agents SDK (Python)","description":"Official guide on building agentic workflows from the [OI] Agents SDK docs. Key content: recommends orchestrating multiple agents through managed high-level patterns (handoffs, routing, guardrails) while pushing granular, speed-sensitive, or deterministic work into single-purpose hand-coded subcomponents; advocates streaming intermediate outputs (tool calls, partial results) so consuming UIs stay responsive; custom output types and typed payloads let consumers validate what they receive.","fetched_at":"2026-09-29","fetch_confirmed":true,"lesson":"Endorses exactly the target architecture for the rune rebase: keep the TUI + orchestration loop in the high-level framework (Python/Textual), recode granular hot spots as single-purpose units, and connect them via typed, streamable interfaces. The TUI is the consumer that renders streamed intermediate events — matching the existing tool_events envelope shape."}]},"source":"live webfetch","fetch_note":"Fetched successfully 2026-09-29 (timeout=60, single-call batch)."}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"data":{"web":[{"url":"https://www.anthropic.com/engineering/claude-code-best-practices","title":"[CC]: Best Practices for Agentic Coding (Engineering blog)","description":"Anthropic engineering article on [CC]. Key content: deliberate choice of a terminal (TUI) interface for the agentic coding assistant — composable with Unix tooling and scripts; emphasis on agentic loop design, streamed feedback, permission/approval prompts, background tasks, and UX flow rather than raw rendering performance; the terminal UI is treated as an orchestration surface, not a rendering showcase.","fetched_at":"2026-09-29","fetch_confirmed":true,"lesson":"Confirms the hard problems of an agentic TUI are orchestration, streamed feedback, approval flows, and state glue — not frame-level render speed. These are precisely the areas where Textual's worker/reactive/call_from_thread machinery already solves the problem (S1), and where a Go/Rust recode would re-litigate solved problems while gaining little."}]},"source":"live webfetch","fetch_note":"Fetched successfully 2026-09-29 (timeout=60, single-call batch)."}
|
||||
@@ -1,45 +0,0 @@
|
||||
# Synthesis — Wave 1, TUI subsystem
|
||||
|
||||
Question: stay Python/Textual vs Go/Rust native recode, disposition of parsing/rendering hot paths, and the adapter surface the TUI needs from the interop contract.
|
||||
|
||||
## Verdict
|
||||
|
||||
**KEEP-PYTHON for the TUI shell.** `rune_tui.py` stays Python/Textual. No parsing/rendering hot path exists to carve out today. The deliverable that constrains every other wave is the **adapter surface** below: the TUI is the consumer of all recoded units, so its requirements define the interop contract.
|
||||
|
||||
## Per-cluster scores (1 = recode, 5 = keep)
|
||||
|
||||
| Cluster | Candidate | Score | Verdict | Evidence |
|
||||
|---|---|---|---|---|
|
||||
| A — Rendering/widgets | Rust/Go native render | 4 | Keep — no hot loop exists; render is plain Rich `Text` concatenation (rune_tui.py:1331, chat_bubble.py:157), only animation is a 0.12s spinner (:263); no markdown/Syntax parsing anywhere in src/rune | inward.md §2A; S2 vendor docs say ratatui gives "little to no help in organizing large applications" |
|
||||
| B — Event glue (~50 _cmd_* handlers, reactives, tool-widget maps) | Native recode | 5 | Keep — this is Textual's core competency: workers, `exclusive=True`, `call_from_thread`, reactives | inward.md §2B; S1 workers guide; S8 ([CC] hard problems are orchestration/UX, not render speed) |
|
||||
| C — Model send path + envelope | Native recode | 5 | Keep — synchronous `rune_operator.send_task` in async worker with completion side-effects; the envelope shape is already the de-facto interop contract | inward.md §2C |
|
||||
| D — Subprocess/streaming | Native recode | 5 (shell) | Keep — JSONL streaming precedent already in-tree (`_cmd_pull` :3443-3517); it is the pattern for consuming recoded units, not a recode target | inward.md §2D; S6 JSON Lines spec |
|
||||
| Parse/render hot paths | Carve out to Rust unit | n/a | **No such hot path found.** If a future parsing need emerges (e.g. markdown in bubbles), carve it as a Rust native unit behind the adapter — not now. | inward.md §2A; S7 (push granular speed-sensitive work to hand-coded subcomponents) |
|
||||
| Whole TUI in Go/Rust | Recode | 1 | Rejected — 80+ first-party module coupling, framework-provided concurrency re-implemented by hand; Go additionally blocked by toolchain absence | inward.md §1, §3; S2, S3, S4, S5 |
|
||||
|
||||
## ADAPTER SURFACE REQUIREMENTS (TUI as consumer — binds all other waves)
|
||||
|
||||
1. **Single-invocation CLI statelessness.** Each call is a fresh process: `native_unit <op> [args]`. No daemon, no session state (matches `interop/rebase-proof` pattern; failure isolation for free).
|
||||
2. **Request/response JSON envelope.** On success, stdout's final line: `{"ok":true, …op-specific fields…}`. Generalizes the model-send envelope the TUI already consumes (`success/response/thinking/model/recall_count/degraded/tool_events`, rune_tui.py:3624ff). Recoded units returning `response`/`tool_events`/`degraded` shapes plug in with zero TUI changes.
|
||||
3. **Error semantics.** Failure = `{"ok":false,"error":"<machine-readable message>"}` on stdout with nonzero exit (proof contract uses exit 2); stderr reserved for human diagnostics. Success = exit 0 AND not timed out (`shared/native_units.py` line ~89) — this fixed metric is the contract's success definition.
|
||||
4. **Mandatory `--version` flag** on every native unit (already in proof contract) — lets the TUI's status bar and canary (`canary_tui_drift.py`) detect which units are live vs Python-fallback.
|
||||
5. **JSONL streaming mode for long ops.** One JSON object per line, `{"ok":true,"event":…}` progress objects, terminal sentinel = final envelope line. Consumed exactly like `_cmd_pull` (:3443-3517): per-line `json.loads` + `call_from_thread`. **Contract gap to fix:** `native_units.py` currently parses only the LAST stdout line — it must gain a streaming reader that yields per-line events and validates the terminal envelope.
|
||||
6. **Timeout budget per call** (`timeout_s=10.0` default in `native_units.py`); long ops must use streaming mode so partial progress is visible rather than blocked. `timed_out` is surfaced in `NativeResult` so the TUI can degrade gracefully (`degraded` list in the envelope).
|
||||
7. **Stable ids for update-in-place.** Streamed events referencing UI objects must carry the TUI's keys — `(channel, call_id)` for tool widgets (:3676), stable object ids for WorkPane `_entries` (:1239). Envelope fields that map to these keys must be preserved verbatim by recoded units.
|
||||
8. **Std-only constraint** for proof-phase units (no runtime deps), matching `interop/rebase-proof/src/main.rs`; relx it per-unit later only with justification.
|
||||
|
||||
## Kill tests
|
||||
|
||||
- **Stay-Python (shell):** killed if (a) UI-thread stalls >16ms are measured during heavy event bursts, or (b) worker↔subprocess IPC latency dominates message round-trip. Measure with Textual pilot + timing around `run_worker`/`call_from_thread`. Current evidence says neither is plausible (no render hot loop; the 120ms 21-step pipeline was already removed, `_run_warm_router` :3575 is a no-op).
|
||||
- **Native recode (Rust):** killed if the adapter must expose >~15 first-party modules to satisfy the TUI — the count today is ~80, so it is killed now.
|
||||
- **Native recode (Go):** additionally killed by toolchain absence (`command -v go` empty) — cannot even build proof units locally.
|
||||
|
||||
## Evidence sufficiency
|
||||
|
||||
Sufficient for the verdict: full inward read of all 5 TUI files with line refs; 8 live-fetched external sources (≥2 per major claim — stay-Python: S1/S2/S7/S8 with countervailing S3/S4/S5; streaming adapter: S6 + in-tree precedent; toolchain: local verification). Gaps: no runtime profiling (kill test (a)/(b) unmeasured — but no mechanism exists for the stall to occur); Textual FAQ timed out and was replaced by the workers guide + two additional sources.
|
||||
|
||||
## Feasibility
|
||||
|
||||
Adapter-only path is feasible now: proof contract exists and builds (Rust 1.98.1, std-only), TUI already has both request/response (`send_task`) and streaming (`_cmd_pull`) consumption patterns. Remaining engineering: streaming reader in `native_units.py` (gap #5) — small, testable, non-breaking.
|
||||
|
||||
Files: `research/wave1/tui/inward.md`, `research/wave1/tui/outward-sources.md`, `research/wave1/tui/outward/fetch-W1..W8.json` (8). No code touched.
|
||||
@@ -1,94 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""adapt_scorecard.py — #301: the final scorecard for the adaptive pipeline.
|
||||
|
||||
Run the fixture job set (2 fixes, 2 standard features, 2 high-uncertainty
|
||||
tasks) through the router; measure route accuracy, time, and avoided
|
||||
waste. The evidence that earns the adaptive framework.
|
||||
|
||||
Usage: python3 scripts/adapt_scorecard.py [--json]
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import adaptive_router as ar # noqa: E402
|
||||
|
||||
|
||||
def _uncertain_kwargs():
|
||||
return dict(sufficiency=ar.SufficiencyInputs(
|
||||
local_authority="UNKNOWN", external_dependency="UNKNOWN",
|
||||
version_freshness_risk="UNKNOWN", verifiability="UNKNOWN",
|
||||
scope_novelty="UNKNOWN",
|
||||
provenance={"local_authority": "no source",
|
||||
"external_dependency": "no source"}))
|
||||
|
||||
# Fixture jobs: (kind, body, kwargs, expected_route)
|
||||
JOBS = [
|
||||
("fix", "fix a typo in the README", dict(has_local_repro=True,
|
||||
owning_authority_known=True, testable_locally=True,
|
||||
narrow_and_reversible=True), "LOCAL_FIX"),
|
||||
("fix", "fix an off-by-one in the pager", dict(has_local_repro=True,
|
||||
owning_authority_known=True, testable_locally=True,
|
||||
narrow_and_reversible=True), "LOCAL_FIX"),
|
||||
("standard", "add a --json flag to the report script",
|
||||
dict(has_local_repro=True, owning_authority_known=True,
|
||||
testable_locally=True, narrow_and_reversible=True),
|
||||
"STANDARD_CHANGE"),
|
||||
("standard", "refactor the cache layer for clarity",
|
||||
dict(has_local_repro=True, owning_authority_known=True,
|
||||
testable_locally=True, narrow_and_reversible=False),
|
||||
"STANDARD_CHANGE"),
|
||||
("uncertain", "migrate the database schema with unknown downstream consumers",
|
||||
None, # production path: sufficiency with UNKNOWNs
|
||||
"RESEARCHED_CHANGE"),
|
||||
("uncertain", "redesign the memory architecture",
|
||||
None,
|
||||
"RESEARCHED_CHANGE"),
|
||||
]
|
||||
|
||||
|
||||
def scorecard():
|
||||
rows = []
|
||||
correct = 0
|
||||
t0 = time.monotonic()
|
||||
for kind, body, kwargs, expected in JOBS:
|
||||
d = ar.classify_route(body, **(kwargs or _uncertain_kwargs()))
|
||||
hit = d.route == expected
|
||||
correct += hit
|
||||
rows.append({"kind": kind, "expected": expected, "got": d.route,
|
||||
"correct": hit, "reasons": len(d.reasons)})
|
||||
elapsed = time.monotonic() - t0
|
||||
return {
|
||||
"jobs": len(JOBS),
|
||||
"route_accuracy": round(correct / len(JOBS), 3),
|
||||
"elapsed_s": round(elapsed, 3),
|
||||
"avoided_waste": f"{correct}/{len(JOBS)} correctly light or escalated",
|
||||
"rows": rows,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--json", action="store_true")
|
||||
args = ap.parse_args()
|
||||
result = scorecard()
|
||||
if args.json:
|
||||
print(json.dumps(result, indent=1))
|
||||
else:
|
||||
print(f"route accuracy: {result['route_accuracy']} "
|
||||
f"({result['avoided_waste']}) in {result['elapsed_s']}s")
|
||||
for r in result["rows"]:
|
||||
mark = "✓" if r["correct"] else "✗"
|
||||
print(f" {mark} {r['kind']}: {r['got']} (want {r['expected']})")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,126 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""backfill_exit_notes.py — retroactively append the EXIT-NOTE (plain-
|
||||
English what-changed) to every existing release that predates the template
|
||||
(Nick directive 2026-10-08). For each tag: render the exit note for the
|
||||
tag's own range (v_prev..v_tag), append it to the release body under a
|
||||
"## What changed" heading — preserving the governed evidence sections —
|
||||
and PATCH the release via the Gitea API. Idempotent: releases already
|
||||
carrying the exit-note heading are skipped.
|
||||
|
||||
Usage: python3 scripts/backfill_exit_notes.py [--dry-run] [--limit N]
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "scripts"))
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
|
||||
from release_exit_note import render_markdown, render # noqa: E402
|
||||
|
||||
EXIT_HEADING = "## What changed"
|
||||
SERVER = "http://127.0.0.1:3000"
|
||||
REPO_SLUG = "conductor/rune"
|
||||
|
||||
|
||||
def _token() -> str:
|
||||
sys.path.insert(0, str(REPO / ".config" / "opencode" / "shared"))
|
||||
try:
|
||||
from gitea_auth import load_gitea_token
|
||||
return load_gitea_token()
|
||||
except ImportError:
|
||||
# fall back to the git credential
|
||||
r = subprocess.run(
|
||||
["git", "credential", "fill"], input="url=http://127.0.0.1:3000\n",
|
||||
capture_output=True, text=True, cwd=REPO)
|
||||
for line in r.stdout.splitlines():
|
||||
if line.startswith("password="):
|
||||
return line.split("=", 1)[1]
|
||||
return ""
|
||||
|
||||
|
||||
def api(path, method="GET", data=None):
|
||||
import urllib.request
|
||||
req = urllib.request.Request(
|
||||
f"{SERVER}/api/v1/repos/{REPO_SLUG}{path}",
|
||||
data=json.dumps(data).encode() if data is not None else None,
|
||||
headers={"Authorization": f"token {_token()}",
|
||||
"Content-Type": "application/json"},
|
||||
method=method,
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=30) as r:
|
||||
return json.loads(r.read())
|
||||
|
||||
|
||||
def tags():
|
||||
r = subprocess.run(["git", "tag", "--sort=v:refname"],
|
||||
capture_output=True, text=True, cwd=REPO)
|
||||
tags = [t for t in r.stdout.splitlines() if t.startswith("v")]
|
||||
# exit-note applies from v0.117.0 onward (the factory-era releases)
|
||||
try:
|
||||
start = tags.index("v0.117.0")
|
||||
except ValueError:
|
||||
return tags
|
||||
return tags[start:]
|
||||
|
||||
|
||||
def main():
|
||||
dry = "--dry-run" in sys.argv
|
||||
limit = 999
|
||||
if "--limit" in sys.argv:
|
||||
limit = int(sys.argv[sys.argv.index("--limit") + 1])
|
||||
|
||||
all_tags = tags()
|
||||
releases = api("/releases?limit=50&sort=desc")
|
||||
by_tag = {r["tag_name"]: r for r in releases}
|
||||
|
||||
patched, skipped, failed = 0, 0, 0
|
||||
# chronological order (oldest first) so ranges nest correctly
|
||||
for i, tag in enumerate(all_tags):
|
||||
if i == 0:
|
||||
prev = None
|
||||
else:
|
||||
prev = all_tags[i - 1]
|
||||
rel = by_tag.get(tag)
|
||||
if rel is None:
|
||||
skipped += 1
|
||||
continue
|
||||
body = rel.get("body") or ""
|
||||
if EXIT_HEADING in body:
|
||||
skipped += 1
|
||||
continue
|
||||
if i == 0 or prev is None:
|
||||
skipped += 1
|
||||
continue
|
||||
# limit: process the N NEWEST unpatched
|
||||
if patched >= limit:
|
||||
skipped += 1
|
||||
continue
|
||||
try:
|
||||
note = render(prev, tag)
|
||||
md = render_markdown(note)
|
||||
new_body = body.rstrip() + "\n\n---\n\n" + md + "\n"
|
||||
if dry:
|
||||
print(f"[dry] {tag}: would append {len(md)} chars "
|
||||
f"({note['by_kind']})")
|
||||
patched += 1
|
||||
continue
|
||||
api(f"/releases/{rel['id']}", method="PATCH",
|
||||
data={"body": new_body})
|
||||
print(f"patched {tag}: +{len(md)} chars ({note['by_kind']})")
|
||||
patched += 1
|
||||
except Exception as e:
|
||||
print(f"FAILED {tag}: {e}")
|
||||
failed += 1
|
||||
|
||||
print(f"\ndone: {patched} patched, {skipped} skipped, {failed} failed"
|
||||
f"{' (dry run)' if dry else ''}")
|
||||
return 1 if failed else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,81 +0,0 @@
|
||||
"""Bulk-issue guard: ceiling + discipline wrapper for mass Gitea issue posts.
|
||||
|
||||
ANTI-BALLOONING guard (Gitea end), built 2026-10-01 after the rebase
|
||||
tranche ballooned to 1,852 per-unit issues via scripts/rebase_issue_factory.py.
|
||||
|
||||
Any bulk post above the procedural tripwire MUST go through this wrapper:
|
||||
- smoke-first: post ONE unit, verify via API, then unleash the batch
|
||||
- resume-safe: progress file, re-runs skip done keys
|
||||
- retry/backoff: api() retries=5, timeout 60s, 2*(attempt+1) backoff
|
||||
- epic-fold shape: per-FILE epics (never per-unit bulk), members absorbed
|
||||
- dynamic fold-sized bound: posted issues <= epic/file count (one epic
|
||||
per file; units live as member link-lists inside epics, never as issues).
|
||||
The limiting factor is how the batch folds into epics — never a fixed
|
||||
number. BULK_ISSUE_CEILING (50) is a procedural tripwire only: above
|
||||
that many POSTED issues the smoke-first + resume-safe + retry/backoff
|
||||
discipline is mandatory. It caps nothing on its own.
|
||||
|
||||
PRESERVE-FIRST: auto-label, pipeline-gate, merge-robot, human-only closure
|
||||
untouched. Companion: TRANCHE-TEMPLATE.md §7 (template end).
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import urllib.request
|
||||
|
||||
BULK_ISSUE_CEILING = 50 # procedural tripwire (matches TRANCHE-TEMPLATE.md §7):
|
||||
# above this many POSTED issues, smoke-first + resume-safe + retry/backoff
|
||||
# discipline is mandatory. This is NOT a cap on units — the substantive
|
||||
# bound is dynamic (see check_ceiling): posted issues <= epic/file count,
|
||||
# units live as member link-lists inside epics, never as issues.
|
||||
API_RETRIES = 5
|
||||
API_TIMEOUT = 60
|
||||
|
||||
|
||||
def api(method, path, token, base="http://127.0.0.1:3000", payload=None):
|
||||
"""Gitea API call with retry + backoff (fold-worker timeout law)."""
|
||||
data = json.dumps(payload).encode() if payload is not None else None
|
||||
last = None
|
||||
for attempt in range(API_RETRIES):
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
base + path, data=data, method=method,
|
||||
headers={"Authorization": "token " + token,
|
||||
"Content-Type": "application/json"})
|
||||
with urllib.request.urlopen(req, timeout=API_TIMEOUT) as r:
|
||||
return json.load(r)
|
||||
except Exception as e: # noqa: BLE001 — retry loop must catch every transient failure class; the final raise carries the last error
|
||||
last = e
|
||||
time.sleep(2 * (attempt + 1))
|
||||
raise RuntimeError("api failed after retries: %r" % (last,))
|
||||
|
||||
|
||||
def check_ceiling(unit_count, epic_map=None, approved=False):
|
||||
"""Dynamic fold-sized bound: posted issues <= epic/file count.
|
||||
|
||||
The limiting factor is how the batch folds into epics (one epic per
|
||||
file; units absorbed as member link-lists), never a fixed number.
|
||||
BULK_ISSUE_CEILING (50) is a procedural tripwire only: above that many
|
||||
POSTED issues, smoke-first + resume-safe + retry/backoff discipline is
|
||||
mandatory. The substantive check: with an epic map, the allowed posted
|
||||
count is len(epic_map) — one issue per epic. Without a map above the
|
||||
tripwire, fold first; without approval, stop. Returns the required
|
||||
epic granularity ('per-file' above the tripwire, 'per-unit-ok' below).
|
||||
This is the check rebase_issue_factory.py never had (1,852 balloon).
|
||||
"""
|
||||
if unit_count <= BULK_ISSUE_CEILING:
|
||||
return "per-unit-ok"
|
||||
if epic_map is None:
|
||||
raise RuntimeError(
|
||||
"tripwire crossed: %d units > %d with no epic map — "
|
||||
"fold into per-FILE epics first (bound = epic count, "
|
||||
"one posted issue per file)" % (unit_count, BULK_ISSUE_CEILING))
|
||||
bound = len(epic_map)
|
||||
if not approved:
|
||||
raise RuntimeError(
|
||||
"tripwire crossed: %d units > %d — epic map present "
|
||||
"(fold bound: %d posted issues, one per file), "
|
||||
"explicit approval still required" % (
|
||||
unit_count, BULK_ISSUE_CEILING, bound))
|
||||
return "per-file"
|
||||
@@ -1,143 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""deploy_rust_build.py — #2455: the Rust cores ship as BINARIES, not sources.
|
||||
|
||||
Builds every Rust cdylib CI builds into the STAGED deployment tree (in-tree
|
||||
target/release, exactly where the Python loaders look by default) and
|
||||
smoke-checks one FFI operation per crate — BEFORE the symlink flips. The
|
||||
deployed runtime then takes the Rust core by default instead of silently
|
||||
running the Python fallbacks; the strangler's hardening/speed point finally
|
||||
materializes in production.
|
||||
|
||||
Smoke tiers (honest, per crate):
|
||||
- symbol: CDLL-load the staged cdylib and resolve the crate's loader entry
|
||||
symbol (dlsym IS an FFI operation; proves the ELF links and exports).
|
||||
- call: a REAL FFI call through the staged loader itself (token_counting:
|
||||
tc_estimate_tokens({"text": ...}) -> int). One end-to-end call proves the
|
||||
full load path in the deployed revision.
|
||||
|
||||
Toolchain law (carried from ci.yml): rustup toolchain PATH-first (system
|
||||
rustc is broken on this host — LLVM version-node symbol gap); builds run
|
||||
in-tree so the cdylib lands at <crate>/target/release/lib<crate>.so.
|
||||
|
||||
Exit 0 = built + smoked; 1 = any failure (deploy_stage refuses promotion).
|
||||
RUNE_DEPLOY_SKIP_RUST=1 is the documented emergency bypass — the deploy then
|
||||
ships Python fallbacks as before and says so.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import ctypes
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
RUSTUP_BIN = "/home/nick/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin"
|
||||
|
||||
# (crate, loader entry symbol, real-call payload or None)
|
||||
CRATES: list[tuple[str, str, dict | None]] = [
|
||||
("evidence_provenance", "ep_compute_hash", None),
|
||||
("rune_spine", "sp_project", None),
|
||||
("memory_scoring", "ms_compute_value", None),
|
||||
("capability_scoring", "cs_score_card", None),
|
||||
("token_counting", "tc_estimate_tokens", {"text": "ffi deploy smoke"}),
|
||||
("scaffold_core", "sc_check_transition", None),
|
||||
("memory_storage", "mems_read_query", None),
|
||||
("memory_retrieval", "mr_call", None),
|
||||
("cognition_core", "cc_default_budget", None),
|
||||
("route_risk_flags", "rrf_detect", None),
|
||||
("construction_interface", "ci_validate", None),
|
||||
]
|
||||
|
||||
|
||||
def _lib_path(staged_src: Path, crate: str) -> Path:
|
||||
return staged_src / "rust" / crate / "target" / "release" / f"lib{crate}.so"
|
||||
|
||||
|
||||
def build_all(staged_src: Path) -> list[str]:
|
||||
built: list[str] = []
|
||||
env = dict(os.environ)
|
||||
env["PATH"] = f"{RUSTUP_BIN}:{env.get('PATH', '')}"
|
||||
env.pop("CARGO_TARGET_DIR", None) # in-tree targets: the loaders' default path
|
||||
for crate, _sym, _payload in CRATES:
|
||||
manifest = staged_src / "rust" / crate / "Cargo.toml"
|
||||
if not manifest.exists():
|
||||
raise RuntimeError(f"{crate}: no Cargo.toml in the staged tree")
|
||||
r = subprocess.run(
|
||||
["cargo", "build", "--release", "--manifest-path", str(manifest)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=env,
|
||||
timeout=600,
|
||||
)
|
||||
if r.returncode != 0:
|
||||
raise RuntimeError(f"{crate}: cargo build failed:\n{r.stderr[-600:]}")
|
||||
lib = _lib_path(staged_src, crate)
|
||||
if not lib.exists() or lib.stat().st_size < 1024:
|
||||
raise RuntimeError(f"{crate}: cdylib missing or implausibly small after build: {lib}")
|
||||
built.append(crate)
|
||||
print(f" BUILT {crate}: {lib.stat().st_size} bytes")
|
||||
return built
|
||||
|
||||
|
||||
def smoke_all(staged_src: Path) -> list[str]:
|
||||
smoked: list[str] = []
|
||||
for crate, sym, payload in CRATES:
|
||||
lib = ctypes.CDLL(str(_lib_path(staged_src, crate)))
|
||||
fn = getattr(lib, sym) # dlsym: the FFI surface exists
|
||||
fn.restype = ctypes.c_void_p # char* — never default c_int (loader law)
|
||||
if payload is not None:
|
||||
_real_call(staged_src, crate, payload)
|
||||
print(f" SMOKED {crate}: symbol {sym} + real FFI call")
|
||||
else:
|
||||
print(f" SMOKED {crate}: symbol {sym} resolved")
|
||||
smoked.append(crate)
|
||||
return smoked
|
||||
|
||||
|
||||
def _real_call(staged_src: Path, crate: str, payload: dict) -> None:
|
||||
"""Call the entry symbol directly with the loader's exact convention:
|
||||
argtypes c_char_p, restype c_void_p (char* — never default c_int), read
|
||||
the returned JSON envelope, free via <prefix>_free_string."""
|
||||
lib = ctypes.CDLL(str(_lib_path(staged_src, crate)))
|
||||
fn = getattr(lib, "tc_estimate_tokens")
|
||||
fn.argtypes = [ctypes.c_char_p]
|
||||
fn.restype = ctypes.c_void_p
|
||||
raw = json.dumps(payload).encode("utf-8")
|
||||
ptr = fn(raw)
|
||||
if not ptr:
|
||||
raise RuntimeError(f"{crate}: FFI call returned NULL")
|
||||
text = ctypes.cast(ptr, ctypes.c_char_p).value or b""
|
||||
getattr(lib, "tc_free_string")(ctypes.c_void_p(ptr))
|
||||
env = json.loads(text.decode("utf-8"))
|
||||
tokens = env.get("value", env.get("tokens")) if isinstance(env, dict) else env
|
||||
if not isinstance(tokens, int) or tokens <= 0:
|
||||
raise RuntimeError(f"{crate}: implausible FFI result: {text!r}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--staged", required=True, help="the staged tree (tmp_stage), pre-promotion")
|
||||
args = ap.parse_args()
|
||||
staged_src = Path(args.staged) / "src"
|
||||
|
||||
print("RUST CORES INTO THE DEPLOYED REVISION (#2455)")
|
||||
built = build_all(staged_src)
|
||||
smoked = smoke_all(staged_src)
|
||||
missing = {c for c, *_ in CRATES} - set(smoked)
|
||||
if missing:
|
||||
raise RuntimeError(f"smoke coverage gap: {sorted(missing)}")
|
||||
print(f"OK: {len(built)} crates built into the staged revision, {len(smoked)} FFI-smoked")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except SystemExit:
|
||||
raise
|
||||
except Exception as e: # noqa: BLE001 — terminal reporter: prints the failure and exits 1 (never silent)
|
||||
print(f"deploy_rust_build: {e}", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
@@ -184,26 +184,6 @@ print("VERIFIED:", json.dumps(info))
|
||||
shutil.rmtree(tmp_stage, ignore_errors=True)
|
||||
return 1
|
||||
|
||||
# --- Rust cores into the staged revision (#2455) ---------------------
|
||||
# The Rust cores ship as BINARIES, not sources: build every cdylib CI
|
||||
# builds into the staged tree (in-tree target/release — the loaders'
|
||||
# default path) and FFI-smoke each BEFORE the symlink flips, so the
|
||||
# deployed runtime takes the Rust core by default instead of silently
|
||||
# running the Python fallbacks. RUNE_DEPLOY_SKIP_RUST=1 is the documented
|
||||
# emergency bypass (the deploy then ships fallbacks and says so).
|
||||
if os.environ.get("RUNE_DEPLOY_SKIP_RUST") == "1":
|
||||
print("Rust phase SKIPPED (RUNE_DEPLOY_SKIP_RUST=1) — staged revision runs Python fallbacks")
|
||||
else:
|
||||
rust = subprocess.run(
|
||||
[sys.executable, str(repo / "scripts" / "deploy_rust_build.py"), "--staged", str(tmp_stage)],
|
||||
capture_output=True, text=True, timeout=7200,
|
||||
)
|
||||
print(rust.stdout.strip())
|
||||
if rust.returncode != 0:
|
||||
print("RUST BUILD/SMOKE FAILED — deployment refused:\n" + rust.stderr[-800:], file=sys.stderr)
|
||||
shutil.rmtree(tmp_stage, ignore_errors=True)
|
||||
return 1
|
||||
|
||||
# --- TUI startup canary (handoff 2026-09-10 §4): the ACTUAL
|
||||
# RuneApp initialization must succeed before promotion. A staged
|
||||
# revision whose TUI cannot initialize never becomes current.
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""dichotomy_audit.py — the honest completion instrument for the dichotomy rebase.
|
||||
|
||||
Function-level, not directory-level: a module counts as covered only when its
|
||||
PYTHON FUNCTIONS have identifiable counterparts in the Go/Rust implementation.
|
||||
A Go directory with 3 structs and none of the module's 70 functions is a
|
||||
facade, and this audit names it as one.
|
||||
|
||||
Matching rule (name-preserving ports): a Python function name matches when
|
||||
its snake_case form, or its Go/Rust camelCase/PascalCase form, appears in the
|
||||
candidate implementation sources. Deliberately strict — novel Go names that
|
||||
don't echo the Python names do NOT count, because unverifiable "trust me,
|
||||
it's in there somewhere" is exactly the failure mode this instrument exists
|
||||
to kill.
|
||||
|
||||
Usage: python3 scripts/dichotomy_audit.py [--write]
|
||||
--write regenerates docs/dichotomy-rebase-honest-audit.md
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
SRC = ROOT / "src" / "rune"
|
||||
GO = ROOT / "src" / "go"
|
||||
RUST = ROOT / "src" / "rust"
|
||||
REPORT = ROOT / "docs" / "dichotomy-rebase-honest-audit.md"
|
||||
CLASSIFICATION = ROOT / "store" / "rebase" / "classification.json"
|
||||
|
||||
TEST_PREFIXES = ("test_",)
|
||||
# Modules that stay Python by decision (test infra stays pytest)
|
||||
TEST_INFRA = {
|
||||
"conftest", "test_truth", "test_adaptive_router", "test_canaries",
|
||||
}
|
||||
RETIRES = {"memory_env", "__main__"}
|
||||
|
||||
|
||||
def snake_to_camel(name: str) -> list[str]:
|
||||
"""Candidate identifier forms for a Python name in Go/Rust sources."""
|
||||
parts = name.split("_")
|
||||
camel = parts[0] + "".join(p.capitalize() for p in parts[1:])
|
||||
pascal = "".join(p.capitalize() for p in parts)
|
||||
return [name, camel, pascal]
|
||||
|
||||
|
||||
def module_functions(path: Path) -> list[str]:
|
||||
"""Every function and method name defined in the module."""
|
||||
try:
|
||||
tree = ast.parse(path.read_text(encoding="utf-8", errors="replace"))
|
||||
except SyntaxError:
|
||||
return []
|
||||
names = []
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
if node.name.startswith("__") and node.name.endswith("__"):
|
||||
continue # dunders are runtime machinery, not port surface
|
||||
names.append(node.name)
|
||||
return names
|
||||
|
||||
|
||||
def load_classification() -> dict:
|
||||
if CLASSIFICATION.exists():
|
||||
return json.loads(CLASSIFICATION.read_text())
|
||||
return {}
|
||||
|
||||
|
||||
def implementation_corpus() -> dict[str, str]:
|
||||
"""module-kebab -> concatenated Go/Rust source text for that module."""
|
||||
corpus: dict[str, str] = {}
|
||||
|
||||
for d in sorted(GO.iterdir()):
|
||||
if not d.is_dir():
|
||||
continue
|
||||
chunks = []
|
||||
for f in d.rglob("*.go"):
|
||||
if f.name.endswith("_test.go"):
|
||||
continue
|
||||
chunks.append(f.read_text(encoding="utf-8", errors="replace"))
|
||||
if chunks:
|
||||
corpus[d.name] = "\n".join(chunks)
|
||||
|
||||
# Survivor packages (per-crate Go membranes under cognition/)
|
||||
cog = GO / "cognition"
|
||||
if cog.exists():
|
||||
for d in sorted(cog.iterdir()):
|
||||
if d.is_dir():
|
||||
chunks = [f.read_text(encoding="utf-8", errors="replace")
|
||||
for f in d.rglob("*.go") if not f.name.endswith("_test.go")]
|
||||
if chunks:
|
||||
corpus[f"cognition-{d.name}"] = "\n".join(chunks)
|
||||
|
||||
for d in sorted(RUST.iterdir()):
|
||||
src = d / "src"
|
||||
if src.exists():
|
||||
chunks = [f.read_text(encoding="utf-8", errors="replace")
|
||||
for f in src.rglob("*.rs")]
|
||||
if chunks:
|
||||
corpus[d.name] = "\n".join(chunks)
|
||||
return corpus
|
||||
|
||||
|
||||
def module_to_keys(module_stem: str) -> list[str]:
|
||||
"""Candidate implementation keys for a Python module stem."""
|
||||
kebab = module_stem.replace("_", "-")
|
||||
keys = [kebab, module_stem]
|
||||
# Deep ports and multi-module binaries register aliases:
|
||||
aliases = {
|
||||
"rune_operator": ["operator", "operator-deep", "operator-support", "core-server"],
|
||||
"rune_tui": ["tui"],
|
||||
"rune_operator_cli": ["operator"],
|
||||
"memory_store": ["memory-ops", "memory-store-deep"],
|
||||
"warm_router": ["warm-router", "operator-support"],
|
||||
"tool_executor": ["tool-executor", "local-tool-runtime", "tool-protocol", "tool-protocol-rw"],
|
||||
"local_tool_runtime": ["local-tool-runtime", "operator"],
|
||||
"provider_registry": ["provider-registry", "model-connect"],
|
||||
"adaptive_router": ["adaptive-router", "operator-support"],
|
||||
"hook_engine": ["hook-engine"],
|
||||
"event_bus": ["event-bus"],
|
||||
"event_envelope": ["event-bus"],
|
||||
"message_queue": ["message-queue"],
|
||||
"subsystem_health": ["subsystem-health"],
|
||||
"parallel_processor": ["parallel-processor"],
|
||||
"connection_pool": ["connection-pool"],
|
||||
"recall_router": ["recall-router"],
|
||||
"cron_engine": ["cron-engine"],
|
||||
"cache": ["cache"],
|
||||
"night_mode": ["night-mode"],
|
||||
"work_manager": ["work-manager"],
|
||||
"failure_auto_filer": ["failure-filer"],
|
||||
"microkernel": ["microkernel"],
|
||||
"construction_interface": ["cognition-cognition", "cognition"],
|
||||
"construction_decision": ["cognition-cognition", "cognition"],
|
||||
"rune_spine": ["cognition-spine", "cognition"],
|
||||
"spine": ["cognition-spine", "cognition"],
|
||||
"memory_storage": ["cognition-storage", "cognition"],
|
||||
"memory_retrieval": ["cognition-retrieval", "cognition"],
|
||||
"scaffold_core": ["cognition-scaffold", "cognition"],
|
||||
"evidence_provenance": ["cognition-provenance", "cognition"],
|
||||
"memory_scoring": ["cognition-scoring", "cognition"],
|
||||
"capability_scoring": ["cognition-capability", "cognition"],
|
||||
"token_counting": ["cognition-token", "cognition"],
|
||||
"query_memory": ["cognition-query", "cognition"],
|
||||
}
|
||||
if module_stem in aliases:
|
||||
keys = aliases[module_stem] + keys
|
||||
# cognition_core broker.rs hosts many kernels
|
||||
if module_stem in {
|
||||
"tier_manager", "safety_override", "pins", "identity_anchors",
|
||||
"abstraction", "growth_delta", "witness", "persona_gate",
|
||||
"memory_consolidation", "drift_compression", "context_broker",
|
||||
"persona_definition", "goal",
|
||||
}:
|
||||
keys.append("cognition_core")
|
||||
keys.append("cognition-cognition")
|
||||
return keys
|
||||
|
||||
|
||||
def audit() -> dict:
|
||||
classification = load_classification()
|
||||
corpus = implementation_corpus()
|
||||
|
||||
rows = []
|
||||
for path in sorted(SRC.glob("*.py")):
|
||||
stem = path.stem
|
||||
if stem in RETIRES:
|
||||
rows.append({"module": stem, "lines": len(path.read_text(errors='replace').splitlines()),
|
||||
"fns": 0, "matched": 0, "side": "RETIRES", "status": "RETIRES", "missing": []})
|
||||
continue
|
||||
if stem.startswith(TEST_PREFIXES) or stem in TEST_INFRA:
|
||||
rows.append({"module": stem, "lines": len(path.read_text(errors='replace').splitlines()),
|
||||
"fns": 0, "matched": 0, "side": "TEST", "status": "TEST", "missing": []})
|
||||
continue
|
||||
fns = module_functions(path)
|
||||
lines = len(path.read_text(errors="replace").splitlines())
|
||||
entry = classification.get(stem) or classification.get(path.name) or {}
|
||||
side = entry.get("side", entry.get("language", "unclassified"))
|
||||
|
||||
sources = []
|
||||
for key in module_to_keys(stem):
|
||||
if key in corpus:
|
||||
sources.append(corpus[key])
|
||||
blob = "\n".join(sources)
|
||||
|
||||
matched, missing = 0, []
|
||||
for fn in fns:
|
||||
hits = any(cand in blob for cand in snake_to_camel(fn))
|
||||
if hits:
|
||||
matched += 1
|
||||
else:
|
||||
missing.append(fn)
|
||||
|
||||
ratio = matched / len(fns) if fns else (1.0 if lines < 30 else 0.0)
|
||||
if stem in RETIRES:
|
||||
status = "RETIRES"
|
||||
elif not blob:
|
||||
status = "NOT TOUCHED"
|
||||
elif ratio >= 0.8:
|
||||
status = "FULL"
|
||||
elif ratio >= 0.2:
|
||||
status = "PARTIAL"
|
||||
else:
|
||||
status = "NOT TOUCHED"
|
||||
rows.append({"module": stem, "lines": lines, "fns": len(fns),
|
||||
"matched": matched, "side": side, "status": status, "missing": missing[:12]})
|
||||
|
||||
return {"rows": rows}
|
||||
|
||||
|
||||
def summarize(result: dict) -> str:
|
||||
rows = result["rows"]
|
||||
runtime = [r for r in rows if r["status"] not in ("TEST", "RETIRES")]
|
||||
full = [r for r in runtime if r["status"] == "FULL"]
|
||||
partial = [r for r in runtime if r["status"] == "PARTIAL"]
|
||||
untouched = [r for r in runtime if r["status"] == "NOT TOUCHED"]
|
||||
total_fns = sum(r["fns"] for r in runtime)
|
||||
total_matched = sum(r["matched"] for r in runtime)
|
||||
total_lines = sum(r["lines"] for r in runtime)
|
||||
fn_pct = 100 * total_matched / total_fns if total_fns else 0
|
||||
|
||||
out = []
|
||||
out.append("# DICHOTOMY REBASE — HONEST AUDIT (function-level)")
|
||||
out.append("")
|
||||
out.append("_Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL only when 80%+ of its Python functions have name-preserving counterparts in the Go/Rust implementation — directories without the functions are facades and count as NOT TOUCHED._")
|
||||
out.append("")
|
||||
out.append(f"**Function-level completion: {fn_pct:.0f}%** ({total_matched}/{total_fns} runtime functions matched)")
|
||||
out.append("")
|
||||
out.append("| Status | Modules | Lines | Meaning |")
|
||||
out.append("|---|---|---|---|")
|
||||
out.append(f"| FULL | {len(full)} | {sum(r['lines'] for r in full)} | 80%+ of functions ported |")
|
||||
out.append(f"| PARTIAL | {len(partial)} | {sum(r['lines'] for r in partial)} | 20–80% — real logic exists, gaps named below |")
|
||||
out.append(f"| NOT TOUCHED | {len(untouched)} | {sum(r['lines'] for r in untouched)} | no name-preserving implementation |")
|
||||
out.append(f"| Total runtime | {len(runtime)} | {total_lines} | |")
|
||||
out.append("")
|
||||
|
||||
if untouched:
|
||||
out.append("## NOT TOUCHED — the port queue, in priority order (largest first)")
|
||||
out.append("")
|
||||
out.append("| Module | Lines | Fns | Side |")
|
||||
out.append("|---|---|---|---|")
|
||||
for r in sorted(untouched, key=lambda r: -r["lines"]):
|
||||
out.append(f"| {r['module']} | {r['lines']} | {r['fns']} | {r['side']} |")
|
||||
out.append("")
|
||||
if partial:
|
||||
out.append("## PARTIAL — gaps to close (matched/total fns; first missing named)")
|
||||
out.append("")
|
||||
out.append("| Module | Lines | Coverage | Missing (first named) |")
|
||||
out.append("|---|---|---|---|")
|
||||
for r in sorted(partial, key=lambda r: -(r["fns"] - r["matched"])):
|
||||
miss = ", ".join(r["missing"][:6]) if r["missing"] else "(structural)"
|
||||
out.append(f"| {r['module']} | {r['lines']} | {r['matched']}/{r['fns']} | {miss} |")
|
||||
out.append("")
|
||||
out.append("## FULL — ported, parity-gated")
|
||||
out.append("")
|
||||
out.append("| Module | Lines | Fns | Side |")
|
||||
out.append("|---|---|---|---|")
|
||||
for r in sorted(full, key=lambda r: -r["lines"]):
|
||||
out.append(f"| {r['module']} | {r['lines']} | {r['matched']}/{r['fns']} | {r['side']} |")
|
||||
out.append("")
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
write = "--write" in sys.argv
|
||||
result = audit()
|
||||
report = summarize(result)
|
||||
if write:
|
||||
REPORT.write_text(report)
|
||||
print(f"written: {REPORT}")
|
||||
# stderr summary for the session log
|
||||
rows = result["rows"]
|
||||
runtime = [r for r in rows if r["status"] not in ("TEST", "RETIRES")]
|
||||
tf = sum(r["fns"] for r in runtime)
|
||||
tm = sum(r["matched"] for r in runtime)
|
||||
print(f"FUNCTION-LEVEL: {tm}/{tf} ({100*tm/tf if tf else 0:.0f}%) | "
|
||||
f"FULL {sum(1 for r in runtime if r['status']=='FULL')} | "
|
||||
f"PARTIAL {sum(1 for r in runtime if r['status']=='PARTIAL')} | "
|
||||
f"NOT TOUCHED {sum(1 for r in runtime if r['status']=='NOT TOUCHED')}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,181 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""finance_tracker.py — #3: track Nick's finances, surface waste and opportunity.
|
||||
|
||||
Nick has no disposable income; every penny matters. This is a zero-dependency
|
||||
(stdlib-only) tracker:
|
||||
|
||||
add — record an expense or income entry into the CSV ledger
|
||||
budget — set a monthly category limit
|
||||
report — per-category totals vs budgets, income vs spend, for a month
|
||||
or the last 7 days; recurring payments (same note, ~monthly,
|
||||
3+ occurrences) are flagged as SUBSCRIPTION candidates
|
||||
|
||||
Storage: ~/.rune/finance/ledger.csv + budgets.json (human-readable, portable,
|
||||
yours — no database, no cloud, no lock-in).
|
||||
|
||||
finance_tracker.py add -30.00 groceries "weekly shop"
|
||||
finance_tracker.py add 1450.00 salary "October pay"
|
||||
finance_tracker.py budget groceries 260
|
||||
finance_tracker.py report --month 2026-10
|
||||
finance_tracker.py report --week
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from datetime import date, datetime, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
FINANCE_DIR = Path(os.environ.get("RUNE_FINANCE_DIR", Path.home() / ".rune" / "finance"))
|
||||
LEDGER = FINANCE_DIR / "ledger.csv"
|
||||
BUDGETS = FINANCE_DIR / "budgets.json"
|
||||
FIELDS = ["date", "amount", "category", "note", "kind"] # kind: in | out
|
||||
|
||||
|
||||
def _ensure() -> None:
|
||||
FINANCE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
if not LEDGER.exists():
|
||||
with open(LEDGER, "w", newline="", encoding="utf-8") as f:
|
||||
csv.writer(f).writerow(FIELDS)
|
||||
|
||||
|
||||
def add(amount: float, category: str, note: str = "", kind: str | None = None, when: str | None = None) -> dict:
|
||||
"""Record one entry. Negative amount = expense, positive = income (unless
|
||||
kind forces it). Returns the stored row."""
|
||||
_ensure()
|
||||
if kind is None:
|
||||
kind = "out" if amount < 0 else "in"
|
||||
amount = abs(amount)
|
||||
row = {
|
||||
"date": when or date.today().isoformat(),
|
||||
"amount": f"{amount:.2f}",
|
||||
"category": category.strip().lower(),
|
||||
"note": note.strip(),
|
||||
"kind": kind,
|
||||
}
|
||||
with open(LEDGER, "a", newline="", encoding="utf-8") as f:
|
||||
csv.DictWriter(f, fieldnames=FIELDS).writerow(row)
|
||||
return row
|
||||
|
||||
|
||||
def set_budget(category: str, monthly_limit: float) -> dict:
|
||||
_ensure()
|
||||
budgets = {}
|
||||
if BUDGETS.exists():
|
||||
budgets = json.loads(BUDGETS.read_text())
|
||||
budgets[category.strip().lower()] = round(monthly_limit, 2)
|
||||
BUDGETS.write_text(json.dumps(budgets, indent=2, sort_keys=True))
|
||||
return budgets
|
||||
|
||||
|
||||
def _rows() -> list[dict]:
|
||||
_ensure()
|
||||
with open(LEDGER, newline="", encoding="utf-8") as f:
|
||||
return [r for r in csv.DictReader(f) if r.get("date")]
|
||||
|
||||
|
||||
def find_subscriptions(rows: list[dict] | None = None) -> list[dict]:
|
||||
"""Recurring payments: same normalized note (or category+note), same-ish
|
||||
amount, 3+ occurrences with ~monthly spacing. These are the
|
||||
cancellation-review candidates."""
|
||||
rows = rows if rows is not None else _rows()
|
||||
groups: dict[str, list[dict]] = defaultdict(list)
|
||||
for r in rows:
|
||||
if r["kind"] != "out":
|
||||
continue
|
||||
key = (r["note"] or r["category"]).strip().lower()
|
||||
groups[key].append(r)
|
||||
subs = []
|
||||
for key, items in groups.items():
|
||||
if len(items) < 3:
|
||||
continue
|
||||
items.sort(key=lambda r: r["date"])
|
||||
gaps = [
|
||||
(datetime.fromisoformat(items[i + 1]["date"]) - datetime.fromisoformat(items[i]["date"])).days
|
||||
for i in range(len(items) - 1)
|
||||
]
|
||||
if gaps and all(20 <= g <= 45 for g in gaps):
|
||||
amounts = {float(i["amount"]) for i in items}
|
||||
subs.append(
|
||||
{
|
||||
"note": key,
|
||||
"occurrences": len(items),
|
||||
"monthly": sorted(amounts)[-1],
|
||||
"first": items[0]["date"],
|
||||
"last": items[-1]["date"],
|
||||
}
|
||||
)
|
||||
subs.sort(key=lambda s: -s["monthly"])
|
||||
return subs
|
||||
|
||||
|
||||
def report(month: str | None = None, week: bool = False) -> dict:
|
||||
"""Per-category totals vs budgets + income vs spend + subscription flags."""
|
||||
rows = _rows()
|
||||
if week:
|
||||
start = (date.today() - timedelta(days=7)).isoformat()
|
||||
rows = [r for r in rows if r["date"] >= start]
|
||||
elif month:
|
||||
rows = [r for r in rows if r["date"].startswith(month)]
|
||||
income = sum(float(r["amount"]) for r in rows if r["kind"] == "in")
|
||||
spend = sum(float(r["amount"]) for r in rows if r["kind"] == "out")
|
||||
by_cat: dict[str, float] = defaultdict(float)
|
||||
for r in rows:
|
||||
if r["kind"] == "out":
|
||||
by_cat[r["category"]] += float(r["amount"])
|
||||
budgets = json.loads(BUDGETS.read_text()) if BUDGETS.exists() else {}
|
||||
over = [
|
||||
{"category": c, "spent": round(s, 2), "budget": budgets[c], "over_by": round(s - budgets[c], 2)}
|
||||
for c, s in sorted(by_cat.items())
|
||||
if c in budgets and s > budgets[c]
|
||||
]
|
||||
return {
|
||||
"income": round(income, 2),
|
||||
"spend": round(spend, 2),
|
||||
"net": round(income - spend, 2),
|
||||
"by_category": {c: round(v, 2) for c, v in sorted(by_cat.items(), key=lambda kv: -kv[1])},
|
||||
"over_budget": over,
|
||||
"subscription_candidates": find_subscriptions(rows),
|
||||
"entries": len(rows),
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description="#3: finances — every penny matters")
|
||||
sub = ap.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
p_add = sub.add_parser("add")
|
||||
p_add.add_argument("amount", type=float)
|
||||
p_add.add_argument("category")
|
||||
p_add.add_argument("note", nargs="?", default="")
|
||||
p_add.add_argument("--kind", choices=["in", "out"])
|
||||
p_add.add_argument("--date", dest="when")
|
||||
|
||||
p_b = sub.add_parser("budget")
|
||||
p_b.add_argument("category")
|
||||
p_b.add_argument("limit", type=float)
|
||||
|
||||
p_r = sub.add_parser("report")
|
||||
p_r.add_argument("--month", help="YYYY-MM")
|
||||
p_r.add_argument("--week", action="store_true")
|
||||
|
||||
args = ap.parse_args()
|
||||
if args.cmd == "add":
|
||||
row = add(args.amount, args.category, args.note, args.kind, args.when)
|
||||
print(f"recorded: {row['kind']} {row['amount']} on {row['category']} ({row['date']})")
|
||||
elif args.cmd == "budget":
|
||||
b = set_budget(args.category, args.limit)
|
||||
print(f"budgets: {json.dumps(b, sort_keys=True)}")
|
||||
elif args.cmd == "report":
|
||||
r = report(args.month, args.week)
|
||||
print(json.dumps(r, indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,164 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""forge_board.py — #204: the forge as the single pipeline state machine.
|
||||
|
||||
Reads the forge's OWN state (open issues, labels, CI status on each head)
|
||||
and derives the next action per issue. No agent memory involved: any agent
|
||||
(or a crashed-and-replaced session) runs this and knows what happens next.
|
||||
|
||||
Derivation rules (deterministic, zero tokens):
|
||||
1. issue carries `blocked` -> BLOCKED (say on what, from the body)
|
||||
2. head has failing CI -> FIX FIRST (fault-watch contract)
|
||||
3. head has pending CI -> WAITING (subject + ETA shape)
|
||||
4. issue carries `awaiting-review`-> REVIEW (reviewer gates decide)
|
||||
5. no linked work (no contract) -> OPEN CONTRACT (scaffolding is absolute)
|
||||
6. otherwise -> IMPLEMENT per the body's acceptance
|
||||
|
||||
Exit codes: 0 = board read; 1 = forge unreachable; 2 = no open issues
|
||||
(the factory's only other legal stop).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
|
||||
Fetch = Callable[[str], Optional[Dict[str, Any]]]
|
||||
|
||||
BLOCKED_LABELS = {"blocked", "waiting-on-user", "on-hold"}
|
||||
REVIEW_LABELS = {"awaiting-review", "in-review", "review-required"}
|
||||
CI_PENDING = {"pending", "running", "unknown"}
|
||||
CI_FAILED = {"failure", "cancelled"}
|
||||
|
||||
|
||||
def derive_next_action(issue: Dict[str, Any], ci_state: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
||||
"""Pure derivation: forge state in, next action out. No network, no memory."""
|
||||
labels = {l.get("name", "") for l in issue.get("labels", [])}
|
||||
num = issue.get("number")
|
||||
title = issue.get("title", "")
|
||||
|
||||
if labels & BLOCKED_LABELS:
|
||||
return {
|
||||
"issue": num,
|
||||
"title": title,
|
||||
"action": "BLOCKED",
|
||||
"why": "carries a blocking label; unblock before the queue touches it",
|
||||
}
|
||||
|
||||
if ci_state:
|
||||
verdict = ci_state.get("verdict")
|
||||
if verdict in CI_FAILED:
|
||||
return {
|
||||
"issue": num,
|
||||
"title": title,
|
||||
"action": "FIX FIRST",
|
||||
"why": f"CI on head {ci_state.get('sha', '?')[:8]} is {verdict}; the fault-watch contract fixes the submit before the queue resumes",
|
||||
}
|
||||
if verdict in CI_PENDING:
|
||||
return {
|
||||
"issue": num,
|
||||
"title": title,
|
||||
"action": "WAITING",
|
||||
"why": f"CI on head {ci_state.get('sha', '?')[:8]} is {verdict}; factory multiplexes the next batch meanwhile",
|
||||
}
|
||||
|
||||
if labels & REVIEW_LABELS:
|
||||
return {
|
||||
"issue": num,
|
||||
"title": title,
|
||||
"action": "REVIEW",
|
||||
"why": "awaiting reviewer gates (spec-compliance + code-quality)",
|
||||
}
|
||||
|
||||
body = issue.get("body") or ""
|
||||
if "BUILDER-" in body:
|
||||
return {
|
||||
"issue": num,
|
||||
"title": title,
|
||||
"action": "CONTINUE CONTRACT",
|
||||
"why": "a construction contract is already linked in the body",
|
||||
}
|
||||
return {
|
||||
"issue": num,
|
||||
"title": title,
|
||||
"action": "OPEN CONTRACT",
|
||||
"why": "no linked work in the body; scaffolding is absolute — contract first",
|
||||
}
|
||||
|
||||
|
||||
def read_board(
|
||||
fetch: Fetch, owner: str = "conductor", repo: str = "rune", base: str = "http://127.0.0.1:3000/api/v1"
|
||||
) -> Dict[str, Any]:
|
||||
"""Pull open issues + CI state from the forge and derive the board."""
|
||||
raw = fetch(f"{base}/repos/{owner}/{repo}/issues?state=open&limit=50")
|
||||
if raw is None:
|
||||
raise RuntimeError("forge unreachable")
|
||||
issues = raw if isinstance(raw, list) else raw.get("data", [])
|
||||
|
||||
board: List[Dict[str, Any]] = []
|
||||
for issue in issues:
|
||||
sha = _head_sha_from_labels(issue) or _head_sha_from_body(issue)
|
||||
ci_state = None
|
||||
if sha:
|
||||
status = fetch(f"{base}/repos/{owner}/{repo}/commits/{sha}/status")
|
||||
if status:
|
||||
ci_state = {"sha": sha, "verdict": status.get("state", "unknown")}
|
||||
board.append(derive_next_action(issue, ci_state))
|
||||
|
||||
order = {"FIX FIRST": 0, "CONTINUE CONTRACT": 1, "OPEN CONTRACT": 2, "REVIEW": 3, "WAITING": 4, "BLOCKED": 5}
|
||||
board.sort(key=lambda r: (order.get(r["action"], 9), r["issue"] or 0))
|
||||
return {"repo": f"{owner}/{repo}", "open": len(board), "board": board}
|
||||
|
||||
|
||||
def _head_sha_from_labels(issue: Dict[str, Any]) -> Optional[str]:
|
||||
for l in issue.get("labels", []):
|
||||
name = l.get("name", "")
|
||||
if name.startswith("head:"):
|
||||
return name.split("head:", 1)[1].strip()
|
||||
return None
|
||||
|
||||
|
||||
def _head_sha_from_body(issue: Dict[str, Any]) -> Optional[str]:
|
||||
import re
|
||||
|
||||
m = re.search(r"\b([0-9a-f]{40})\b", issue.get("body") or "")
|
||||
return m.group(1) if m else None
|
||||
|
||||
|
||||
def _default_fetch(url: str) -> Optional[Any]:
|
||||
try:
|
||||
import urllib.request
|
||||
|
||||
sys.path.insert(0, "/home/nick/.config/opencode/shared")
|
||||
from gitea_auth import load_gitea_token
|
||||
|
||||
req = urllib.request.Request(url, headers={"Authorization": f"token {load_gitea_token()}"})
|
||||
with urllib.request.urlopen(req, timeout=10) as r:
|
||||
return json.load(r)
|
||||
except Exception: # noqa: BLE001 — fetcher probe: unreachability is reported upstream as a hard error (read_board raises)
|
||||
return None
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description="#204 forge board: the next action, from forge state alone")
|
||||
ap.add_argument("--json", action="store_true", help="machine-readable output")
|
||||
args = ap.parse_args()
|
||||
try:
|
||||
board = read_board(_default_fetch)
|
||||
except RuntimeError as e:
|
||||
print(f"forge_board: {e}", file=sys.stderr)
|
||||
return 1
|
||||
if args.json:
|
||||
print(json.dumps(board, indent=2))
|
||||
else:
|
||||
print(f"== FORGE BOARD {board['repo']} — {board['open']} open ==")
|
||||
for row in board["board"]:
|
||||
print(f" #{row['issue']} [{row['action']}] {row['title'][:60]} — {row['why']}")
|
||||
if board["open"] == 0:
|
||||
return 2
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,111 +0,0 @@
|
||||
import json, sys
|
||||
sys.path.insert(0, 'src')
|
||||
from rune.adaptive_router import (
|
||||
classify_route, derive_sufficiency, body_has_floor_trigger, floor_applies,
|
||||
escalate_route, downgrade_route, escalate_on_verification_failure,
|
||||
build_research_dispatch, FloorViolation,
|
||||
)
|
||||
|
||||
cases = []
|
||||
ESC_EVIDENCE = "the fix works locally but the production parser accepts different input shapes — input contract uncertain"
|
||||
|
||||
cr_cases = [
|
||||
("local_fix_happy", "fix the broken typewriter regex in warm_router, crash on empty input",
|
||||
dict(has_local_repro=True, owning_authority_known=True, testable_locally=True, narrow_and_reversible=True)),
|
||||
("standard_change", "add a progress bar to the export dialog",
|
||||
dict(has_local_repro=True, owning_authority_known=True, testable_locally=True, narrow_and_reversible=True)),
|
||||
("defect_word_absent", "update the version number in the footer",
|
||||
dict(has_local_repro=True, owning_authority_known=True, testable_locally=False, narrow_and_reversible=True)),
|
||||
("floor_new_subsystem", "adopt a new subsystem for memory indexing, replacement of spine",
|
||||
dict(has_local_repro=False, owning_authority_known=False)),
|
||||
("risk_new_authority", "this creates a new authority path for dispatch",
|
||||
dict(has_local_repro=False, owning_authority_known=False)),
|
||||
("uncertainty_competing", "there are competing designs here, expensive reversal likely",
|
||||
dict(has_local_repro=True, owning_authority_known=True)),
|
||||
("not_grounded", "add support for markdown export",
|
||||
dict(has_local_repro=False, owning_authority_known=True, testable_locally=True, narrow_and_reversible=True)),
|
||||
("inspection_verb", "explain why the failing test fails",
|
||||
dict(has_local_repro=True, owning_authority_known=True, testable_locally=True, narrow_and_reversible=True)),
|
||||
]
|
||||
for name, body, kw in cr_cases:
|
||||
d = classify_route(body, **kw)
|
||||
cases.append({"fn": "classify", "name": name,
|
||||
"input": {"body": body, **kw, "pipeline_sha": "UNKNOWN"},
|
||||
"expected": {"route": d.route, "confidence": d.confidence, "reasons": d.reasons,
|
||||
"risk": d.risk_flags, "uncertainty": d.uncertainty_flags,
|
||||
"floor": d.floor, "task_description": d.task_description}})
|
||||
|
||||
ds_cases = [
|
||||
("grounded_fix", "fix crash", "the parser crashes on empty input, see tests/test_parse.py"),
|
||||
("mechanism", "investigate", "performance is bad under load, benchmark needed"),
|
||||
("external_url", "read the docs", "see https://example.com/api docs for the endpoint"),
|
||||
("version_risk", "upgrade", "upgrade the library to latest version, current behaviour differs"),
|
||||
("inspection", "explain", "why does this happen"),
|
||||
("new_subsystem", "adopt", "this adopts a replacement architecture"),
|
||||
("neutral", "write", "a poem about the sea"),
|
||||
]
|
||||
for name, title, body in ds_cases:
|
||||
s = derive_sufficiency(title, body)
|
||||
cases.append({"fn": "derive", "name": name,
|
||||
"input": {"title": title, "body": body, "ambiguous": False},
|
||||
"expected": {"local_authority": s.local_authority,
|
||||
"external_dependency": s.external_dependency,
|
||||
"version_freshness_risk": s.version_freshness_risk,
|
||||
"verifiability": s.verifiability, "scope_novelty": s.scope_novelty,
|
||||
"unknowns": s.unknowns(),
|
||||
"task_class": s.provenance.get("task_class_language")}})
|
||||
|
||||
cases.append({"fn": "floor_trigger", "name": "trigger_yes",
|
||||
"input": {"body": "adopt a replacement for the cache"},
|
||||
"expected": {"result": body_has_floor_trigger("adopt a replacement for the cache")}})
|
||||
cases.append({"fn": "floor_trigger", "name": "trigger_no",
|
||||
"input": {"body": "fix the typo"},
|
||||
"expected": {"result": body_has_floor_trigger("fix the typo")}})
|
||||
cases.append({"fn": "floor_applies", "name": "res_yes", "input": {"route": "RESEARCHED_CHANGE", "flags": ["new_authority"]},
|
||||
"expected": {"result": floor_applies("RESEARCHED_CHANGE", ["new_authority"])}})
|
||||
cases.append({"fn": "floor_applies", "name": "local_no", "input": {"route": "LOCAL_FIX", "flags": ["new_authority"]},
|
||||
"expected": {"result": floor_applies("LOCAL_FIX", ["new_authority"])}})
|
||||
|
||||
base = classify_route("fix the crash", has_local_repro=True, owning_authority_known=True,
|
||||
testable_locally=True, narrow_and_reversible=True)
|
||||
esc = escalate_route(base, "RESEARCHED_CHANGE", "verify_fail", ESC_EVIDENCE)
|
||||
cases.append({"fn": "escalate", "name": "esc",
|
||||
"input": {"decision_route": base.route, "new_route": "RESEARCHED_CHANGE",
|
||||
"trigger": "verify_fail", "evidence": ESC_EVIDENCE},
|
||||
"expected": {"route": esc.route, "previous": esc.previous_route,
|
||||
"decided_by": esc.decided_by, "trigger": esc.trigger}})
|
||||
|
||||
try:
|
||||
downgrade_route(base, "STANDARD_CHANGE", "try", "ev")
|
||||
cases.append({"fn": "downgrade", "name": "dg_ok", "input": {"base_route": base.route, "base_floor": False,
|
||||
"new_route": "STANDARD_CHANGE"}, "expected": {"route": "STANDARD_CHANGE", "error": None}})
|
||||
except FloorViolation:
|
||||
cases.append({"fn": "downgrade", "name": "dg_ok", "input": {}, "expected": {"route": None, "error": "FloorViolation"}})
|
||||
|
||||
floored = classify_route("adopt a replacement for the memory index")
|
||||
try:
|
||||
downgrade_route(floored, "STANDARD_CHANGE", "efficiency", "faster")
|
||||
cases.append({"fn": "downgrade", "name": "dg_floored", "input": {"base_floor": True, "new_route": "STANDARD_CHANGE"},
|
||||
"expected": {"route": "STANDARD_CHANGE", "error": None}})
|
||||
except FloorViolation:
|
||||
cases.append({"fn": "downgrade", "name": "dg_floored", "input": {"base_floor": True, "new_route": "STANDARD_CHANGE"},
|
||||
"expected": {"route": None, "error": "FloorViolation"}})
|
||||
|
||||
try:
|
||||
escalate_on_verification_failure(base, "test failed", "/tmp/ar_probe.jsonl")
|
||||
cases.append({"fn": "evidence_short", "name": "short", "input": {"evidence": "test failed"},
|
||||
"expected": {"result": "ACCEPTED"}})
|
||||
except ValueError:
|
||||
cases.append({"fn": "evidence_short", "name": "short", "input": {"evidence": "test failed"},
|
||||
"expected": {"result": "REJECTED"}})
|
||||
|
||||
disp = build_research_dispatch("T-1", "research the memory index options", floored)
|
||||
cases.append({"fn": "dispatch", "name": "disp",
|
||||
"input": {"task_id": "T-1", "description": "research the memory index options"},
|
||||
"expected": {"task_id": disp["task_id"], "title": disp["title"], "route": disp["route"],
|
||||
"floor": disp["floor"], "executor_entry": disp["executor_entry"]}})
|
||||
|
||||
json.dump(cases, open('src/go/adaptive-router/truth.json', 'w'), indent=1)
|
||||
print(f"{len(cases)} truth cases with inputs")
|
||||
for c in cases:
|
||||
print(f" {c['fn']:14} {c['name']}")
|
||||
@@ -1,115 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_build_mode_truth.py — build-mode batch 1 truth battery
|
||||
(contract BUILDER-2026-10-07T17:08:00Z-6e177d-unknown).
|
||||
|
||||
The LIVE BuildManager runs with the clock FROZEN (module-patched datetime)
|
||||
and create_worktree no-op'd (reactive piece, deferred to batch 2). Cases
|
||||
capture: the start_build id format, the ledger flow across phases
|
||||
(including a failure + correction), resume-point scans at several states,
|
||||
and the status shape. The Go replay compares state dicts key-for-key.
|
||||
|
||||
Usage: python3 scripts/gen_build_mode_truth.py (from repo root)
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
|
||||
from rune import build_mode as bm # noqa: E402
|
||||
|
||||
FROZEN = "2026-10-07T16:08:00"
|
||||
FROZEN_DT = datetime(2026, 10, 7, 16, 8, 0, tzinfo=timezone.utc)
|
||||
|
||||
|
||||
class FrozenDatetime(datetime):
|
||||
@classmethod
|
||||
def now(cls, tz=None):
|
||||
return FROZEN_DT
|
||||
|
||||
|
||||
def main():
|
||||
# Freeze the clock (the manager reads datetime.now at two call sites)
|
||||
bm.datetime = FrozenDatetime
|
||||
|
||||
def flow(name, steps):
|
||||
"""Run a phase flow with the worktree op no-op'd; record the CALLS."""
|
||||
mgr = bm.BuildManager()
|
||||
mgr.create_worktree = lambda: "/nonexistent-worktree" # reactive no-op
|
||||
build_id = mgr.start_build("truth battery build")
|
||||
calls = []
|
||||
for fn, args in steps:
|
||||
fn(mgr, **args)
|
||||
calls.append({"fn": fn.__name__, "args": args})
|
||||
return {
|
||||
"name": name,
|
||||
"build_id": build_id,
|
||||
"calls": calls,
|
||||
"state": _jsonify(mgr.state),
|
||||
"resume_point": mgr.get_resume_point(),
|
||||
"can_resume": mgr.can_resume(),
|
||||
"status": mgr.get_status(),
|
||||
}
|
||||
|
||||
def step(fn, **args):
|
||||
return (fn, args)
|
||||
|
||||
cases = [
|
||||
flow("fresh_start_assess_in_progress", []),
|
||||
flow("assess_complete", [
|
||||
step(bm.BuildManager.complete_assess, complexity_report={"complexity": 3}),
|
||||
]),
|
||||
flow("through_plan", [
|
||||
step(bm.BuildManager.complete_assess, complexity_report={"complexity": 3}),
|
||||
step(bm.BuildManager.complete_research, findings={"findings": "dichotomy applies"}),
|
||||
step(bm.BuildManager.complete_feasible, feasible=True, risk="low"),
|
||||
step(bm.BuildManager.complete_consult, patterns=["oracle-battery pattern"]),
|
||||
step(bm.BuildManager.complete_consent, approved=True),
|
||||
step(bm.BuildManager.complete_plan, batches=[{"batch": 1, "fns": 11}]),
|
||||
]),
|
||||
flow("verify_with_failures", [
|
||||
step(bm.BuildManager.complete_assess, complexity_report={}),
|
||||
step(bm.BuildManager.complete_research, findings={}),
|
||||
step(bm.BuildManager.complete_feasible, feasible=True, risk="low"),
|
||||
step(bm.BuildManager.complete_consult, patterns=[]),
|
||||
step(bm.BuildManager.complete_consent, approved=True),
|
||||
step(bm.BuildManager.complete_plan, batches=[]),
|
||||
step(bm.BuildManager.complete_build_phase, results=[{"ok": True}]),
|
||||
step(bm.BuildManager.complete_verify, passed=False, failures=["test_x failed"]),
|
||||
]),
|
||||
flow("correction_cycle", [
|
||||
step(bm.BuildManager.complete_assess, complexity_report={}),
|
||||
step(bm.BuildManager.complete_research, findings={}),
|
||||
step(bm.BuildManager.complete_feasible, feasible=True, risk="low"),
|
||||
step(bm.BuildManager.complete_consult, patterns=[]),
|
||||
step(bm.BuildManager.complete_consent, approved=True),
|
||||
step(bm.BuildManager.complete_plan, batches=[{"batch": 1}]),
|
||||
step(bm.BuildManager.start_correct),
|
||||
step(bm.BuildManager.complete_correct, fixed=True),
|
||||
]),
|
||||
]
|
||||
|
||||
out = {
|
||||
"oracle": "src/rune/build_mode.py (live BuildManager, clock frozen)",
|
||||
"generated": "2026-10-07",
|
||||
"frozen_now": FROZEN,
|
||||
"cases": cases,
|
||||
}
|
||||
target = REPO / "src/go/build-mode" / "truth_buildmode.json"
|
||||
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
|
||||
print(f"wrote {target} ({len(cases)} flow cases)")
|
||||
|
||||
|
||||
def _jsonify(state):
|
||||
"""asdict + the worktree path the no-op returned."""
|
||||
from dataclasses import asdict
|
||||
d = asdict(state)
|
||||
return d
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,148 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_build_mode_wt_truth.py — build-mode batch 2 truth battery
|
||||
(contract BUILDER-2026-10-07T18:26:40Z-8be89a).
|
||||
|
||||
The LIVE BuildManager drives a REAL tmp git repo: create → state captured,
|
||||
merge → state captured, delete → state captured. Cases carry the exact
|
||||
argv sequences (from monkeypatched subprocess.run) + the state after each
|
||||
op + the error texts. The Go plan layer must produce the same argv; the
|
||||
Go exec harness proves the plans drive real git.
|
||||
|
||||
Usage: python3 scripts/gen_build_mode_wt_truth.py (from repo root)
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
|
||||
from rune import build_mode as bm # noqa: E402
|
||||
|
||||
FROZEN = "2026-10-07T18:28:00"
|
||||
|
||||
|
||||
class FrozenDatetime(datetime):
|
||||
@classmethod
|
||||
def now(cls, tz=None):
|
||||
return datetime(2026, 10, 7, 18, 28, 0, tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def main():
|
||||
bm.datetime = FrozenDatetime
|
||||
bm.REPO_DIR = str(make_git_repo())
|
||||
|
||||
calls = []
|
||||
|
||||
def spy_run(cmd, **kwargs):
|
||||
calls.append(list(cmd))
|
||||
return subprocess.CompletedProcess(cmd, 0, "", "")
|
||||
|
||||
bm.subprocess.run = spy_run
|
||||
|
||||
mgr = bm.BuildManager()
|
||||
build_id = mgr.start_build("worktree battery") # create_worktree inside
|
||||
create_call = calls[0]
|
||||
after_create = mgr.state.worktree_path
|
||||
|
||||
n_before_merge = len(calls)
|
||||
mgr.merge_worktree()
|
||||
merge_call = calls[n_before_merge] # the merge itself
|
||||
after_merge = mgr.state.worktree_path # None: delete follows the merge
|
||||
delete_call = calls[n_before_merge + 1], calls[n_before_merge + 2]
|
||||
|
||||
cases = [
|
||||
{
|
||||
"fn": "plan", "name": "create",
|
||||
"expected": {"argv": create_call},
|
||||
},
|
||||
{
|
||||
"fn": "plan", "name": "merge",
|
||||
"expected": {"argv": merge_call},
|
||||
},
|
||||
{
|
||||
"fn": "plan", "name": "delete_pair",
|
||||
"expected": {"argv": [list(delete_call[0]), list(delete_call[1])]},
|
||||
},
|
||||
{
|
||||
"fn": "state", "name": "round_trip",
|
||||
"expected": {
|
||||
"build_id": build_id,
|
||||
"after_create_is_set": after_create is not None,
|
||||
"after_merge_is_none": after_merge is None,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
# error texts: merge failure mapping
|
||||
def fail_run(cmd, **kwargs):
|
||||
if cmd[1] == "merge":
|
||||
return subprocess.CompletedProcess(cmd, 128, "", "fatal: not something we can merge")
|
||||
return subprocess.CompletedProcess(cmd, 0, "", "")
|
||||
bm.subprocess.run = fail_run
|
||||
mgr2 = bm.BuildManager()
|
||||
mgr2.state = bm.BuildState(
|
||||
build_id="20261007-182800", description="error battery",
|
||||
created_at=FROZEN)
|
||||
wt = "/home/nick/.rune/worktrees/20261007-182800"
|
||||
mgr2.state.worktree_path = wt # merge_worktree requires a live worktree path
|
||||
try:
|
||||
mgr2.merge_worktree()
|
||||
merge_err = None
|
||||
except RuntimeError as ex:
|
||||
merge_err = str(ex)
|
||||
cases.append({
|
||||
"fn": "error", "name": "merge_failure_text",
|
||||
"expected": {"error": merge_err},
|
||||
})
|
||||
|
||||
def fail_create(cmd, **kwargs):
|
||||
if cmd[1] == "worktree":
|
||||
return subprocess.CompletedProcess(cmd, 128, "", "'x' already exists")
|
||||
return subprocess.CompletedProcess(cmd, 0, "", "")
|
||||
bm.subprocess.run = fail_create
|
||||
mgr3 = bm.BuildManager()
|
||||
mgr3.state = bm.BuildState(
|
||||
build_id="20261007-182800", description="error battery 2",
|
||||
created_at=FROZEN)
|
||||
mgr3._save_state()
|
||||
try:
|
||||
mgr3.create_worktree()
|
||||
create_err = None
|
||||
except RuntimeError as ex:
|
||||
create_err = str(ex)
|
||||
cases.append({
|
||||
"fn": "error", "name": "create_failure_text",
|
||||
"expected": {"error": create_err},
|
||||
})
|
||||
|
||||
out = {
|
||||
"oracle": "src/rune/build_mode.py (live BuildManager on a real tmp git repo, clock frozen)",
|
||||
"generated": "2026-10-07",
|
||||
"frozen_now": FROZEN,
|
||||
"cases": cases,
|
||||
}
|
||||
target = REPO / "src/go/build-mode" / "truth_worktree.json"
|
||||
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
|
||||
print(f"wrote {target} ({len(cases)} cases)")
|
||||
|
||||
|
||||
def make_git_repo():
|
||||
root = tempfile.mkdtemp(prefix="bm-wt-truth-")
|
||||
env_realloc = subprocess.run(
|
||||
["git", "init", "-q"], cwd=root, capture_output=True, text=True)
|
||||
assert env_realloc.returncode == 0
|
||||
subprocess.run(["git", "config", "user.email", "t@t"], cwd=root, capture_output=True)
|
||||
subprocess.run(["git", "config", "user.name", "t"], cwd=root, capture_output=True)
|
||||
(Path(root) / "seed.txt").write_text("seed\n")
|
||||
subprocess.run(["git", "add", "."], cwd=root, capture_output=True)
|
||||
subprocess.run(["git", "commit", "-qm", "seed"], cwd=root, capture_output=True)
|
||||
return root
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_cache_hash_truth.py — factory batch 6 truth battery (live cache._hash)."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import cache as ch # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
cases = [
|
||||
{"fn": "hash", "name": "ascii", "input": {"text": s},
|
||||
"expected": {"hash": ch._hash(s)}}
|
||||
for s in ["", "hello world", "unicode ümlaut ✅", "a" * 500]
|
||||
]
|
||||
comp_inputs = [
|
||||
"",
|
||||
"# comment\n\nreal line here\n====\n// slash comment\n(_source_: x)\n[source: y]\ntiny\nkeep this line too\n\n" + "z" * 900,
|
||||
"line one\nline two\nline three",
|
||||
"====",
|
||||
"ab\ncdefgh",
|
||||
]
|
||||
for i, s in enumerate(comp_inputs):
|
||||
cases.append({"fn": "compress", "name": f"compress_{i}",
|
||||
"input": {"text": s},
|
||||
"expected": {"compressed": ch._compress(s)}})
|
||||
out = {"oracle": "cache._hash", "generated": "2026-10-07", "cases": cases}
|
||||
(REPO / "src/go/cache" / "truth_hash.json").write_text(json.dumps(out, indent=1) + "\n")
|
||||
print(f"wrote {len(cases)} cases")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,161 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_curator_lexicon_truth.py — regenerate the lexicon truth batteries
|
||||
(contract BUILDER-2026-10-07T16:31:17Z-997c9d).
|
||||
|
||||
Why: batch 1's truth.json encoded the LEXICON DEGRADE — the phantom shadow
|
||||
("lexicon module unavailable — strength gate only") — because
|
||||
lexicon_evolution.py was absent when it was generated. The phantom has now
|
||||
been recovered from provenance (commit 5749029), so the LIVE oracle returns
|
||||
real lexicon verdicts and the Go port must match THEM.
|
||||
|
||||
What this does:
|
||||
1. Rewrites ONLY the fn=='le_promote_eligible' cases inside truth.json,
|
||||
regenerated against the live curator.le_promote_eligible (which now
|
||||
delegates to the recovered lexicon_evolution). Other cases untouched.
|
||||
2. Emits truth_lexicon.json — direct live-oracle cases for the recovered
|
||||
module's full surface: coherence (conflict/consistent/novel), grounded,
|
||||
distinctive_terms, promote_eligible (shared / novel-grounded /
|
||||
novel-parked / no-signal / strength-gate).
|
||||
|
||||
Note on `existing`: the truth carries the block values as a single string;
|
||||
the oracle is called with a one-element list ([existing]) — the batch-1
|
||||
convention, documented here so the Go test wraps identically.
|
||||
|
||||
Usage: python3 scripts/gen_curator_lexicon_truth.py (from repo root)
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
from rune import curator # noqa: E402 — live oracle (imports lexicon_evolution)
|
||||
import lexicon_evolution as le # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
core = REPO / "src/go/curator-core"
|
||||
|
||||
# ── 1. regenerate the le_promote_eligible cases in truth.json ──────────
|
||||
truth_path = core / "truth.json"
|
||||
truth = json.loads(truth_path.read_text())
|
||||
replaced = 0
|
||||
for case in truth:
|
||||
if case.get("fn") != "le_promote_eligible":
|
||||
continue
|
||||
inp = case["input"]
|
||||
r = curator.le_promote_eligible(
|
||||
inp["proposal"],
|
||||
[inp["existing"]],
|
||||
inp["strength"],
|
||||
min_strength=3,
|
||||
wash_count=inp["wash_count"],
|
||||
)
|
||||
case["expected"] = {"eligible": r}
|
||||
replaced += 1
|
||||
assert replaced >= 4, f"expected >=4 le cases, found {replaced}"
|
||||
# Self-check: no case may still encode the degrade shadow.
|
||||
for case in truth:
|
||||
if case.get("fn") == "le_promote_eligible":
|
||||
assert "lexicon module unavailable" not in json.dumps(case["expected"]), case["name"]
|
||||
truth_path.write_text(json.dumps(truth, indent=1, ensure_ascii=False) + "\n")
|
||||
print(f"truth.json: {replaced} le_promote_eligible cases regenerated (live lexicon)")
|
||||
|
||||
# ── 2. the direct lexicon-surface battery ──────────────────────────────
|
||||
corpus = [
|
||||
"nick writes Go and Rust code daily in the rune repository",
|
||||
"the curator gates memory writes through worthiness and grading",
|
||||
"migration of modules follows the dichotomy: reactive goes Go, deterministic goes Rust",
|
||||
]
|
||||
|
||||
cases = []
|
||||
|
||||
def add(fn, name, inp, expected):
|
||||
cases.append({"fn": fn, "name": name, "input": inp, "expected": expected})
|
||||
|
||||
# coherence: conflict (distinctive shared term + negation ON it)
|
||||
add("coherence", "conflict",
|
||||
{"fact": "nick never writes Rust code", "existing": ["nick writes Go and Rust code daily"],
|
||||
"corpus": corpus},
|
||||
{"verdict": le.coherence("nick never writes Rust code",
|
||||
["nick writes Go and Rust code daily"], corpus)})
|
||||
# coherence: consistent (distinctive shared term, no negation)
|
||||
add("coherence", "consistent",
|
||||
{"fact": "nick writes Rust code on weekends", "existing": ["nick writes Go and Rust code daily"],
|
||||
"corpus": corpus},
|
||||
{"verdict": le.coherence("nick writes Rust code on weekends",
|
||||
["nick writes Go and Rust code daily"], corpus)})
|
||||
# coherence: novel (nothing distinctive shared)
|
||||
add("coherence", "novel_axis",
|
||||
{"fact": "nick plays bass guitar in a band", "existing": ["nick writes Go and Rust code daily"],
|
||||
"corpus": corpus},
|
||||
{"verdict": le.coherence("nick plays bass guitar in a band",
|
||||
["nick writes Go and Rust code daily"], corpus)})
|
||||
# coherence: common word only is NEVER a relation
|
||||
add("coherence", "common_word_not_relation",
|
||||
{"fact": "nick likes black coffee", "existing": ["black holes bend light"],
|
||||
"corpus": ["black coffee in the morning", "black holes bend light"]},
|
||||
{"verdict": le.coherence("nick likes black coffee", ["black holes bend light"],
|
||||
["black coffee in the morning", "black holes bend light"])})
|
||||
# coherence: empty existing -> novel
|
||||
add("coherence", "empty_existing",
|
||||
{"fact": "nick writes Rust code daily", "existing": [], "corpus": []},
|
||||
{"verdict": le.coherence("nick writes Rust code daily", [], [])})
|
||||
|
||||
# grounded: stem-aware (migrated matches migration)
|
||||
add("grounded", "stem_match",
|
||||
{"fact": "nick migrated the modules", "sources": corpus},
|
||||
{"grounded": le.grounded("nick migrated the modules", corpus)})
|
||||
add("grounded", "invented_token",
|
||||
{"fact": "nick collects vintage railway timetables", "sources": corpus},
|
||||
{"grounded": le.grounded("nick collects vintage railway timetables", corpus)})
|
||||
add("grounded", "empty_sources",
|
||||
{"fact": "nick migrated the modules", "sources": []},
|
||||
{"grounded": le.grounded("nick migrated the modules", [])})
|
||||
|
||||
# distinctive_terms: rare survives, common does not
|
||||
add("distinctive_terms", "rare_vs_common",
|
||||
{"fact": "nick writes Rust code daily", "corpus": corpus},
|
||||
{"terms": sorted(le.distinctive_terms("nick writes Rust code daily", corpus))})
|
||||
|
||||
# promote_eligible: the four verdict shapes
|
||||
add("promote_eligible", "strength_gate",
|
||||
{"proposal": "add support for retries", "existing": ["support for retries in the fetch loop"],
|
||||
"strength": 2, "min_strength": 3, "corpus": []},
|
||||
{"eligible": le.promote_eligible("add support for retries",
|
||||
["support for retries in the fetch loop"], 2, 3, ())})
|
||||
add("promote_eligible", "shared_distinctive",
|
||||
{"proposal": "add retries to the fetch loop", "existing": ["support for retries in the fetch loop"],
|
||||
"strength": 3, "min_strength": 3, "corpus": []},
|
||||
{"eligible": le.promote_eligible("add retries to the fetch loop",
|
||||
["support for retries in the fetch loop"], 3, 3, ())})
|
||||
add("promote_eligible", "novel_grounded",
|
||||
{"proposal": "the curator gates every memory write", "existing": ["nick writes Go and Rust code daily"],
|
||||
"strength": 3, "min_strength": 3, "corpus": corpus},
|
||||
{"eligible": le.promote_eligible("the curator gates every memory write",
|
||||
["nick writes Go and Rust code daily"], 3, 3, corpus)})
|
||||
add("promote_eligible", "novel_parked",
|
||||
{"proposal": "nick collects vintage railway timetables", "existing": ["nick writes Go and Rust code daily"],
|
||||
"strength": 3, "min_strength": 3, "corpus": corpus},
|
||||
{"eligible": le.promote_eligible("nick collects vintage railway timetables",
|
||||
["nick writes Go and Rust code daily"], 3, 3, corpus)})
|
||||
add("promote_eligible", "first_principle",
|
||||
{"proposal": "parking is never wrong for growth", "existing": [],
|
||||
"strength": 3, "min_strength": 3, "corpus": []},
|
||||
{"eligible": le.promote_eligible("parking is never wrong for growth", [], 3, 3, ())})
|
||||
|
||||
out = {
|
||||
"oracle": "src/rune/lexicon_evolution.py (recovered provenance 0308ccc6) via curator.py",
|
||||
"generated": "2026-10-07 (post-recovery regeneration)",
|
||||
"cases": cases,
|
||||
}
|
||||
(core / "truth_lexicon.json").write_text(
|
||||
json.dumps(out, indent=1, ensure_ascii=False) + "\n")
|
||||
print(f"truth_lexicon.json: {len(cases)} cases")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,51 +0,0 @@
|
||||
"""gen_drift_fama_truth.py — factory batch 12 truth battery (live oracle)."""
|
||||
import json
|
||||
import sqlite3
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import drift_core as dc # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
tmp = Path(tempfile.mkdtemp(prefix="fama-truth-"))
|
||||
db = sqlite3.connect(str(tmp / "t.db"))
|
||||
db.row_factory = sqlite3.Row
|
||||
db.execute("CREATE TABLE entries (id INTEGER PRIMARY KEY, status TEXT, rock_status TEXT, wash_count INTEGER)")
|
||||
rows = [
|
||||
(1, "active", "washable", 5), # valid (wash>0)
|
||||
(2, "active", "established", 0), # valid (established)
|
||||
(3, "active", "rock", 0), # valid (rock)
|
||||
(4, "active", "washable", 0), # INVALID (active, no wash, washable)
|
||||
(5, "superseded", "washable", 9), # invalid (not active)
|
||||
]
|
||||
db.executemany("INSERT INTO entries VALUES (?,?,?,?)", rows)
|
||||
db.commit()
|
||||
|
||||
cases = []
|
||||
for name, ids in [("all_valid", [1, 2, 3]), ("mixed", [1, 2, 4]),
|
||||
("with_missing", [1, 999]), ("empty", []),
|
||||
("all_invalid", [4, 5])]:
|
||||
fetched = []
|
||||
for eid in ids:
|
||||
r = db.execute("SELECT status, rock_status, wash_count FROM entries WHERE id=?", (eid,)).fetchone()
|
||||
if r:
|
||||
fetched.append(dict(r))
|
||||
cases.append({
|
||||
"fn": "fama", "name": name,
|
||||
"input": {"rows": fetched, "count": len(ids)},
|
||||
"expected": {"fama": dc.compute_fama(db, "q", ids)},
|
||||
})
|
||||
|
||||
out = {"oracle": "drift_core.compute_fama (live)", "generated": "2026-10-08", "cases": cases}
|
||||
(REPO / "src/go/drift-core" / "truth_fama.json").write_text(json.dumps(out, indent=1) + "\n")
|
||||
print(f"wrote {len(cases)} cases")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,62 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_drift_value_truth.py — factory batch 10 truth battery (live oracle)."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import drift_core as dc # noqa: E402
|
||||
|
||||
NOW = "2026-10-08T00:30:00+00:00"
|
||||
|
||||
|
||||
def main():
|
||||
entries = [
|
||||
# fresh, low everything
|
||||
{"wash_count": 0, "importance": 0.5, "text": "unproven entry", "rock_status": "washable"},
|
||||
# high proven, recent access
|
||||
{"wash_count": 25, "importance": 0.9, "text": "proven entry", "rock_status": "washable",
|
||||
"last_accessed": "2026-10-07T20:00:00+00:00"},
|
||||
# proven but stale (30+ days)
|
||||
{"wash_count": 30, "importance": 0.8, "text": "stale entry", "rock_status": "washable",
|
||||
"last_accessed": "2026-08-01T10:00:00+00:00"},
|
||||
# already rock
|
||||
{"wash_count": 40, "importance": 0.9, "text": "rocked", "rock_status": "rock"},
|
||||
# bad timestamp (degrade path)
|
||||
{"wash_count": 22, "importance": 0.7, "text": "bad ts", "rock_status": "washable",
|
||||
"last_accessed": "not-a-date"},
|
||||
# goal relevance hit
|
||||
{"wash_count": 21, "importance": 0.6, "text": "the curator gates memory writes",
|
||||
"rock_status": "washable", "last_accessed": "2026-10-06T00:00:00+00:00"},
|
||||
]
|
||||
goals = ["curator memory writes", "gate the pipeline"]
|
||||
cases = []
|
||||
for i, e in enumerate(entries):
|
||||
cases.append({
|
||||
"fn": "value", "name": f"value_{i}", "input": {"entry": e},
|
||||
"expected": {"value": dc._py_compute_value(e, None, NOW)},
|
||||
})
|
||||
cases.append({
|
||||
"fn": "promo", "name": f"promo_{i}", "input": {"entry": e},
|
||||
"expected": {"eligible": dc._py_check_promotion_eligibility(e, NOW)[0],
|
||||
"reason": dc._py_check_promotion_eligibility(e, NOW)[1]},
|
||||
})
|
||||
# goal-relevance path
|
||||
cases.append({
|
||||
"fn": "value", "name": "with_goals", "input": {"entry": entries[5], "goals": goals},
|
||||
"expected": {"value": dc._py_compute_value(entries[5], goals, NOW)},
|
||||
})
|
||||
|
||||
out = {"oracle": "drift_core._py_* oracles", "generated": "2026-10-08",
|
||||
"frozen_now": NOW, "cases": cases}
|
||||
(REPO / "src/go/drift-core" / "truth_value.json").write_text(
|
||||
json.dumps(out, indent=1) + "\n")
|
||||
print(f"wrote {len(cases)} cases")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_event_bus_truth.py — factory batch 9 truth battery (live oracle)."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import event_bus as eb # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
payloads = [
|
||||
{},
|
||||
{"k": "v"},
|
||||
{"task_id": "t1", "status": "failed", "count": 3},
|
||||
{"nested": {"a": [1, 2, "x"]}, "flag": True, "nothing": None},
|
||||
{"text": "quote\" inside\\ back\nnewline\ttab"},
|
||||
{"float_int": 1.0, "float_frac": 2.5},
|
||||
]
|
||||
cases = [
|
||||
{"fn": "hash", "name": f"payload_{i}", "input": {"payload": p},
|
||||
"expected": {"hash": eb._content_hash(p)}}
|
||||
for i, p in enumerate(payloads)
|
||||
]
|
||||
out = {"oracle": "event_bus._content_hash", "generated": "2026-10-07", "cases": cases}
|
||||
(REPO / "src/go/event-bus" / "truth_bus.json").write_text(json.dumps(out, indent=1) + "\n")
|
||||
print(f"wrote {len(cases)} cases")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_hook_placement_truth.py — factory batch 4 truth battery
|
||||
(contract BUILDER-2026-10-07T23:06:18Z-ec6208).
|
||||
|
||||
The LIVE recommend_placement oracle over a factor matrix covering every
|
||||
branch: hook-point combos, frequency ladder, cache scopes, concurrency,
|
||||
failure modes, context budget.
|
||||
|
||||
Usage: python3 scripts/gen_hook_placement_truth.py (from repo root)
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import hook_engine as he # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
factor_sets = [
|
||||
{"output_dep": True},
|
||||
{"input_dep": True},
|
||||
{"input_dep": True, "output_dep": True},
|
||||
{},
|
||||
{"side_effects": "read-write"},
|
||||
{"volatility": "session"},
|
||||
{"volatility": "per-turn"},
|
||||
{"scope": "persistent"},
|
||||
{"scope": "session"},
|
||||
{"concurrent": True},
|
||||
{"failure": "fail-loud"},
|
||||
{"context_budget": 500},
|
||||
{"input_dep": True, "scope": "session", "concurrent": True,
|
||||
"context_budget": 250},
|
||||
{"side_effects": "read-write", "failure": "fail-loud",
|
||||
"scope": "persistent"},
|
||||
]
|
||||
cases = []
|
||||
for i, factors in enumerate(factor_sets):
|
||||
cases.append({
|
||||
"fn": "placement", "name": f"matrix_{i}",
|
||||
"input": {"factors": factors},
|
||||
"expected": he.recommend_placement(f"hook_{i}", factors),
|
||||
})
|
||||
|
||||
out = {
|
||||
"oracle": "src/rune/hook_engine.py recommend_placement (live)",
|
||||
"generated": "2026-10-07",
|
||||
"cases": cases,
|
||||
}
|
||||
target = REPO / "src/go/hook-engine" / "truth_placement.json"
|
||||
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
|
||||
print(f"wrote {target} ({len(cases)} cases)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,118 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_memory_store_gate_truth.py — memory-store batch 4 truth battery
|
||||
(contract BUILDER-2026-10-07T19:47:37Z-1cf1dc).
|
||||
|
||||
The LIVE oracle: the dense-side meta-judgement extracted from recall()
|
||||
(lines 655-676) exercised against a FIXTURE STORE (sqlite entries + df
|
||||
counts), plus the entries-side fusion vs the chunk-side one (identity
|
||||
check), plus the abstain constants.
|
||||
|
||||
Usage: python3 scripts/gen_memory_store_gate_truth.py (from repo root)
|
||||
"""
|
||||
|
||||
import json
|
||||
import sqlite3
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import memory_store as ms # noqa: E402
|
||||
|
||||
|
||||
def make_fixture_store(db_path):
|
||||
"""Entries table + df data mirroring recall()'s df-of-word query."""
|
||||
db = sqlite3.connect(db_path)
|
||||
db.row_factory = sqlite3.Row
|
||||
db.execute("CREATE TABLE entries (id INTEGER PRIMARY KEY, text TEXT, status TEXT)")
|
||||
rows = [
|
||||
(1, "the curator gates memory writes through worthiness"),
|
||||
(2, "black holes bend light near the event horizon"),
|
||||
(3, "black coffee in the morning keeps nick running"),
|
||||
(4, "the spine rebuild parity proofs live in store"),
|
||||
(5, "memory writes require the operator approval gate"),
|
||||
(6, "unrelated filler text about weather patterns"),
|
||||
(7, "curator provenance recovery from odysseus"),
|
||||
(8, "another filler row to pad the document frequency"),
|
||||
]
|
||||
db.executemany("INSERT INTO entries VALUES (?,?,?)",
|
||||
[(i, t, "active") for (i, t) in rows])
|
||||
db.commit()
|
||||
return db
|
||||
|
||||
|
||||
def main():
|
||||
tmp = Path(tempfile.mkdtemp(prefix="ms-gate-truth-"))
|
||||
db = make_fixture_store(str(tmp / "store.db"))
|
||||
total = db.execute("SELECT COUNT(*) AS n FROM entries WHERE status='active'").fetchone()["n"]
|
||||
|
||||
def df_of(word):
|
||||
return db.execute(
|
||||
"SELECT COUNT(*) AS n FROM entries WHERE status='active' AND text LIKE ?",
|
||||
(f"%{word}%",),
|
||||
).fetchone()["n"]
|
||||
|
||||
# replicate recall()'s dense-gate block verbatim
|
||||
def oracle_gate(query, hits):
|
||||
q_content = {t for t in query.lower().split() if len(t) > 3 and t not in ms._STOPWORDS}
|
||||
dense = []
|
||||
for rowid, cos in hits:
|
||||
etxt = (db.execute("SELECT text FROM entries WHERE id=?", (rowid,)).fetchone()["text"] or "").lower()
|
||||
distinctive = [w for w in q_content if w in etxt and df_of(w) / total < 0.05]
|
||||
if distinctive:
|
||||
dense.append((rowid, cos))
|
||||
elif not q_content or cos >= 0.80:
|
||||
dense.append((rowid, cos))
|
||||
return dense
|
||||
|
||||
cases = []
|
||||
|
||||
def add(fn, name, inp, expected):
|
||||
cases.append({"fn": fn, "name": name, "input": inp, "expected": expected})
|
||||
|
||||
# gate: shared DISTINCTIVE word (curator: df=2/8=0.25? no — check)
|
||||
# df(curator) = rows 1,7 = 2 → 0.25 ≥ 0.05 → NOT distinctive!
|
||||
# The oracle's threshold means common-store words fail; only truly
|
||||
# rare words pass. Fixture exercise:
|
||||
for name, query, hits in [
|
||||
("distinctive_shared", "worthiness gates", [(1, 0.9), (2, 0.85)]),
|
||||
("common_word_falls_back", "black", [(2, 0.86), (3, 0.79)]),
|
||||
("strong_cos_no_share", "unrelated query terms", [(6, 0.91), (4, 0.70)]),
|
||||
("no_content_words", "the was and", [(1, 0.60), (6, 0.95)]),
|
||||
]:
|
||||
add("dense_gate", name,
|
||||
{"query": query, "hits": [[r, c] for r, c in hits], "total": total},
|
||||
{"kept": [[r, c] for r, c in oracle_gate(query, hits)],
|
||||
"q_content": sorted({t for t in query.lower().split() if len(t) > 3 and t not in ms._STOPWORDS}),
|
||||
"df": {w: df_of(w) for w in query.lower().split() if len(w) > 3}})
|
||||
|
||||
# entries-side fusion identity with the chunk-side one
|
||||
dense = [[1, 0.9], [2, 0.8]]
|
||||
bm25 = [[2, 10.0], [3, 4.0]]
|
||||
add("fusion_identity", "entries_eq_chunks",
|
||||
{"dense": dense, "bm25": bm25},
|
||||
{"fusion": ms._py_rank_fusion(dense, bm25)})
|
||||
|
||||
add("constants", "abstain",
|
||||
{},
|
||||
{"budget": ms.RECALL_BUDGET, "min_score": ms.RECALL_MIN_SCORE})
|
||||
|
||||
import shutil
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
|
||||
out = {
|
||||
"oracle": "src/rune/memory_store.py recall() dense gate + _py_rank_fusion",
|
||||
"generated": "2026-10-07",
|
||||
"fixture_df_note": "df via LIKE-substring over active entries; threshold 0.05",
|
||||
"cases": cases,
|
||||
}
|
||||
target = REPO / "src/go/memory-store-deep" / "truth_gate.json"
|
||||
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
|
||||
print(f"wrote {target} ({len(cases)} cases)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,107 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_memory_store_score_truth.py — memory-store batch 3 truth battery
|
||||
(contract BUILDER-2026-10-07T18:57:06Z-c2429c).
|
||||
|
||||
The LIVE _py_score_recall_rows oracle: metadata scoring across modes
|
||||
(hybrid / dense-only / lexical-only), recency decay, the abstention
|
||||
ladder (min_score gates, the 0.74 high-confidence gate, the 0.08 gap
|
||||
detection), position-aware re-rank.
|
||||
|
||||
Usage: python3 scripts/gen_memory_store_score_truth.py (from repo root)
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import memory_store as ms # noqa: E402
|
||||
|
||||
NOW = "2026-10-07T18:58:00"
|
||||
|
||||
|
||||
def rows_for(ids):
|
||||
"""Fixture rows: confidence/temperature/recency variety."""
|
||||
out = []
|
||||
for i, eid in enumerate(ids):
|
||||
out.append({
|
||||
"id": eid,
|
||||
"text": f"entry {eid} body",
|
||||
"importance": 0.5 + i * 0.01,
|
||||
"topic": "project",
|
||||
"entities": ["a"],
|
||||
"source": "fixture",
|
||||
"confidence": 0.9 if i % 2 == 0 else 0.6,
|
||||
"temperature": 1.2 if i % 3 == 0 else 0.8,
|
||||
"last_accessed": ["2026-10-07T18:00:00", "2026-09-01T10:00:00",
|
||||
"2026-05-01T10:00:00", None][i % 4],
|
||||
})
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
cases = []
|
||||
|
||||
def add(fn, name, inp, expected):
|
||||
cases.append({"fn": fn, "name": name, "input": inp, "expected": expected})
|
||||
|
||||
# hybrid: ranks over 4 rows, dense + bm25 present
|
||||
fusion = {"ranks": [[1, 0.12], [2, 0.11], [3, 0.10], [4, 0.09]],
|
||||
"best_dense": 0.8, "mode": "hybrid"}
|
||||
dense = [[1, 0.8], [2, 0.7], [3, 0.6]]
|
||||
bm25 = [[2, 10.0], [4, 5.0], [1, 2.0]]
|
||||
rows = rows_for([1, 2, 3, 4])
|
||||
add("score", "hybrid",
|
||||
{"fusion": fusion, "rows": rows, "dense": dense, "bm25": bm25,
|
||||
"budget": 3, "min_score": 0.3, "now": NOW},
|
||||
{"scored": ms._py_score_recall_rows(fusion, rows, dense, bm25, 3, 0.3, NOW)})
|
||||
|
||||
# dense-only: high confidence (>= 0.74) → position-aware
|
||||
fusion_d = {"ranks": [[1, 0.06], [2, 0.055], [3, 0.05]],
|
||||
"best_dense": 0.8, "mode": "dense-only"}
|
||||
add("score", "dense_only_high_conf",
|
||||
{"fusion": fusion_d, "rows": rows_for([1, 2, 3]), "dense": dense,
|
||||
"bm25": [], "budget": 5, "min_score": 0.3, "now": NOW},
|
||||
{"scored": ms._py_score_recall_rows(fusion_d, rows_for([1, 2, 3]), dense, [], 5, 0.3, NOW)})
|
||||
|
||||
# dense-only: narrow gap → abstain
|
||||
dense_close = [[1, 0.80], [2, 0.75]]
|
||||
add("score", "dense_only_gap_abstain",
|
||||
{"fusion": fusion_d, "rows": rows_for([1, 2, 3]), "dense": dense_close,
|
||||
"bm25": [], "budget": 5, "min_score": 0.3, "now": NOW},
|
||||
{"scored": ms._py_score_recall_rows(fusion_d, rows_for([1, 2, 3]), dense_close, [], 5, 0.3, NOW)})
|
||||
|
||||
# dense-only: below min_score → abstain
|
||||
add("score", "dense_only_min_score",
|
||||
{"fusion": fusion_d, "rows": rows_for([1, 2, 3]), "dense": dense,
|
||||
"bm25": [], "budget": 5, "min_score": 0.9, "now": NOW},
|
||||
{"scored": ms._py_score_recall_rows(fusion_d, rows_for([1, 2, 3]), dense, [], 5, 0.9, NOW)})
|
||||
|
||||
# lexical-only: max relevance gate
|
||||
fusion_l = {"ranks": [[2, 0.9], [4, 0.7]], "best_dense": 0.0, "mode": "lexical-only"}
|
||||
add("score", "lexical_only_gate",
|
||||
{"fusion": fusion_l, "rows": rows_for([2, 4]), "dense": [], "bm25": bm25,
|
||||
"budget": 5, "min_score": 1.0, "now": NOW},
|
||||
{"scored": ms._py_score_recall_rows(fusion_l, rows_for([2, 4]), [], bm25, 5, 1.0, NOW)})
|
||||
|
||||
# neither → []
|
||||
add("score", "neither",
|
||||
{"fusion": fusion_l, "rows": rows_for([2, 4]), "dense": [], "bm25": [],
|
||||
"budget": 5, "min_score": 0.3, "now": NOW},
|
||||
{"scored": ms._py_score_recall_rows(fusion_l, rows_for([2, 4]), [], [], 5, 0.3, NOW)})
|
||||
|
||||
out = {
|
||||
"oracle": "src/rune/memory_store.py _py_score_recall_rows",
|
||||
"generated": "2026-10-07",
|
||||
"cases": cases,
|
||||
}
|
||||
target = REPO / "src/go/memory-store-deep" / "truth_score.json"
|
||||
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
|
||||
print(f"wrote {target} ({len(cases)} cases)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,120 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_memory_store_truth2.py — memory-store batch 2 truth battery
|
||||
(contract BUILDER-2026-10-07T18:05:47Z-152c16).
|
||||
|
||||
The LIVE _py_* oracles of memory_store.py. Cases: FTS conjunctive builder
|
||||
(stopword filtering, fallback, 8-cap), chunk_text (recombine + hard-split),
|
||||
rank fusion (hybrid/dense-only/lexical-only), project_chunk_rows,
|
||||
map_reduce, fuse_results (dedup + scale-alignment).
|
||||
|
||||
Usage: python3 scripts/gen_memory_store_truth2.py (from repo root)
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import memory_store as ms # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
cases = []
|
||||
|
||||
def add(fn, name, inp, expected):
|
||||
cases.append({"fn": fn, "name": name, "input": inp, "expected": expected})
|
||||
|
||||
# ── FTS conjunctive ───────────────────────────────────────────────────
|
||||
add("fts", "significant_terms",
|
||||
{"query": "the curator gates memory writes"},
|
||||
{"q": ms._py_fts_query_conjunctive("the curator gates memory writes")})
|
||||
add("fts", "stopwords_dropped",
|
||||
{"query": "the and was with nick"},
|
||||
{"q": ms._py_fts_query_conjunctive("the and was with nick")})
|
||||
add("fts", "short_fallback",
|
||||
{"query": "go is fun ai"},
|
||||
{"q": ms._py_fts_query_conjunctive("go is fun ai")})
|
||||
long_q = "alpha beta gamma delta epsilon zeta eta theta iota kappa"
|
||||
add("fts", "cap_eight",
|
||||
{"query": long_q},
|
||||
{"q": ms._py_fts_query_conjunctive(long_q)})
|
||||
add("fts", "empty_returns_raw",
|
||||
{"query": "a an of"},
|
||||
{"q": ms._py_fts_query_conjunctive("a an of")})
|
||||
|
||||
# ── chunk_text ────────────────────────────────────────────────────────
|
||||
small = "one paragraph only"
|
||||
add("chunk", "under_size", {"text": small, "size": 1500, "overlap": 150},
|
||||
{"chunks": ms._py_chunk_text(small, 1500, 150)})
|
||||
para = "\n\n".join(f"paragraph {i} " + "x" * 40 for i in range(30))
|
||||
add("chunk", "recombine", {"text": para, "size": 400, "overlap": 150},
|
||||
{"chunks": ms._py_chunk_text(para, 400, 150)})
|
||||
noline = "y" * 3000
|
||||
add("chunk", "hard_split", {"text": noline, "size": 1000, "overlap": 150},
|
||||
{"chunks": ms._py_chunk_text(noline, 1000, 150)})
|
||||
add("chunk", "empty", {"text": "", "size": 1500, "overlap": 150},
|
||||
{"chunks": ms._py_chunk_text("", 1500, 150)})
|
||||
|
||||
# ── rank fusion ───────────────────────────────────────────────────────
|
||||
dense = [[1, 0.9], [2, 0.8], [3, 0.7]]
|
||||
bm25 = [[2, 12.0], [4, 8.0], [1, 3.0]]
|
||||
add("fuse_ranks", "hybrid", {"dense": dense, "bm25": bm25},
|
||||
ms._py_rank_fusion(dense, bm25))
|
||||
add("fuse_ranks", "dense_only", {"dense": dense, "bm25": []},
|
||||
ms._py_rank_fusion(dense, []))
|
||||
add("fuse_ranks", "lexical_only", {"dense": [], "bm25": bm25},
|
||||
ms._py_rank_fusion([], bm25))
|
||||
add("fuse_ranks", "neither", {"dense": [], "bm25": []},
|
||||
ms._py_rank_fusion([], []))
|
||||
|
||||
# ── project_chunk_rows ────────────────────────────────────────────────
|
||||
rows = [
|
||||
{"rowid": 1, "chunk_id": "c1", "text": "t" * 500, "wing": "w1", "room": "r1",
|
||||
"source_path": "a.md", "page": 3},
|
||||
{"rowid": 2, "chunk_id": "c2", "text": "short", "wing": "w1", "room": "r1",
|
||||
"source_path": "b.md"},
|
||||
]
|
||||
ranks = {"2": 0.0625, "1": 0.05}
|
||||
add("project", "budget_and_shape", {"ranks": ranks},
|
||||
{"rows": ms._py_project_chunk_rows(ranks, rows, 6)})
|
||||
|
||||
# ── map_reduce ────────────────────────────────────────────────────────
|
||||
entries = [{"id": i, "relevance": i * 0.1} for i in range(25)]
|
||||
add("map_reduce", "top3_per_chunk", {"entries": entries, "chunk_size": 10},
|
||||
{"mapped": ms._py_map_reduce(entries, 10)})
|
||||
add("map_reduce", "under_threshold", {"entries": entries[:5], "chunk_size": 10},
|
||||
{"mapped": ms._py_map_reduce(entries[:5], 10)})
|
||||
|
||||
# ── fuse_results ──────────────────────────────────────────────────────
|
||||
ents = [
|
||||
{"id": 1, "text": "nick prefers coffee", "topic": "human",
|
||||
"relevance": 2.5, "confidence": 0.9},
|
||||
{"id": 2, "text": "NICK PREFERS COFFEE", "topic": "human",
|
||||
"relevance": 1.1, "confidence": 0.8}, # dedup hit
|
||||
{"id": 3, "text": "rune gates memory writes", "topic": "project",
|
||||
"relevance": 5.6, "confidence": 0.95},
|
||||
]
|
||||
res = [
|
||||
{"chunk_id": "c1", "text": "the spine rebuild parity", "wing": "research",
|
||||
"rrf": 0.0625, "confidence": 0.7},
|
||||
{"chunk_id": "c2", "text": "curator provenance recovery", "wing": "research",
|
||||
"rrf": 0.05},
|
||||
]
|
||||
add("fuse_results", "dedup_scale_align", {"entries": ents, "research": res},
|
||||
{"merged": ms._py_fuse_results(ents, res)})
|
||||
|
||||
out = {
|
||||
"oracle": "src/rune/memory_store.py _py_* oracles",
|
||||
"generated": "2026-10-07",
|
||||
"cases": cases,
|
||||
}
|
||||
target = REPO / "src/go/memory-store-deep" / "truth_recall.json"
|
||||
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
|
||||
print(f"wrote {target} ({len(cases)} cases)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_microkernel_truth.py — factory batch 8 truth battery (live oracle)."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import microkernel as mk # noqa: E402
|
||||
|
||||
FROZEN = "2026-10-07T23:35:00"
|
||||
|
||||
|
||||
def main():
|
||||
mk.now_iso = lambda: FROZEN
|
||||
cases = []
|
||||
|
||||
def snap(reg, name):
|
||||
return {
|
||||
"plugins": {k: {"active": v["active"], "registered_at": v["registered_at"]}
|
||||
for k, v in reg["plugins"].items()},
|
||||
"capabilities": reg["capabilities"],
|
||||
"hooks": reg["hooks"],
|
||||
}
|
||||
|
||||
# register + resolve priority tie
|
||||
import tempfile, os as _os
|
||||
_tmpdb = _os.path.join(tempfile.mkdtemp(prefix="mk-truth-"), "registry.json")
|
||||
mk.REGISTRY_DB = _tmpdb
|
||||
|
||||
def _snap():
|
||||
return mk._load_registry()
|
||||
mk.register({"name": "alpha", "capabilities": ["cap.a"], "priority": 50})
|
||||
mk.register({"name": "beta", "capabilities": ["cap.a"], "priority": 10})
|
||||
mk.register({"name": "gamma", "capabilities": ["cap.a"], "priority": 10, "auto_activate": False})
|
||||
mk.register({"name": "delta", "hooks": {"pre-turn": True, "post-turn": False}})
|
||||
cases.append({"fn": "state", "name": "after_registers", "input": {},
|
||||
"expected": snap(_snap(), "x")})
|
||||
cases.append({"fn": "resolve", "name": "priority_active",
|
||||
"input": {"capability": "cap.a"},
|
||||
"expected": {"resolved": mk.resolve("cap.a")}})
|
||||
cases.append({"fn": "resolve", "name": "unknown_cap",
|
||||
"input": {"capability": "cap.nope"},
|
||||
"expected": {"resolved": mk.resolve("cap.nope")}})
|
||||
|
||||
# unregister removes from indexes
|
||||
mk.unregister("beta")
|
||||
cases.append({"fn": "state", "name": "after_unregister", "input": {},
|
||||
"expected": snap(_snap(), "x")})
|
||||
cases.append({"fn": "resolve", "name": "after_unregister",
|
||||
"input": {"capability": "cap.a"},
|
||||
"expected": {"resolved": mk.resolve("cap.a")}})
|
||||
|
||||
# error texts
|
||||
err1 = mk.register({})
|
||||
err2 = mk.unregister("nope")
|
||||
cases.append({"fn": "errors", "name": "shapes", "input": {},
|
||||
"expected": {"register_empty": err1, "unregister_unknown": err2}})
|
||||
|
||||
out = {"oracle": "src/rune/microkernel.py (live)", "generated": "2026-10-07",
|
||||
"frozen_now": FROZEN, "cases": cases}
|
||||
(REPO / "src/go/microkernel" / "truth_microkernel.json").write_text(
|
||||
json.dumps(out, indent=1) + "\n")
|
||||
print(f"wrote {len(cases)} cases")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_provider_format_truth.py — factory batch 5 truth battery (live
|
||||
provider_registry._format_tools_* oracles)."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import provider_registry as pr # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
tools = [
|
||||
{"name": "read_file", "description": "Read a file",
|
||||
"parameters": {"type": "object", "properties": {"path": {"type": "string"}}}},
|
||||
{"name": "write_file", "description": "Write a file"}, # no parameters key
|
||||
]
|
||||
cases = [
|
||||
{"fn": "openai", "name": "shape", "input": {"tools": tools},
|
||||
"expected": pr._format_tools_openai(tools)},
|
||||
{"fn": "anthropic", "name": "shape", "input": {"tools": tools},
|
||||
"expected": pr._format_tools_anthropic(tools)},
|
||||
]
|
||||
out = {"oracle": "provider_registry._format_tools_*", "generated": "2026-10-07", "cases": cases}
|
||||
target = REPO / "src/go/provider-registry" / "truth_format.json"
|
||||
target.write_text(json.dumps(out, indent=1) + "\n")
|
||||
print(f"wrote {target} ({len(cases)} cases)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loaded 100 of 1701 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user