Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01b57297b8 | ||
|
|
497db5a144 | ||
|
|
9425ccc1f4 | ||
|
|
3ed547f86f | ||
|
|
5bc837c232 | ||
|
|
08bc1a6b62 | ||
|
|
201ca05b56 | ||
|
|
5cd90f2104 | ||
|
|
c8bc454e33 | ||
|
|
b81edb2029 | ||
|
|
87a890dce3 | ||
|
|
a0821be8a5 | ||
|
|
cb137bd37a | ||
|
|
72afb1a55a | ||
|
|
c9095f5af5 | ||
|
|
b5422f0772 | ||
|
|
da36b99184 | ||
|
|
873d0025ad | ||
|
|
a9ce967557 | ||
|
|
eb3a2c681c | ||
|
|
1bc1cdeaf0 | ||
|
|
31565844d7 | ||
|
|
c08b211f0e | ||
|
|
46c5032208 | ||
|
|
92584daeef | ||
|
|
bb5e243c88 | ||
|
|
ac936a8ba9 | ||
|
|
e6c8c5444d | ||
|
|
11270cb06a | ||
|
|
f8a568714b | ||
|
|
c3f81e60ec | ||
|
|
efb99d4682 | ||
|
|
489718ab1b | ||
|
|
9db580ac6d | ||
|
|
80ed978fbf | ||
|
|
3f119e50d8 | ||
|
|
517379313b | ||
|
|
643f9aa9d1 | ||
|
|
61a5082633 | ||
|
|
9121bbd8b0 | ||
|
|
cba9045982 | ||
|
|
0c92f482a7 | ||
|
|
3120e8ae08 | ||
|
|
ea3c20e205 | ||
|
|
a93327d107 | ||
|
|
e08625f629 | ||
|
|
021fef2065 | ||
|
|
3788875410 | ||
|
|
d96b89bd4c | ||
|
|
efe3871916 | ||
|
|
026a1bd919 | ||
|
|
d9bcebb730 | ||
|
|
2b2639783a | ||
|
|
634821efd4 | ||
|
|
c6c18ae041 | ||
|
|
e03ad9aad9 | ||
|
|
89b603024e | ||
|
|
dac6e97e16 |
No files matched your search
@@ -1,16 +1,46 @@
|
||||
---
|
||||
name: Bug Fix
|
||||
about: Fix a bug or issue
|
||||
about: Demonstrate currently incorrect behaviour — plain English first, proof required
|
||||
title: "[BUG] "
|
||||
labels: bug
|
||||
assignees: conductor
|
||||
---
|
||||
|
||||
## Plain summary
|
||||
<!-- 2-4 sentences, NON-TECHNICAL: what's broken and why it matters. -->
|
||||
<restate the issue title here in everyday words — this heading IS the
|
||||
plain-English summary; no meta-labels like "plain English" in it>
|
||||
<!-- The heading above carries the summary itself — a scan of issue
|
||||
headings alone should tell the whole story of the board. TOP PRIORITY:
|
||||
if a technical detail below contradicts this section, the issue is
|
||||
buggy — fix the issue. -->
|
||||
<!-- SUBMITTED_BODY -->
|
||||
|
||||
## Example
|
||||
<!-- A concrete before/after: "Doing X currently produces Y; it should produce Z." -->
|
||||
|
||||
What is broken: <what a person observes going wrong>
|
||||
|
||||
What should happen instead: <the correct behaviour>
|
||||
|
||||
How often / when: <always | after X | since change Y>
|
||||
|
||||
## Proof it is broken (required — no proof, no bug)
|
||||
<!-- A bug is DEMONSTRATED currently incorrect behaviour. Nothing else.
|
||||
If this section cannot be filled, file it as a question, not a bug. -->
|
||||
- [ ] Reproduction command or steps (deterministic where possible)
|
||||
- [ ] The exact wrong output observed: <paste/log excerpt>
|
||||
- [ ] Where the evidence lives: <log path, fixture, session id>
|
||||
|
||||
## Steps to reproduce
|
||||
<!-- How to trigger the bug -->
|
||||
|
||||
## What would let us close this
|
||||
- [ ] The reproduction command now shows correct behaviour
|
||||
- [ ] A regression test exists that fails before the fix and passes after
|
||||
- [ ] No other behaviour changed (or changes are listed and justified)
|
||||
|
||||
## Version impact (declared at submission — verified at merge)
|
||||
<!-- A bug fix is USUALLY a patch. Pick major or minor only with a reason. -->
|
||||
- [ ] patch — same behaviour, done correctly (usual for bugs)
|
||||
- [ ] major — the bug was in a published contract and fixing it breaks consumers (justify)
|
||||
- [ ] minor — fixing revealed a missing capability that had to be added (justify)
|
||||
|
||||
## Technical details
|
||||
<!-- WHAT (the bug) / WHERE (files) / EVIDENCE (how it was confirmed). -->
|
||||
@@ -29,10 +59,6 @@ assignees: conductor
|
||||
- [ ] Canary passes (name)
|
||||
- [ ] Closed with a properly formatted closing comment + commit references
|
||||
|
||||
## Steps to reproduce
|
||||
<!-- How to trigger the bug -->
|
||||
|
||||
|
||||
## Cognitive invariants (memory/cognition issues — both handoffs)
|
||||
<!-- Complete ONLY if this issue touches memory, learning, or self-model state. -->
|
||||
- [ ] **Owner** — which existing subsystem owns this (audit before creating modules)
|
||||
|
||||
@@ -1,18 +1,44 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: New feature or improvement — DESCRIPTION GATE v4 format (plain summary + pipeline requirements)
|
||||
about: New feature or improvement — plain English first, verifiable close conditions, version intent
|
||||
title: "[FEATURE] "
|
||||
labels: feature
|
||||
assignees: conductor
|
||||
---
|
||||
|
||||
## Plain summary
|
||||
<!-- 2-4 sentences, NON-TECHNICAL: what this does and why it matters. Nick should
|
||||
understand the goal without decoding internals. -->
|
||||
<restate the issue title here in everyday words — this heading IS the
|
||||
plain-English summary; no meta-labels like "plain English" in it>
|
||||
<!-- The heading above carries the summary itself — a scan of issue
|
||||
headings alone should tell the whole story of the board. TOP PRIORITY:
|
||||
if a technical detail below contradicts this section, the issue is
|
||||
buggy — fix the issue. A non-technical reader must be able to retell this
|
||||
section. 3-6 sentences, no jargon. -->
|
||||
<!-- SUBMITTED_BODY -->
|
||||
|
||||
|
||||
What is this about: <what>
|
||||
|
||||
Why do we need it: <the itch — what happens today that shouldn't, or what becomes possible>
|
||||
|
||||
Why is it still open: <"not started yet" | "part done, X remains" | "deliberately parked as a future idea">
|
||||
|
||||
## Example
|
||||
<!-- A concrete example of the intended behavior, in plain terms:
|
||||
"If X happens, the system will Y instead of Z." -->
|
||||
<!-- A concrete before/after in plain terms: "If X happens, the system will Y instead of Z." -->
|
||||
|
||||
## What would let us close this
|
||||
<!-- Checkable statements, verifiable by looking at something that EXISTS —
|
||||
a file, a log line, a passing test. Not "when appropriate". -->
|
||||
- [ ] <condition 1 — observable>
|
||||
- [ ] <condition 2>
|
||||
|
||||
## Version impact (declared at submission — verified at merge)
|
||||
<!-- The pipeline derives the real bump from merged conventional commits and
|
||||
compares against this declaration. A mismatch is flagged, not fatal:
|
||||
either the declaration was wrong or the work grew. Both facts matter. -->
|
||||
- [ ] major — breaking: changes a contract, schema, or interface others depend on
|
||||
- [ ] minor — new capability: something becomes possible that wasn't
|
||||
- [ ] patch — repair: same behaviour, done correctly
|
||||
- [ ] none — touches no released artifact (docs, memory, process notes)
|
||||
|
||||
## Technical details
|
||||
<!-- WHAT — one-line objective.
|
||||
@@ -37,7 +63,6 @@ DEPENDENCIES — parent epic + preceding stage/plan refs. -->
|
||||
- [ ] Canary passes (name)
|
||||
- [ ] Closed with a properly formatted closing comment + commit/PR references
|
||||
|
||||
|
||||
## Cognitive invariants (memory/cognition issues — both handoffs)
|
||||
<!-- Complete ONLY if this issue touches memory, learning, or self-model state. -->
|
||||
- [ ] **Owner** — which existing subsystem owns this (audit before creating modules)
|
||||
@@ -69,4 +94,4 @@ Hard invariants: derived cognition preserves evidentiary ancestry · epistemic c
|
||||
- [ ] **P0 — critical** — breaks the spine / core correctness, or blocks other work
|
||||
- [ ] **P1 — high** — material user value or a real defect (money, correctness bugs, next-stage dependency)
|
||||
- [ ] **P2 — medium** — quality/consolidation improvement (check the fold-into mapping first)
|
||||
- [ ] **P3 — low** — measurement / benchmark / deferred policy
|
||||
- [ ] **P3 — low** — measurement / benchmark / deferred policy
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
name: Research Submission
|
||||
about: Buy down uncertainty before building — question, falsifier, budget, durable findings
|
||||
title: "[RESEARCH] "
|
||||
labels: research
|
||||
assignees: conductor
|
||||
---
|
||||
|
||||
<restate the issue title here in everyday words — this heading IS the
|
||||
plain-English summary; no meta-labels like "plain English" in it>
|
||||
<!-- The heading above carries the summary itself — a scan of issue
|
||||
headings alone should tell the whole story of the board. TOP PRIORITY:
|
||||
if a technical detail below contradicts this section, the issue is
|
||||
buggy — fix the issue. -->
|
||||
<!-- SUBMITTED_BODY -->
|
||||
|
||||
|
||||
The question: <what we're trying to learn, one sentence>
|
||||
|
||||
Why we're asking: <what decision this research will inform — a name, an issue
|
||||
number, or "exploratory: none yet">
|
||||
|
||||
What we believe today: <the current assumption, stated so it can be proven wrong>
|
||||
|
||||
## The shape of an answer
|
||||
- [ ] What evidence would settle the question: <observation, benchmark, or spike>
|
||||
- [ ] What evidence would KILL the current assumption (the falsifier): <be specific —
|
||||
this is stated BEFORE starting so the research cannot become a search for confirmation>
|
||||
- [ ] Budget: <time/effort cap — when research must stop and report back>
|
||||
|
||||
## What would let us close this
|
||||
- [ ] Findings written to a durable document: <path, e.g. research/issue-NNN/> —
|
||||
a comment thread is not a durable finding
|
||||
- [ ] The decision the research informs is recorded: made / deferred / changed
|
||||
- [ ] If a follow-up build issue was minted: <#N or "none needed">
|
||||
|
||||
## Version impact (declared at submission — verified at merge)
|
||||
- [ ] none — research changes no released artifact (usual)
|
||||
- [ ] minor/major — only if a code spike is being merged as part of this (justify)
|
||||
|
||||
## Technical detail
|
||||
<!-- Candidate approaches, prior art in the repo, related issues, constraints,
|
||||
rebuildable-projection or authority requirements if findings touch canonical state. -->
|
||||
|
||||
## Pipeline requirements
|
||||
- [ ] Findings committed under the stated durable path
|
||||
- [ ] Every citation verified against a real source (no fabricated references)
|
||||
- [ ] Closed with a properly formatted closing comment: findings summary + decision
|
||||
|
||||
## Cognitive invariants (memory/cognition research — both handoffs)
|
||||
<!-- Complete ONLY if findings touch memory, learning, or self-model state. -->
|
||||
- [ ] **Owner** — which existing subsystem owns this (audit before proposing modules)
|
||||
- [ ] **Read/write authority** — which canonical state is affected
|
||||
- [ ] **Provenance** — findings traceable to evidence
|
||||
- [ ] **Reversibility** — projections remain rebuildable; no unique truth moves into a derived index
|
||||
- [ ] **No duplicate authority** — why extend vs create
|
||||
|
||||
Hard invariants: derived cognition preserves evidentiary ancestry · retrieval never increases utility · raw evidence is never destroyed by promotion.
|
||||
|
||||
## Related umbrella
|
||||
- [ ] Memory
|
||||
- [ ] Governance
|
||||
- [ ] Identity
|
||||
- [ ] Growth
|
||||
- [ ] Perception
|
||||
- [ ] Infrastructure
|
||||
- [ ] Life (Nick's)
|
||||
- [ ] Custodian
|
||||
- [ ] Orchestration
|
||||
|
||||
## Priority (REQUIRED — the priority gate)
|
||||
<!-- Pick exactly one. An issue without a priority is not filed. -->
|
||||
- [ ] **P0 — critical** — blocks a decision that blocks other work
|
||||
- [ ] **P1 — high** — informs a next-stage dependency
|
||||
- [ ] **P2 — medium** — quality/consolidation understanding
|
||||
- [ ] **P3 — low** — watchlist / deferred / exploratory
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
# 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'
|
||||
if: github.event_name == 'issues' && github.event.action != 'labeled' && github.event.issue.state == 'open'
|
||||
runs-on: rune-infra-pi
|
||||
steps:
|
||||
- name: Enforce priority label
|
||||
@@ -50,6 +50,20 @@ jobs:
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
// CLOSED-ISSUE GUARD (#407): labels are filing-time metadata.
|
||||
// A closed issue's lifecycle has ended; re-running label
|
||||
// inference on it re-adds stale type labels (bug = currently
|
||||
// incorrect behavior — a closed fixed issue must not carry
|
||||
// it) and makes any human label cleanup self-defeating,
|
||||
// because every PUT fires a 'labeled' event that re-triggers
|
||||
// this job. Post-close label curation belongs to humans and
|
||||
// the conductor, not this workflow.
|
||||
const issueState = context.payload.issue?.state;
|
||||
if (issueState === 'closed') {
|
||||
console.log(`Issue #${context.payload.issue?.number} is closed — auto-label skips (labels are curated post-close).`);
|
||||
return;
|
||||
}
|
||||
const action = context.payload.action;
|
||||
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();
|
||||
@@ -58,9 +72,43 @@ jobs:
|
||||
const managedLabels = new Set([
|
||||
'memory', 'governance', 'identity', 'growth',
|
||||
'perception', 'infrastructure', 'life', 'custodian',
|
||||
'priority: high', 'bug', 'feature',
|
||||
'priority: high', 'bug', 'feature', 'research',
|
||||
]);
|
||||
|
||||
// Type label: DECLARED over GUESSED. The template spine
|
||||
// (kind: bug|feature|research|epic|...) is authoritative.
|
||||
// A recognized kind maps to its label; ANY other declared kind
|
||||
// (e.g. epic) means NO type label and NO keyword guessing —
|
||||
// epics are containers, not bugs. Keyword heuristics apply
|
||||
// only to pre-template issues with no spine at all.
|
||||
let isBug = false, isFeature = false, isResearch = false;
|
||||
const kindMatch = body && body.match(/^kind:\s*([a-z_-]+)\s*$/m);
|
||||
if (kindMatch) {
|
||||
const kind = kindMatch[1];
|
||||
isBug = kind === 'bug';
|
||||
isFeature = kind === 'feature';
|
||||
isResearch = kind === 'research';
|
||||
} else if (action === 'opened') {
|
||||
// KEYWORD FALLBACK (#407): pre-template issues only, and
|
||||
// ONLY at filing time. Re-running keyword guesses on every
|
||||
// edit/label event overrides human curation of spine-less
|
||||
// issues (documented rule: keyword heuristics are the
|
||||
// pre-template fallback, not a standing authority).
|
||||
const textBug = title.startsWith('[BUG]') || text.includes('bug') || text.includes('fix') || text.includes('broken');
|
||||
isBug = textBug;
|
||||
isFeature = !isBug && (title.startsWith('[FEATURE]') || text.includes('feature') || text.includes('improve') || text.includes('add'));
|
||||
isResearch = !isBug && !isFeature && title.startsWith('[RESEARCH]');
|
||||
}
|
||||
if (isBug) {
|
||||
desiredLabels.add('bug');
|
||||
}
|
||||
if (isFeature) {
|
||||
desiredLabels.add('feature');
|
||||
}
|
||||
if (isResearch) {
|
||||
desiredLabels.add('research');
|
||||
}
|
||||
|
||||
// Umbrella labels
|
||||
if (text.includes('memory') || text.includes('store') || text.includes('recall') || text.includes('consolidat')) {
|
||||
desiredLabels.add('memory');
|
||||
@@ -92,16 +140,6 @@ jobs:
|
||||
desiredLabels.add('priority: high');
|
||||
}
|
||||
|
||||
// Type labels
|
||||
const isBug = title.startsWith('[BUG]') || text.includes('bug') || text.includes('fix') || text.includes('broken');
|
||||
const isFeature = !isBug && (title.startsWith('[FEATURE]') || text.includes('feature') || text.includes('improve') || text.includes('add'));
|
||||
if (isBug) {
|
||||
desiredLabels.add('bug');
|
||||
}
|
||||
if (isFeature) {
|
||||
desiredLabels.add('feature');
|
||||
}
|
||||
|
||||
const issueNumber = context.payload.issue?.number || context.payload.pull_request?.number;
|
||||
const current = await github.rest.issues.listLabelsOnIssue({
|
||||
owner: context.repo.owner,
|
||||
|
||||
@@ -58,3 +58,26 @@ fix, full pipeline re-entry (suite + ratchet + ruff + canaries + henxels;
|
||||
gates for anything beyond a mechanical minor), regression tests frozen forever,
|
||||
discharge recorded finding → test → commit. Symptom patches are rejected at
|
||||
review. To escape: edit `henxels.yaml` or this file — visibly.
|
||||
|
||||
## Issue organisation standard (binding, 2026-09-19)
|
||||
|
||||
One open note per idea. Issues use the template spine (kind, subsystem,
|
||||
version intent) with a plain-English heading that restates the subject —
|
||||
no meta-labels. Before minting a standalone issue, check whether the work
|
||||
belongs inside an existing parent:
|
||||
|
||||
- **Parked ideas under a blocked/future epic** are filed as checklist items
|
||||
in the parent's "Absorbed children" section, NOT as standalone issues.
|
||||
Absorption is reversible — re-mint standalone when the idea becomes live.
|
||||
- **Live, dependency-tracked, or starting work** gets a standalone issue.
|
||||
- **Closures state the reason as data**: `closed_because` in the spine
|
||||
(completed / superseded-by-#N / absorbed-into-#N / wont-do / duplicate),
|
||||
plus a standard closing comment (plain summary first).
|
||||
- The reconciliation checker (`scripts/gitea_reconciliation_check.py`) must
|
||||
stay green after any issue state change; the artifact is updated in the
|
||||
same change that moves issues.
|
||||
|
||||
## Async continuation final flow proofs (R13/M9) — 2026-09-19
|
||||
|
||||
PR-flow live proof marker: harmless documentation addition exercising the
|
||||
canonical single-continuation path on the PC-local forge. No code change.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Rune
|
||||
|
||||
**Current release: v0.87.0**
|
||||
**Current release: v0.88.4**
|
||||
|
||||
**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.**
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import { execFile } from "node:child_process"
|
||||
import { existsSync, appendFileSync } from "node:fs"
|
||||
|
||||
// builder-bridge — Rune Core preflight for the MiMo builder (handoff
|
||||
// 2026-09-10 §3–§7, Option C bridge tranche). For each user turn, the hook
|
||||
// extracts the user's message from the outgoing LLM request, runs the Rune
|
||||
// Core builder-bridge preflight (deterministic: route classification +
|
||||
// memory selection + active-Scaffolding projection, ZERO model calls), and
|
||||
// appends a compact capsule to the final user message. Same Rune Core the
|
||||
// TUI/operator path uses — this file is a thin adapter with no cognition.
|
||||
//
|
||||
// CANONICAL SOURCE: config/mimo-hooks/builder-bridge.ts
|
||||
// Installed to ~/.mimocode/hooks/builder-bridge.ts by
|
||||
// `scripts/install_mimo_hook.py` (hash-verified, drift-detecting — the same
|
||||
// contract as event-wait-guard.ts). T22: this file was previously
|
||||
// UNVERSIONED and hardcoded an ephemeral interpreter path (/tmp/ci-venv),
|
||||
// which silently killed the whole edge; both defects are repaired here.
|
||||
//
|
||||
// Overhead contract (§7/§8): capsule ≤ ~300 tokens; a repeat/empty task
|
||||
// costs ~0ms (TTL cache); a fresh task ~150ms (bounded retrieval). The hook
|
||||
// degrades silently to no-injection on any failure — it must never block
|
||||
// the builder.
|
||||
//
|
||||
// Injection policy: only append when the capsule is non-empty. A plain
|
||||
// "hello" gets nothing (§5: if nothing relevant exists, inject nothing).
|
||||
|
||||
const BRIDGE = "/mnt/workdrive/issue161-harness/src/rune/builder_bridge_cli.py"
|
||||
const MARKER_PREFIX = "/tmp/rune-bridge-"
|
||||
|
||||
// Interpreter resolution (T22 repair): the previous hardcoded
|
||||
// "/tmp/ci-venv/bin/python" is an EPHEMERAL path that no longer exists, so
|
||||
// every bridge call failed and the hook silently degraded — the MiMo edge
|
||||
// received no Rune Core preflight at all (zero fire-log lines). Resolve
|
||||
// against durable candidates, first existing wins; env override wins over
|
||||
// all of them. If nothing exists the hook degrades as before.
|
||||
const PY_CANDIDATES = [
|
||||
process.env.MIMO_BRIDGE_PY,
|
||||
"/mnt/workdrive/issue161-harness/.test-venv/bin/python",
|
||||
"/home/nick/.venvs/memory/bin/python3",
|
||||
"/usr/bin/python3",
|
||||
].filter((p) => typeof p === "string" && p.length > 0)
|
||||
|
||||
function resolvePy() {
|
||||
for (const p of PY_CANDIDATES) {
|
||||
try {
|
||||
if (existsSync(p)) return p
|
||||
} catch {}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// Per-process dedupe: identical task text within the cache TTL does not need
|
||||
// a second bridge call — the CLI has its own TTL cache, but skipping the
|
||||
// process spawn entirely for the same message text within 10 minutes keeps
|
||||
// repeats at ~0ms.
|
||||
const lastText = new Map() // text -> timestamp
|
||||
const TTL = 600_000
|
||||
|
||||
function extractUserText(messages) {
|
||||
// messages: Array<{ info: Message, parts: Part[] }> — newest last.
|
||||
for (let i = messages.length - 1; i >= 0; i--) {
|
||||
const m = messages[i]
|
||||
if (m?.info?.role !== "user") continue
|
||||
const texts = []
|
||||
for (const p of m.parts ?? []) {
|
||||
if (p?.type === "text" && typeof p.text === "string") texts.push(p.text)
|
||||
}
|
||||
if (texts.length) return texts.join("\n").slice(0, 4000)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
export default {
|
||||
"experimental.chat.messages.transform": async (input, output) => {
|
||||
try {
|
||||
if (!Array.isArray(output.messages) || output.messages.length === 0) return
|
||||
const userText = extractUserText(output.messages)
|
||||
if (!userText || userText.length < 12) return // trivial/noise guard
|
||||
// Harness-internal steps (checkpoint writer, compaction, system
|
||||
// reminders) are not builder tasks — no capsule (measured: the fire
|
||||
// log showed checkpoint-writer steps receiving capsules 2026-09-10).
|
||||
if (/^(<system-reminder>|EXTRACTION REQUIRED)/.test(userText.trim())) return
|
||||
const now = Date.now()
|
||||
const prev = lastText.get(userText)
|
||||
if (prev !== undefined && now - prev < TTL) return // dedupe repeats
|
||||
lastText.set(userText, now)
|
||||
if (lastText.size > 64) {
|
||||
// evict oldest
|
||||
let oldestKey = null, oldestVal = Infinity
|
||||
for (const [k, v] of lastText) if (v < oldestVal) { oldestVal = v; oldestKey = k }
|
||||
if (oldestKey) lastText.delete(oldestKey)
|
||||
}
|
||||
|
||||
const py = resolvePy()
|
||||
if (!py) return // no durable interpreter — degrade (never block)
|
||||
|
||||
const capsule = await new Promise((resolve) => {
|
||||
execFile(py, [BRIDGE, userText], { timeout: 15_000 }, (err, stdout) => {
|
||||
resolve(err ? "" : (stdout?.toString() ?? ""))
|
||||
})
|
||||
})
|
||||
if (!capsule.trim()) return
|
||||
|
||||
// Durable fire-trace: one line per ACTUAL injection into an outgoing
|
||||
// model request (handoff §1 proof requirement). Not a canary — this is
|
||||
// standing observability for the bridge's consumer edge.
|
||||
try {
|
||||
appendFileSync("/tmp/rune-bridge-fire.log",
|
||||
JSON.stringify({ ts: new Date().toISOString(), task: userText.slice(0, 80), capsule_tokens: Math.round(capsule.length / 4), py }) + "\n")
|
||||
} catch {}
|
||||
|
||||
// Append the capsule to the LAST user message (the one being answered).
|
||||
const last = output.messages[output.messages.length - 1]
|
||||
if (last?.parts && Array.isArray(last.parts)) {
|
||||
last.parts.push({
|
||||
type: "text",
|
||||
text: "\n\n<rune-preflight>\n" + capsule.trim() + "\n</rune-preflight>\n(Injected by Rune Core builder bridge — deterministic preflight, zero model calls. Relevant state above; ignore if not applicable to this task.)",
|
||||
})
|
||||
}
|
||||
} catch {
|
||||
// never block the builder on bridge failure
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,54 +1,92 @@
|
||||
import { tool } from "@mimo-ai/plugin"
|
||||
import { execSync } from "child_process"
|
||||
|
||||
// await_operation — T21.3 §21.3C: FIRST-CLASS async wait tool.
|
||||
// Uses the plugin tool() API with args (not parameters).
|
||||
|
||||
export const AwaitOperation = tool({
|
||||
description: [
|
||||
"Wait for an asynchronous external operation (CI, deploy, release) to complete.",
|
||||
"Registers on the event bridge, yields until the completion event arrives, then returns the verified result.",
|
||||
"USE THIS instead of `sleep N; curl status` — it is the canonical event-driven wait.",
|
||||
].join(" "),
|
||||
export default tool({
|
||||
description: "Wait for an external operation (CI, deploy, release) to complete. Call this when you cannot make progress until an external process finishes. You do NOT need to know the sha, op_type, or duration — Rune's controller resolves those from the bound PendingOperation. Just call this when you want to wait.",
|
||||
args: {
|
||||
sha: tool.schema.string().describe(
|
||||
"The exact commit SHA the operation is running against"),
|
||||
deadline_secs: tool.schema.number().optional().describe(
|
||||
"Maximum wait in seconds (default 900)"),
|
||||
operation_id: tool.schema.string().optional().describe("Optional: the operation to wait for. If omitted, the controller resolves the current pending operation automatically."),
|
||||
task_id: tool.schema.string().optional().describe("Optional: the active task id (e.g. T4). When provided, resolution is scoped to operations bound to this task — stale global operations are never consulted."),
|
||||
sha: tool.schema.string().optional().describe("OPTIONAL HINT — non-authoritative. The controller uses this only to help resolve which operation you mean."),
|
||||
op_type: tool.schema.string().optional().describe("OPTIONAL HINT — non-authoritative. The controller derives the canonical operation type from repository/Gitea state."),
|
||||
deadline_secs: tool.schema.number().optional().describe("OPTIONAL HINT — non-authoritative. The controller applies governed policy timing. Real user deadlines must be stated in conversation."),
|
||||
},
|
||||
async execute(args, ctx) {
|
||||
const repoRoot = "/mnt/workdrive/issue161-harness"
|
||||
const deadline = args.deadline_secs || 900
|
||||
const cmd = [
|
||||
"python3", `${repoRoot}/scripts/ci_event_wait.py`,
|
||||
"--sha", args.sha,
|
||||
"--deadline", String(deadline),
|
||||
].join(" ")
|
||||
async execute(args) {
|
||||
// INTENT NORMALIZATION — model output is intent; the controller
|
||||
// owns execution semantics. All model args are hints recorded for
|
||||
// observability; canonical truth comes from the bound operation.
|
||||
const parts = []
|
||||
if (args.operation_id) parts.push(`--operation-id ${args.operation_id}`)
|
||||
if (args.task_id) parts.push(`--task-id ${args.task_id}`)
|
||||
if (args.sha) parts.push(`--sha ${args.sha}`)
|
||||
if (args.op_type) parts.push(`--model-op-type ${args.op_type}`)
|
||||
if (args.deadline_secs) parts.push(`--model-deadline ${args.deadline_secs}`)
|
||||
const normCmd = `python3 /mnt/workdrive/issue161-harness/scripts/await_intent_cli.py normalize ${parts.join(" ")}`
|
||||
let norm: any
|
||||
try {
|
||||
const normOut = execSync(normCmd, {
|
||||
cwd: "/mnt/workdrive/issue161-harness",
|
||||
encoding: "utf-8" as const,
|
||||
timeout: 120000,
|
||||
env: { ...process.env, RUNE_WR_ROOT: "/mnt/workdrive/wr-bridge" },
|
||||
})
|
||||
norm = JSON.parse(normOut.trim().split("\n").find((l: string) => l.startsWith("{")) || "{}")
|
||||
} catch (e: any) {
|
||||
return JSON.stringify({ ok: false, stage: "normalization", error: (e.stderr || e.message || "?").slice(0, 300) })
|
||||
}
|
||||
if (norm.normalized === "AMBIGUOUS") {
|
||||
return JSON.stringify({ ok: false, stage: "normalization", ...norm })
|
||||
}
|
||||
if (!norm.normalized) {
|
||||
return JSON.stringify({ ok: false, stage: "normalization", ...norm })
|
||||
}
|
||||
// canonical continuation: stored/derived op_type + POLICY deadline
|
||||
// (the sha for the wait comes from the normalization resolution,
|
||||
// NOT from the model's args)
|
||||
const waitSha = norm.sha_for_wait || args.sha || ""
|
||||
if (!waitSha) {
|
||||
return JSON.stringify({ ok: false, stage: "resolution", error: "no sha resolved for the pending operation", norm })
|
||||
}
|
||||
const cmd = `python3 /mnt/workdrive/issue161-harness/scripts/ci_event_wait.py --sha ${waitSha} --deadline ${norm.deadline_secs} --op-type ${norm.op_type}`
|
||||
try {
|
||||
const result = execSync(cmd, {
|
||||
cwd: repoRoot,
|
||||
timeout: (deadline + 60) * 1000,
|
||||
cwd: "/mnt/workdrive/issue161-harness",
|
||||
timeout: (norm.deadline_secs + 60) * 1000,
|
||||
encoding: "utf-8" as const,
|
||||
env: {
|
||||
...process.env,
|
||||
DEPLOY_SHA: args.sha,
|
||||
RUNE_WR_ROOT: "/mnt/workdrive/wr-bridge",
|
||||
RUNE_WR_CODE: "/home/nick/.local/share/mimo-wait-resume",
|
||||
env: { ...process.env, DEPLOY_SHA: waitSha, RUNE_WR_ROOT: "/mnt/workdrive/wr-bridge", RUNE_WR_CODE: "/home/nick/.local/share/mimo-wait-resume" },
|
||||
})
|
||||
const jl = result.trim().split("\n").find((l: string) => l.startsWith("{"))
|
||||
const envelope = jl ? JSON.parse(jl) : { ok: false, error: "no output" }
|
||||
return JSON.stringify({
|
||||
...envelope,
|
||||
normalization: {
|
||||
model_deadline_ignored: norm.model_deadline_ignored,
|
||||
model_op_type_ignored: norm.model_op_type_ignored,
|
||||
model_sha_ignored: !!args.sha && args.sha !== waitSha,
|
||||
canonical_op_type: norm.op_type,
|
||||
canonical_authority: norm.authority,
|
||||
deadline_provenance: norm.deadline_provenance,
|
||||
matched_by: norm.matched_by || norm.evidence || "auto-resolved",
|
||||
},
|
||||
})
|
||||
const lines = result.trim().split("\n")
|
||||
const jsonLine = lines.find((l: string) => l.startsWith("{"))
|
||||
if (jsonLine) return jsonLine
|
||||
return "await_operation: no JSON output"
|
||||
} catch (e: any) {
|
||||
const stdout = e.stdout || ""
|
||||
const lines = stdout.trim().split("\n")
|
||||
const jsonLine = lines.find((l: string) => l.startsWith("{"))
|
||||
if (jsonLine) return jsonLine
|
||||
return JSON.stringify({
|
||||
ok: false,
|
||||
error: `await_operation failed: ${(e.stderr || e.message || "?").slice(0, 200)}`,
|
||||
})
|
||||
const lines = (e.stdout || "").trim().split("\n")
|
||||
const jl = lines.find((l: string) => l.startsWith("{"))
|
||||
if (jl) {
|
||||
const envelope = JSON.parse(jl)
|
||||
return JSON.stringify({
|
||||
...envelope,
|
||||
normalization: {
|
||||
model_deadline_ignored: norm.model_deadline_ignored,
|
||||
model_op_type_ignored: norm.model_op_type_ignored,
|
||||
model_sha_ignored: !!args.sha && args.sha !== waitSha,
|
||||
canonical_op_type: norm.op_type,
|
||||
canonical_authority: norm.authority,
|
||||
deadline_provenance: norm.deadline_provenance,
|
||||
matched_by: norm.matched_by || norm.evidence || "auto-resolved",
|
||||
},
|
||||
})
|
||||
}
|
||||
return JSON.stringify({ ok: false, stage: "wait", error: (e.stderr || e.message || "?").slice(0, 300) })
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,167 @@
|
||||
|
||||
// bash — executes a shell command. PROCESS-OWNERSHIP CONTRACT (v2):
|
||||
//
|
||||
// MODE A (tool-owned): the child is launched in its own process group;
|
||||
// stdout/stderr are CAPTURED pipes (never the TUI tty). On timeout or
|
||||
// failure the ENTIRE process group is signalled (SIGTERM, grace,
|
||||
// SIGKILL) so grandchildren cannot survive the invocation, then the
|
||||
// result is finalized. After finalization NO descendant retains a
|
||||
// writer into MiMo's streams.
|
||||
//
|
||||
// MODE B (explicitly detached): a command suffixed with " &" that the
|
||||
// user/model intends to outlive the tool (nohup/setsid/disown-style)
|
||||
// is executed via the detached helper: stdin=/dev/null, stdout/stderr
|
||||
// -> durable log file, own session (setsid), no MiMo PTY inheritance.
|
||||
// The tool returns the log path as the durable handle.
|
||||
//
|
||||
// Wait-intent compilation (sleep/check/poll aimed at a pending operation)
|
||||
// is preserved: interception happens at the SEMANTIC level via
|
||||
// await_intent route-bash, and a NO-OP for anything that is not a genuine
|
||||
// continuation of a live pending operation. Arbitrary shell syntax
|
||||
// (quotes, pipes, semicolons) passes through untouched — the router
|
||||
// response is only trusted when it carries normalized=true AND
|
||||
// ContinuePendingOperation with a concrete operation bound.
|
||||
import { tool } from "@mimo-ai/plugin"
|
||||
import { spawn, execFile } from "child_process"
|
||||
|
||||
const REPO = "/mnt/workdrive/issue161-harness"
|
||||
const WR_ROOT = "/mnt/workdrive/wr-bridge"
|
||||
|
||||
// ── MODE A: process-group-owned capture execution ──────────────────────
|
||||
interface OwnedResult { stdout: string; stderr: string; status: number; timedOut: boolean }
|
||||
|
||||
function runOwned(command: string, timeoutMs: number): Promise<OwnedResult> {
|
||||
return new Promise((resolve) => {
|
||||
// /bin/sh -c "command" in its OWN process group (detached:true makes
|
||||
// the child a session/group leader we can signal as a WHOLE).
|
||||
const child = spawn("/bin/sh", ["-c", command], {
|
||||
cwd: REPO,
|
||||
stdio: ["ignore", "pipe", "pipe"], // NEVER inherit the TUI tty
|
||||
env: process.env,
|
||||
detached: true, // own process group
|
||||
})
|
||||
let stdout = "", stderr = ""
|
||||
let timedOut = false
|
||||
let settled = false
|
||||
const outChunks: Buffer[] = []
|
||||
const errChunks: Buffer[] = []
|
||||
child.stdout!.on("data", (d) => outChunks.push(d))
|
||||
child.stderr!.on("data", (d) => errChunks.push(d))
|
||||
|
||||
const killGroup = (sig: NodeJS.Signals) => {
|
||||
try { process.kill(-child.pid!, sig) } catch { /* already gone */ }
|
||||
}
|
||||
const finalize = (status: number) => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
clearTimeout(timer)
|
||||
// detach listeners, then resolve — no late listeners remain
|
||||
child.stdout!.removeAllListeners()
|
||||
child.stderr!.removeAllListeners()
|
||||
resolve({ stdout: Buffer.concat(outChunks).toString(), stderr: Buffer.concat(errChunks).toString(), status, timedOut })
|
||||
}
|
||||
const timer = setTimeout(() => {
|
||||
timedOut = true
|
||||
killGroup("SIGTERM")
|
||||
// bounded grace for clean shutdown, then SIGKILL the group
|
||||
setTimeout(() => killGroup("SIGKILL"), 2000)
|
||||
// the exit/close event settles; a hard stop-guard settles anyway
|
||||
setTimeout(() => finalize(124), 4000)
|
||||
}, timeoutMs)
|
||||
|
||||
child.on("error", (e) => finalize(-1))
|
||||
child.on("close", (code) => finalize(code ?? -1))
|
||||
})
|
||||
}
|
||||
|
||||
// ── MODE B: explicit detachment for "cmd &" invocations ────────────────
|
||||
function runDetached(command: string): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
const logPath = `/tmp/mimo-detached-${Date.now()}-${Math.floor(Math.random() * 1e6)}.log`
|
||||
const out = `exec >>"${logPath}" 2>&1; exec 0</dev/null; ${command}`
|
||||
const child = spawn("/bin/sh", ["-c", `setsid /bin/sh -c '${out.replace(/'/g, `'\\''`)}'`], {
|
||||
cwd: REPO,
|
||||
stdio: "ignore", // child rebinds its own fds — no PTY inheritance
|
||||
env: process.env,
|
||||
detached: true,
|
||||
// unref: MiMo's event loop does not wait for it
|
||||
})
|
||||
child.unref()
|
||||
resolve(JSON.stringify({
|
||||
detached: true,
|
||||
log: logPath,
|
||||
note: "process detached (setsid, own fds); output streams to the log file only; fd 0/1/2 do NOT reference the MiMo tty",
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
// ── wait-intent routing (semantic level, preserved from v1) ────────────
|
||||
async function tryCompileWaitIntent(command: string): Promise<string | null> {
|
||||
let routeOut: string
|
||||
try {
|
||||
routeOut = await new Promise<string>((resolve, reject) => {
|
||||
execFile("python3", [`${REPO}/scripts/await_intent_cli.py`, "route-bash", "--command", command], {
|
||||
cwd: REPO, timeout: 60000, encoding: "utf-8",
|
||||
env: { ...process.env, RUNE_WR_ROOT: WR_ROOT },
|
||||
maxBuffer: 8 * 1024 * 1024,
|
||||
}, (err, stdout) => { if (err && !stdout) reject(err); else resolve(stdout || "") })
|
||||
})
|
||||
} catch {
|
||||
return null // router unavailable: normal execution (never block on routing)
|
||||
}
|
||||
const jl = routeOut.trim().split("\n").find((l) => l.startsWith("{"))
|
||||
if (!jl) return null
|
||||
let norm: any
|
||||
try { norm = JSON.parse(jl) } catch { return null }
|
||||
// STRICT gate: compile ONLY a normalized, concrete continuation.
|
||||
if (!(norm.normalized === true &&
|
||||
norm.action === "ContinuePendingOperation" &&
|
||||
norm.operation_id && norm.sha_for_wait)) return null
|
||||
const waitCmd = `python3 ${REPO}/scripts/ci_event_wait.py --sha ${norm.sha_for_wait} --deadline ${norm.deadline_secs} --op-type ${norm.op_type}`
|
||||
const r = await runOwned(waitCmd, (norm.deadline_secs + 60) * 1000)
|
||||
const jline = r.stdout.trim().split("\n").find((l) => l.startsWith("{"))
|
||||
if (jline) {
|
||||
return JSON.stringify({
|
||||
...JSON.parse(jline),
|
||||
intent_compilation: {
|
||||
raw_command_kind: norm.raw_command_kind || "sleep_poll",
|
||||
literal_sleep_executed: false,
|
||||
operation_id: norm.operation_id,
|
||||
canonical_op_type: norm.op_type,
|
||||
authority: norm.authority,
|
||||
},
|
||||
})
|
||||
}
|
||||
return JSON.stringify({ ok: false, stage: "compiled-wait", error: (r.stderr || "no output").slice(0, 300) })
|
||||
}
|
||||
|
||||
export default tool({
|
||||
description: "Run a shell command. If the command expresses external wait intent (sleep/check/poll aimed at CI, deploy, or release operations with pending operations), it is automatically compiled to Rune's event-driven continuation — you do not need to manage wait mechanics. Plain local commands execute normally. Commands ending in ' &' run detached with output logged to a file.",
|
||||
args: {
|
||||
command: tool.schema.string().describe("Shell command to run"),
|
||||
},
|
||||
async execute(args) {
|
||||
// 1. wait-intent compilation (semantic, strict-gated)
|
||||
try {
|
||||
const compiled = await tryCompileWaitIntent(args.command)
|
||||
if (compiled !== null) return compiled
|
||||
} catch { /* fall through to normal execution */ }
|
||||
|
||||
// 2. MODE B: explicit detachment for backgrounded invocations
|
||||
const cmd = args.command
|
||||
if (/\b(nohup|setsid)\b/.test(cmd) || /&\s*$/.test(cmd)) {
|
||||
return await runDetached(cmd)
|
||||
}
|
||||
|
||||
// 3. MODE A: tool-owned, group-killed, captured execution
|
||||
const r = await runOwned(cmd, 120000)
|
||||
const text = r.stdout + (r.stderr ? `\n[stderr]\n${r.stderr}` : "")
|
||||
if (r.timedOut) {
|
||||
return `exit timed-out (process group terminated): ${text.slice(0, 500)}`
|
||||
}
|
||||
if (r.status !== 0) {
|
||||
return `exit ${r.status}: ${text.slice(0, 500) || "?"}`
|
||||
}
|
||||
return text || "(no output)"
|
||||
},
|
||||
})
|
||||
@@ -17,6 +17,7 @@
|
||||
"intent_continuity",
|
||||
"local_tool_runtime",
|
||||
"message_queue",
|
||||
"native_units",
|
||||
"openai_compat_transport",
|
||||
"provider_context",
|
||||
"recall_uplift",
|
||||
|
||||
@@ -11,24 +11,22 @@
|
||||
"NEEDS_REVALIDATION",
|
||||
"DEFERRED_FUTURE"
|
||||
],
|
||||
"live_defects": [
|
||||
324
|
||||
],
|
||||
"live_defects": [],
|
||||
"records": [
|
||||
{
|
||||
"number": 324,
|
||||
"title": "Engine defect: checkpoint writer fails deterministically on aborted worker sessions (MessageAbortedError -> empty checkpoint shells)",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "VALID_OPEN",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "FIXED_VERIFIED",
|
||||
"labels": [
|
||||
"bug",
|
||||
"custodian",
|
||||
"life",
|
||||
"memory"
|
||||
],
|
||||
"live_defect": true,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 defect no longer reproduces: zero MessageAbortedError in current logs (incl. active worker), six most recent session checkpoints full documents (111-396 lines); verified by present-absence 2026-09-19"
|
||||
},
|
||||
{
|
||||
"number": 316,
|
||||
@@ -237,8 +235,8 @@
|
||||
{
|
||||
"number": 183,
|
||||
"title": "Future: typed temporal semantics for facts, relationships, beliefs, and preferences",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "DEFERRED_FUTURE",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "HISTORICAL_EVIDENCE",
|
||||
"labels": [
|
||||
"P3 \u2014 low",
|
||||
"governance",
|
||||
@@ -250,14 +248,14 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
|
||||
},
|
||||
{
|
||||
"number": 182,
|
||||
"title": "Future: GitHub code-search prior-art audit for graph and vector memory",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "DEFERRED_FUTURE",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "HISTORICAL_EVIDENCE",
|
||||
"labels": [
|
||||
"P3 \u2014 low",
|
||||
"governance",
|
||||
@@ -266,8 +264,8 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
|
||||
},
|
||||
{
|
||||
"number": 181,
|
||||
@@ -287,13 +285,13 @@
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"next_action": "epic holds absorbed children #182 #183 + research watchlist #164 #165 #166; closes when prerequisites land or ideas dropped"
|
||||
},
|
||||
{
|
||||
"number": 179,
|
||||
"title": "Future: succession/privacy semantics and lineage evaluation",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "DEFERRED_FUTURE",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "HISTORICAL_EVIDENCE",
|
||||
"labels": [
|
||||
"P3 \u2014 low",
|
||||
"governance",
|
||||
@@ -305,14 +303,14 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 idea absorbed into parent epic #175 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
|
||||
},
|
||||
{
|
||||
"number": 178,
|
||||
"title": "Future: evidence-grounded ancestral perspective with explicit uncertainty",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "DEFERRED_FUTURE",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "HISTORICAL_EVIDENCE",
|
||||
"labels": [
|
||||
"P3 \u2014 low",
|
||||
"governance",
|
||||
@@ -322,14 +320,14 @@
|
||||
"perception"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 idea absorbed into parent epic #175 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
|
||||
},
|
||||
{
|
||||
"number": 177,
|
||||
"title": "Future: temporal autobiographical model with provenance and reinterpretation lineage",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "DEFERRED_FUTURE",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "HISTORICAL_EVIDENCE",
|
||||
"labels": [
|
||||
"P3 \u2014 low",
|
||||
"governance",
|
||||
@@ -340,14 +338,14 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 idea absorbed into parent epic #175 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
|
||||
},
|
||||
{
|
||||
"number": 176,
|
||||
"title": "Future: lineage-aware situated curiosity for meaningful autobiographical gaps",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "DEFERRED_FUTURE",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "HISTORICAL_EVIDENCE",
|
||||
"labels": [
|
||||
"P3 \u2014 low",
|
||||
"feature",
|
||||
@@ -358,8 +356,8 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 idea absorbed into parent epic #175 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
|
||||
},
|
||||
{
|
||||
"number": 175,
|
||||
@@ -379,13 +377,13 @@
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"next_action": "epic holds absorbed children #176-#179 as checklist items; closes when prerequisites land or ideas dropped"
|
||||
},
|
||||
{
|
||||
"number": 166,
|
||||
"title": "RESEARCH WATCHLIST: Memory-R1 (RL memory ops), Titans (test-time memory), Vespa/Weaviate/Milvus (retrieval competitors)",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "DEFERRED_FUTURE",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "HISTORICAL_EVIDENCE",
|
||||
"labels": [
|
||||
"P3 \u2014 low",
|
||||
"growth",
|
||||
@@ -394,14 +392,14 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
|
||||
},
|
||||
{
|
||||
"number": 165,
|
||||
"title": "RESEARCH: SimpleMem semantic compression + A-MEM dynamic linking + Letta sleep-time compute",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "DEFERRED_FUTURE",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "HISTORICAL_EVIDENCE",
|
||||
"labels": [
|
||||
"P3 \u2014 low",
|
||||
"infrastructure",
|
||||
@@ -410,14 +408,14 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
|
||||
},
|
||||
{
|
||||
"number": 164,
|
||||
"title": "RESEARCH: HippoRAG 2 \u2014 PPR-style associative propagation as warm-neuron activation candidate",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "DEFERRED_FUTURE",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "HISTORICAL_EVIDENCE",
|
||||
"labels": [
|
||||
"P3 \u2014 low",
|
||||
"growth",
|
||||
@@ -426,27 +424,27 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 idea absorbed into parent epic #181 as tracked checklist item; full detail preserved in this closed issue; re-mint when live"
|
||||
},
|
||||
{
|
||||
"number": 163,
|
||||
"title": "Temporal graph backend spike: Neo4j vs FalkorDB (LadybugDB experimental; Graphiti as reference)",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "NEEDS_REVALIDATION",
|
||||
"reconciliation_state": "VALID_OPEN",
|
||||
"labels": [
|
||||
"P1 \u2014 high",
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "run the backend spike; compare on same corpus/query set; record evidence-backed recommendation"
|
||||
},
|
||||
{
|
||||
"number": 162,
|
||||
"title": "Qdrant associative-memory projection spike (dense/sparse/multivector + ColBERT late-interaction reranking)",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "NEEDS_REVALIDATION",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "SUPERSEDED",
|
||||
"labels": [
|
||||
"P1 \u2014 high",
|
||||
"custodian",
|
||||
@@ -454,8 +452,8 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 scope carried verbatim by #316 (ADAPT-1 B3-v2); single-tracker rule"
|
||||
},
|
||||
{
|
||||
"number": 159,
|
||||
@@ -478,8 +476,8 @@
|
||||
{
|
||||
"number": 158,
|
||||
"title": "Generated wiring-status / architecture-truth report",
|
||||
"tracker_state": "open",
|
||||
"reconciliation_state": "VALID_OPEN",
|
||||
"tracker_state": "closed",
|
||||
"reconciliation_state": "SUPERSEDED",
|
||||
"labels": [
|
||||
"P2 \u2014 medium",
|
||||
"growth",
|
||||
@@ -489,8 +487,8 @@
|
||||
"ready"
|
||||
],
|
||||
"live_defect": false,
|
||||
"last_revalidated": "2026-09-11",
|
||||
"next_action": ""
|
||||
"last_revalidated": "2026-09-19",
|
||||
"next_action": "none \u2014 scope carried verbatim by #315 (ADAPT-1 B2-v2); single-tracker rule"
|
||||
},
|
||||
{
|
||||
"number": 156,
|
||||
@@ -1151,6 +1149,6 @@
|
||||
"next_action": ""
|
||||
}
|
||||
],
|
||||
"last_reconciled": "2026-09-12",
|
||||
"reconciled_by": "PL1 held-out era reconciliation (fresh session 2026-09-12)"
|
||||
}
|
||||
"last_reconciled": "2026-09-19",
|
||||
"reconciled_by": "fresh-session tranche 2026-09-19: template retrofit (spine+plain-English on all open issues), closures #158/#162 (SUPERSEDED) and #324 (FIXED_VERIFIED), research labels applied to #163/#164/#165/#166/#182/#316, stale bug labels removed from #163-#166; 2026-09-19 absorption pass: parked children absorbed into parents (#175<-#176..#179; #181<-#182,#183,#164..#166) per one-open-note-per-idea standard"
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
# Language-Fit Rubric — Wave 1 (Language-Rebasing Tranche R1)
|
||||
|
||||
> STATUS: FINAL — self-verified 2026-09-29 per tranche §12 (all 6 rounds completed,
|
||||
> evidence-sufficiency statements recorded, kill tests frozen; execution proceeds on the
|
||||
> evidence, every RECODE still passes its benchmark gate — no win, no recode).
|
||||
> Per-subsystem sections filled from live research rounds (≥2 live-verified external sources per claim,
|
||||
> per-source lessons, evidence→decision mapping, kill test per candidate). No code changes in Wave 1.
|
||||
> Governing law from §11: **KEEP-PYTHON honesty determines how much of the rebase volume is real.**
|
||||
> Toolchain baseline: Rust 1.98.1 + GCC 16.2.1 present; Go NOT installed — Go earns installation only
|
||||
> through rubric evidence here.
|
||||
|
||||
## Verdict (all rounds, one paragraph)
|
||||
|
||||
**KEEP-PYTHON across the board: 40 clusters scored, 0 recode units awarded.** Six research
|
||||
rounds (W2 leaf utilities, W3 memory, W4 provider-layer, W5 orchestration, W6 runtime-core,
|
||||
W7 TUI) each characterized their subsystem's actual workload inward (file:line-anchored) and
|
||||
tested Python/Rust/Go/C against it with live-verified sources and frozen kill tests. The
|
||||
pattern is consistent: the compute-shaped work already executes in C (hashlib, sqlite3/FTS5/vec0,
|
||||
json, regex), the dominant latency is network or LLM-bound, and no cluster contains a hot loop
|
||||
that pays for a process-boundary recode through the 658 µs–0.63 ms interop crossing. **Go:
|
||||
REJECTED — does not earn installation this tranche** (D5=0 everywhere; nothing measured or
|
||||
fetch-confirmed earns it; orchestration additionally rejects its design fit; K-GO kill tests
|
||||
frozen per round should the case be revived). **Rust: toolchain-ready, justified nowhere this
|
||||
tranche** — keep as the standing option behind the CI-proven std-only adapter for any future
|
||||
measured hot loop. **C: rejected everywhere scored** (duplicates C already inside SQLite/hashlib;
|
||||
adds an unsafe-memory surface). The rebase volume the tranche hypothesized is real only as a
|
||||
small set of named improvements — see "Wave-plan consequence" below.
|
||||
|
||||
## Rubric dimensions (applied to every candidate language per subsystem)
|
||||
|
||||
| Dimension | Question | Evidence required |
|
||||
|---|---|---|
|
||||
| D1 Workload fit | Does the subsystem's dominant workload (I/O-bound, CPU-bound, FFI, protocol, UI) actually favour this language? | Benchmarks or authoritative docs, live-verified |
|
||||
| D2 Measured gain | What wins, concretely — latency, memory, startup, binary distribution? | Named hot paths from the Wave 0 inventory + numbers |
|
||||
| D3 Interop cost | What does the interop contract (§5) cost to carry for this boundary? | Adapter surface size, ABI/build complexity |
|
||||
| D4 Ecosystem | Do the needed libraries exist and are they maintained? | Live-verified crate/package/module listings |
|
||||
| D5 Toolchain reality | Is the toolchain present (or installable and justified) on this machine and the CI runner? | Runner + local `--version` evidence |
|
||||
| D6 Maintenance continuity | Can the Rune ecosystem's single-maintainer loop sustain code in this language here? | Honest judgement, stated plainly |
|
||||
| D7 Kill test | What is the CHEAPEST disproof of this candidate? | One falsifiable early test, frozen before any recode |
|
||||
|
||||
Scoring: each candidate gets D1–D6 scored 0–2 with one-line evidence each, D7 written regardless.
|
||||
Decision per subsystem: **KEEP-PYTHON** / **RECODE→<language>** — KEEP-PYTHON is the expected default;
|
||||
a RECODE that cannot pass its own kill test reverts to KEEP-PYTHON before implementation.
|
||||
|
||||
---
|
||||
|
||||
## W3 — Memory & persistence (units: memory_store 56 fns, curator 43, warm_router 32, memory_consolidation 20, sleep_time 25, + graph_memory, night_mode, identity_anchors)
|
||||
|
||||
- **Research round actor:** general-2 (COMPLETED 2026-09-29 — artifacts at
|
||||
`research/wave1/memory/`: inward.md, outward/ ×6, outward-sources.md, synthesis.md)
|
||||
- **Intention profile:** JSONL-heavy appends, BM25/FTS ranking, consolidation passes, long-running
|
||||
scheduled jobs, file-backed state.
|
||||
- **Decision:** **KEEP-PYTHON (all 7 clusters, zero RECODE).** Cluster verdicts:
|
||||
(1) hot-store JSON persistence — KEEP with upgrade path: orjson in-process wheel
|
||||
(~10× dumps / 2× loads); a bespoke Rust CLI unit is dead on spawn cost (the
|
||||
`shared/native_units.py` crossing ~1–5 ms ≈ orjson's entire 3.4 MB `knowledge.json` decode);
|
||||
(2) SQLite store + FTS5/vec0 recall — KEEP, the compute is already C inside SQLite
|
||||
(`memory_store.py:646` vec0 MATCH, `:693` bm25); (3) neuron scoring/routing — KEEP,
|
||||
network-bound `_embed` (Ollama subprocess curl) dominates; (4) graph BFS — KEEP,
|
||||
hops=1 default, per-node SQL, tiny N; the future fix is a SQL CTE, not a language;
|
||||
(5) batch consolidation/curator — KEEP, LLM/I-O-bound and latency-insensitive,
|
||||
asyncio sweet spot; (6) orchestration/glue — KEEP, pure glue pinned by the Python-TUI
|
||||
interop contract; (7) embedding transport — KEEP, network-bound.
|
||||
- **Candidate matrix summary:** Python 7/7 · Go 0/7 (not installed, nothing measured or
|
||||
fetch-confirmed earns installation; Go's JSON stack mid-rewrite upstream) · hand-written C
|
||||
0/7 (C already battle-tested inside SQLite — hand-writing would duplicate it) · Rust 0/7
|
||||
as CLI units (spawn cost kills the one credible vector; in-process wheels excluded by
|
||||
Wave 0 policy).
|
||||
- **Kill tests (frozen in synthesis.md):** Rust-JSON — orjson microbench on live 3.4 MB
|
||||
`knowledge.json` (if drop-in and ≥2× load / ≥5× dump, the CLI unit is disproven on spawn
|
||||
cost); Rust-general — kill unless a profile shows ≥50% wall time in pure Python compute
|
||||
(none exists; reopen only on materially changed workload); Go — instrument one
|
||||
`consolidate_all` run, kill if Python-compute share <50% (it will be — LLM/I-O bound);
|
||||
C — kill unless a hot kernel absent from the SQLite extension ecosystem is identified
|
||||
(none).
|
||||
- **Sources + lessons:** 6 live-fetched 2026-09-29 (orjson, sled, sqlite-vec, SQLite FTS5
|
||||
docs, Go json/v2 rewrite issue, pydantic-core) — full annotations in
|
||||
`research/wave1/memory/outward-sources.md`.
|
||||
- **Evidence sufficiency (honest):** static analysis only, no runtime profiling;
|
||||
memory.store SQLite DB not materialized locally — kill tests specify *measured*
|
||||
thresholds rather than assertions. Verdicts rest on "Python is glue around C/network,"
|
||||
which profiling would only strengthen.
|
||||
|
||||
## W4 — Provider/model layer (units: provider_registry 28, model_connect 10, model_routing 15, model_profiles 15, provider_budget 21, + standardized_providers, model_registry, connection_pool)
|
||||
|
||||
- **Research round actor:** general-5 (COMPLETED 2026-09-29 — artifacts at
|
||||
`research/wave1/provider-layer/`: inward.md, outward-sources.md, outward/ (8 evidence
|
||||
JSONs), synthesis.md)
|
||||
- **Intention profile:** HTTP/SSE streaming, connection pooling, retries/backoff, protocol parsing,
|
||||
tool-call reliability.
|
||||
- **Intention profile correction (inward-verified):** the layer has **NO retry/backoff and NO
|
||||
SSE stub at all** (grep-verified) — `stream: False` everywhere, ~900 lines, remote-LLM-latency-
|
||||
bound. Rewrite pitches are therefore feature-adds, not ports.
|
||||
- **Candidate matrix:** 5 clusters, all KEEP-PYTHON. Scores (1–5 = fit for the cluster's actual
|
||||
workload): (C1) HTTP wire + transport (provider_registry, openai_compat_transport, model_connect
|
||||
discovery) Python 5 / Go 2 / Rust 1; (C2) connection pool (connection_pool.py, 144 lines —
|
||||
in-process object guards under threading.Lock, NOT a TCP pool) Python 5 / Go 2 / Rust 2;
|
||||
(C3) routing decisions (model_routing.py, 432 lines, pure decision logic, one httpx call)
|
||||
Python 5 / Go 1 / Rust 1; (C4) budget accounting (provider_budget.py, 354 lines, pure
|
||||
arithmetic + lock, no I/O) Python 5 / Go 1 / Rust 1; (C5) config/registry/normalization
|
||||
(model_profiles, model_registry, standardized_providers, model_connect tables — dataclasses +
|
||||
JSON, editable by non-systems programmers) Python 5 / Go 1 / Rust 1.
|
||||
- **Decision:** **KEEP-PYTHON (all 5 clusters).**
|
||||
- **Kill tests:** C1 Go — KILLED: toolchain absent (`which go` → not found); 28 call-site
|
||||
behaviors incl. the tool-call envelope contract (openai_compat_transport.py:67-107, 160-207)
|
||||
would be re-implemented with zero incumbent test port and NO performance signal (remote-LLM-
|
||||
latency-bound, kilobyte payloads). Re-earn path if Go is ever installed: std-only proof via
|
||||
`interop/rebase-proof/` + a benchmark harness on C1 only. C1 Rust — KILLED BY CONSTRUCTION:
|
||||
SSE parsing requires reqwest+tokio+eventsource-stream+nom (outward O3/O4/O5 — even mistral.rs
|
||||
takes the tokio stack), violating the std-only interop contract. C2–C5 Go/Rust — KILLED:
|
||||
burden of proof sits on the rewrite candidates; kill tests need contention/throughput/
|
||||
counter-evidence that does not exist; routing runs once per request at millisecond scale
|
||||
against multi-second LLM calls (5 orders of magnitude below any measurable threshold).
|
||||
- **Sources + lessons:** 8 live-fetched (O1–O8), ≥2 per major claim, coverage map in
|
||||
`outward-sources.md`. Lessons: (1) stdlib-only Rust has no realistic precedent for HTTP/SSE
|
||||
workloads — the interop contract's zero-crate standard effectively decides Rust out of all
|
||||
network-wire clusters; (2) Go's stdlib HTTP+NDJSON streaming is capability-proven
|
||||
(pkg.go.dev/net/http, ollama api/client.go, ollama's Go API server) — Go's losses here are
|
||||
evidence-absence, not capability-absence; (3) the honest reliability upgrade for this layer
|
||||
is a small Python-level httpx retry/timeout wrapper — a feature-add, not a language change.
|
||||
|
||||
## W5 — Orchestration, authority, plugins, skills (units: orchestration/ 44 files 244 fns, contracts, build_mode 34, construction_authority*, verification_construction, spine, + governance surfaces: drift_*, persona_gate, safety_override, witness, behavior, growth_delta, claim_audit)
|
||||
|
||||
- **Research round actor:** general-1 (COMPLETED 2026-09-29 — artifacts at
|
||||
`research/wave1/orchestration/`: inward.md, outward-sources.md, outward/ (4 search
|
||||
JSONs), synthesis.md)
|
||||
- **Intention profile:** contract/lifecycle state machines, authority gating, fail-closed validation,
|
||||
HMAC-chained ledgers, policy dispatch.
|
||||
- **Intention profile correction (inward-verified):** the subsystem is durable-ledger I/O,
|
||||
authority wiring, deterministic policy gates, and TUI-facing coordination — NOT hot loops
|
||||
(2 RLocks, 0 sockets, 0 thread pools across 43 files). **Scope gap: `construction_authority.py`
|
||||
and `verification_construction.py` do not exist in the tree** — the construction cluster is
|
||||
covered by build_mode.py; no evidence invented for the missing files.
|
||||
- **Candidate matrix:** 6 clusters, all KEEP-PYTHON. Scores (1–5 = fit for the cluster's actual
|
||||
workload): (C1) durable state & ledger stores (event_store.py:56-101, atomic.py, evidence_store.py
|
||||
— fsync-bound; hashing already C via hashlib) Python 5; (C2) composition roots & authority wiring
|
||||
(composition.py, authority.py, cognitive.py — pure glue, runtime cost ≈ 0) Python 5; (C3)
|
||||
policy/state machines/gates (lifecycle.py, scheduler.py, broker.py, no_change.py, reflex.py —
|
||||
deterministic dict/enum decisions, sub-ms; testability is the requirement) Python 5; (C4)
|
||||
structural self-model & schema tooling (spine.py:24-25, microkernel.py, contracts.py, records.py
|
||||
— introspection + canonical JSON; only candidate for a future Rust spine-diff if snapshots grow
|
||||
1000×) Python 4; (C5) TUI-facing orchestration & build pipeline (build_mode.py 11-stage pipeline,
|
||||
gateway.py, transport.py — the consumer IS the Python TUI; latency dominated by LLM/subprocess
|
||||
waits) Python 5; (C6) benchmark/migration harnesses (retrieval_benchmark.py, migrate.py,
|
||||
benchmark.py — offline tooling, recode buys nothing, loses iteration speed) Python 4.
|
||||
- **Decision:** **KEEP-PYTHON (all 6 clusters). This subsystem contributes 0 recode units to
|
||||
the wave plan.** Go: REJECTED, do not install — differentiator (goroutine-dense servers)
|
||||
targets a workload absent here; cost is exception→error-value rewrite of ~260 functions.
|
||||
Rust: FEASIBLE (toolchain proven) but UNJUSTIFIED anywhere — no cluster has the hot loop
|
||||
that pays for a process-boundary recode; keep as toolchain-ready for other subsystems.
|
||||
C: REJECTED — the only compute-shaped work (sha256) already executes C via stdlib hashlib.
|
||||
- **Kill tests:** K1 (frozen, ALREADY RUN): 100 round-trips through the rebase-proof adapter —
|
||||
mean 0.63ms, p95 0.74ms, cold 0.87ms, 100% exit-0 + ok:true → adapter overhead does NOT block
|
||||
recodes on cost; recodes die on value grounds. Re-open any cluster if profiling shows a
|
||||
function consuming >10% of a real interactive session. K-GO (frozen, ~30 min): Go prototype
|
||||
of event_store.py's batched append+fsync vs Python at 1000 events; if Python's p95 is within
|
||||
2× of Go's, Go is dead here permanently. K-RUST (frozen, ~20 min): measure spine diff on a
|
||||
10k-entity snapshot; <50ms kills any Rust spine recode by absence of pain.
|
||||
- **Sources + lessons:** 4 live-fetched web sources (pydantic-core, ruff blog, go.dev FAQ,
|
||||
Python 3.14 hashlib docs) + 1 LOCAL EXPERIMENT (n=100 adapter benchmark). Lessons: (1) the
|
||||
rebase-proof adapter round-trips at 0.63ms/op — subprocess-per-op is viable for coarse ops,
|
||||
never per-event; (2) Python's "slowness" argument dissolves where the actual compute already
|
||||
runs in C via stdlib (hashlib, sqlite) — the language question is really "where is the hot
|
||||
loop", and here the answer is nowhere; (3) assumed limits flagged honestly: human-scale event
|
||||
cadence (batch_size=8) and Linux spawn cost — both would need revisit at 10⁴+ events/sec or
|
||||
cross-platform targets.
|
||||
|
||||
## W6 — Runtime core & tooling (units: tool_executor 46, tool_protocol 27, local_tool_runtime 32, capability_broker 19, context_broker 21, work_manager 25, cron_engine 28, + failure_auto_filer 28, hook_engine, elastic_cognition, auto_tasks, goal)
|
||||
|
||||
- **Research round actor:** general-4 (COMPLETED 2026-09-29 on disk despite cancellation
|
||||
notification — artifacts at `research/wave1/runtime-core/`: inward.md, outward/,
|
||||
outward-sources.md, synthesis.md)
|
||||
- **Intention profile:** subprocess/process supervision, native execution boundary (native_units
|
||||
adapter already exists), event loops, cron scheduling, hook dispatch.
|
||||
- **Decision:** **STAY-PYTHON (all 6 clusters).** Round scores (1–5 = fit for the cluster's
|
||||
actual inward-characterized workload): (A) subprocess lifecycle (tool_executor, cron_engine,
|
||||
auto_tasks) 4.7 — `subprocess.run(timeout=, capture_output=)` is a one-call expression of the
|
||||
pattern; Rust std::process has NO built-in child timeout (outward-verified), strictly more
|
||||
code under zero-crate; (B) protocol/JSON parsing (tool_protocol, brokers) 4.5 — inputs are
|
||||
KB-scale model fragments; Python json/regex is already C-backed, so a rewrite swaps C for
|
||||
compiled code at the same asymptotic cost; serde's typed-struct model actively mismatches
|
||||
fence-wrapped schema-flexible output; (C) model→tool control loop + HTTP
|
||||
(local_tool_runtime, elastic_cognition, goal) 4.8 — wall time is LLM HTTP latency in seconds;
|
||||
Python overhead is µs–ms noise; the loop's content is policy (circuit breaker, escalation
|
||||
ladders, routing tables); (D) context assembly (context_broker) 4.7 — correctness lives in
|
||||
admission policy and degrade-not-crash semantics, not speed; compaction is itself an LLM call;
|
||||
(E) reliability/queueing (failure_auto_filer) 4.2 — honest lowest: on paper the best Rust
|
||||
candidate (queue + worker + crash-safe JSONL spool), but perf requirement ≈ nil and the
|
||||
correctness burden is threading semantics a rewrite would re-risk for no win ("nothing
|
||||
breaks today"); (F) declarative config/brokers (work_manager, hook_engine, capability_broker)
|
||||
4.9 — literal data, no-op runtime, portable to anything valuable in nothing.
|
||||
- **Candidate matrix summary:** Python 6/6 · Go 0/6 (paper verdicts only — evidence-starved,
|
||||
not installed, kill tests unrunnable locally) · Rust 0/6 (kill tests runnable via the
|
||||
existing std-only interop harness) · C unscored (no FFI-adjacent cluster surfaced).
|
||||
Best-language moment found anywhere: robfig/cron replacing ~37 hand-rolled cron-parsing
|
||||
lines (cron_engine.py:199-236) — ergonomics nicety, not a fit verdict.
|
||||
- **Kill tests (frozen in synthesis.md):** Rust-A — re-express `_run_command`
|
||||
(tool_executor.py:1064) with std::process + manual timeout; kill if >2× the ~40-line
|
||||
Python wrapper (Q4 predicts it is); Go-A — port `cron_engine._run_loop` with os/exec,
|
||||
measure task-fire latency delta (prediction: zero — 60 s sleep and child runtime dominate);
|
||||
B — parse the largest observed tool-protocol stream 1000× in Python; kill if total <1 s
|
||||
(no rewrite yields an observable win); C — instrument `_run_loop`
|
||||
(local_tool_runtime.py:417), log non-HTTP CPU per iteration (prediction <1% of wall);
|
||||
D — time `assemble`+`_admit` on the largest stored context, kill if <10 ms; E — fault-inject
|
||||
kill -9 during spool append; if recovery semantics already hold, the rewrite has no
|
||||
correctness win to buy; F — none needed: absence of any win condition IS the disproof.
|
||||
- **Sources + lessons:** live-fetched 2026-09-29 — annotations in
|
||||
`research/wave1/runtime-core/outward-sources.md`; headline lessons: Rust std::process lacks
|
||||
child timeout (Q4); Go os/exec reaches parity but changes only syntax (Q1); Python
|
||||
json/regex C-backed (Q5b); serde typed structs mismatch dynamic model output (Q5a);
|
||||
concurrency features irrelevant at ≤2 threads (Q6).
|
||||
- **Evidence sufficiency:** Python verdicts fully evidenced inward+outward; Go execution-side
|
||||
evidence honestly starved (paper kill tests carried forward); E's JSONL-spool crash-safety
|
||||
claim rests on inward semantics only — flagged in synthesis.md.
|
||||
|
||||
## W7 — Operator + TUI (units: rune_operator 61 fns, rune_tui 161 fns — largest module, tui_validator)
|
||||
|
||||
- **Research round actor:** general-3 (COMPLETED 2026-09-29 — artifacts at
|
||||
`research/wave1/tui/`: inward.md, outward/ ×8, outward-sources.md, synthesis.md)
|
||||
- **Intention profile:** terminal rendering, input handling, rich layout, hot store state, supervisory
|
||||
command surface. Design decision 4 holds: TUI consumes the interop contract, never rewritten first.
|
||||
- **Decision:** **KEEP-PYTHON (TUI shell; all 4 clusters, zero RECODE, no carve-out found).**
|
||||
Cluster scores (1 = recode, 5 = keep): (A) rendering/widgets 4 — no hot loop exists; render is
|
||||
plain Rich `Text` concatenation (rune_tui.py:1331, chat_bubble.py:157), only animation a 0.12 s
|
||||
spinner (:263), no markdown/Syntax parsing anywhere in src/rune; (B) event glue (~50 `_cmd_*`
|
||||
handlers, reactives, tool-widget maps) 5 — this is Textual's core competency (workers,
|
||||
`exclusive=True`, `call_from_thread`); vendor docs (ratatui) admit "little to no help in organizing
|
||||
large applications"; (C) model send path + envelope 5 — synchronous `send_task` in async worker;
|
||||
the envelope shape (`success/response/thinking/tool_events/degraded`, rune_tui.py:3624ff) is
|
||||
ALREADY the de-facto interop contract; (D) subprocess/streaming 5 — JSONL streaming precedent
|
||||
already in-tree (`_cmd_pull` :3443-3517): the pattern for consuming recoded units, not a recode
|
||||
target. Whole-TUI native recode 1/5 REJECTED — 80+ first-party module coupling, framework-provided
|
||||
concurrency re-implemented by hand; Go additionally toolchain-blocked. Countervailing evidence
|
||||
(Bubble Tea/tview/Codex TUI maturity) recorded honestly in outward-sources.md — it does not
|
||||
outweigh the coupling.
|
||||
- **⚠ CONTRACT GAP FLAGGED (binds Waves 2–7):** `shared/native_units.py` parses only the LAST
|
||||
stdout line — it must gain a JSONL streaming reader (per-line `json.loads` + terminal-envelope
|
||||
validation) before any recoded long-running unit can stream progress to the TUI. Small, testable,
|
||||
non-breaking; candidate for the first Wave 2 implementation issue.
|
||||
- **Adapter surface (TUI as consumer — adopted as the rubric's interop-contract restatement):**
|
||||
(1) single-invocation stateless CLI (`native_unit <op> [args]`, no daemon); (2) success = final
|
||||
stdout line `{"ok":true, …}` generalizing the model-send envelope — recoded units emitting
|
||||
`response`/`tool_events`/`degraded` plug in with zero TUI changes; (3) failure = `ok:false` +
|
||||
nonzero exit, stderr human-only, success = exit 0 AND not timed out; (4) mandatory `--version`
|
||||
on every unit (status bar + `canary_tui_drift.py` detect live units vs Python fallback);
|
||||
(5) JSONL streaming mode for long ops with terminal sentinel envelope; (6) per-call timeout
|
||||
budget, `timed_out` surfaced in `NativeResult` for graceful degradation; (7) streamed events
|
||||
referencing UI objects carry the TUI's stable keys — `(channel, call_id)` for tool widgets
|
||||
(:3676), WorkPane `_entries` object ids (:1239) — preserved verbatim; (8) std-only for
|
||||
proof-phase units.
|
||||
- **Candidate matrix summary:** Python 4/4 clusters · Rust/Go whole-TUI 1/5 rejected · carve-out
|
||||
candidates: none found (future markdown parsing would carve as a Rust native unit behind the
|
||||
adapter, not now).
|
||||
- **Kill tests (frozen in synthesis.md):** stay-Python — killed if >16 ms UI-thread stalls under
|
||||
heavy event bursts OR IPC latency dominates message round-trip (Textual pilot measurement);
|
||||
Rust recode — killed if the adapter must expose >~15 first-party modules (count today ≈80:
|
||||
killed NOW); Go recode — additionally killed by toolchain absence (`command -v go` empty).
|
||||
- **Sources + lessons:** 8 live-fetched 2026-09-29 (Textual workers guide, ratatui vendor docs,
|
||||
Bubble Tea/tview/Codex countervailing evidence, JSON Lines spec, push-granular-work guidance) —
|
||||
annotations in `research/wave1/tui/outward-sources.md`.
|
||||
- **Evidence sufficiency (honest):** full inward read of all 5 TUI files with line refs; ≥2 sources
|
||||
per major claim; gap = no runtime profiling (stall kill test unmeasured — but no mechanism exists
|
||||
for the stall to occur; the 120 ms 21-step pipeline was already removed, `_run_warm_router`
|
||||
:3575 is a no-op).
|
||||
|
||||
## W2 — Leaf utilities & canaries (~40 modules, low coupling: pins, time_awareness, message_queue, event_envelope, attention_capsule, complexity_scorer, token_optimizer, cache 501/17, prompt_sync, chat_bubble, ~15 canary_* modules)
|
||||
|
||||
- **Research round actor:** general-6 (COMPLETED 2026-09-29 — full report in actor notification)
|
||||
- **Intention profile:** small pure helpers, envelopes, scoring, cache; smallest blast radius; the
|
||||
factory + interop proving ground at real scale.
|
||||
- **Ground-truth measurements (local, this session):** Python fn call ~46 ns (100k timed
|
||||
iterations in-process) · native CLI roundtrip ~658 µs (subprocess to
|
||||
`interop/rebase-proof/target/release/rebase-proof --version`) · Python startup floor ~18 ms ·
|
||||
overhead ratio ≈ **14,000×**. The only CI-proven interop contract is the subprocess CLI boundary
|
||||
(`shared/native_units.py`: argv in → JSON stdout, `--version`, timeout, typed `NativeResult`).
|
||||
PyO3/in-process bindings excluded by Wave 0 policy. Therefore every per-call crossing costs
|
||||
≥658 µs — a per-turn helper would need to run >14,000× faster in Rust to break even.
|
||||
- **Candidate matrix (representative — full per-cluster 0–2 scoring in round report):**
|
||||
Python 12/12 in every cluster · Rust 5–6/12 · Go 1–3/12 (D5=0, not installed) · C 1–2/12.
|
||||
No module contains a hot loop (heaviest: 2 `re.sub` per turn in token_optimizer).
|
||||
- **Decision:** **KEEP-PYTHON (all ~40, zero RECODE).** Cluster verdicts: (a) pure CRUD helpers
|
||||
pins/time_awareness/token_optimizer — KEEP, CPython 3.11+ already 10–60% faster on this shape
|
||||
(PEP 659); (b) message/envelope/capsule structures — KEEP, recode would insert a boundary
|
||||
between the chattiest neighbors; (c) cache.py (501 L, largest in wave) — KEEP, the fast part is
|
||||
already C (sqlite3 DB-API 2.0 over SQLite's C library), Python is thin orchestration, batching
|
||||
(threshold 50 / 30 s) already amortizes writes; (d) chat_bubble.py — KEEP, **hard-pinned** to
|
||||
Python by the Textual framework (recode = full framework abandonment, bottleneck is human
|
||||
typing speed); (e) prompt_sync.py glue — KEEP, glue into Python siblings (memory_env,
|
||||
voice_sync, build_pipeline_policy); (f) ~19 canary_* — KEEP **categorically**, a canary that
|
||||
verifies Python importability cannot exist in another language.
|
||||
- **Kill tests (reopening criteria, all fail today on first cheap measurement):** Rust — microbench
|
||||
one per-turn helper behind the native_units CLI, must beat the Python in-process call >10×
|
||||
end-to-end including the 658 µs crossing (whole call <~46 µs; a trivial `--version` already
|
||||
costs 658 µs); Go — identical benchmark post-install, uninstall if roundtrip >100 µs with no
|
||||
named hot path; C — identical benchmark + required fuzz-clean JSON roundtrip, plus a
|
||||
demonstrated GC-free allocation-hot loop first; cache.py — recode only if Python-side
|
||||
orchestration (excl. sqlite3 waits) exceeds 5% of end-to-end latency; capsule/envelope/queue —
|
||||
recode only if one turn's Python total exceeds ~5 ms AND a candidate's CLI path is >10× cheaper.
|
||||
- **Sources + lessons:** (1) https://docs.python.org/3/whatsnew/3.11.html — 10–60% faster,
|
||||
PEP 659 specializing interpreter: CPython already optimized for helper-shaped code, the D2
|
||||
baseline is a moving improving target; (2) https://docs.python.org/3/whatsnew/3.13.html —
|
||||
free-threading/JIT experimental, KEEP-PYTHON ≠ frozen but no bets on experimental paths;
|
||||
(3) https://www.maturin.rs/ — in-process Rust↔Python needs a whole binding/packaging toolchain
|
||||
atop the CLI boundary, D3 worse than measured 658 µs (Wave 0 policy excludes it anyway);
|
||||
(4) https://go.dev/doc/install — Go is a pre-install prerequisite, D5=0 everywhere, never earned
|
||||
installation; (5) https://textual.textualize.io/ — Textual is a Python TUI framework,
|
||||
chat_bubble.py framework-pinned; (6) https://docs.python.org/3/library/sqlite3.html — sqlite3 is
|
||||
DB-API 2.0 over C, cache.py's perf layer already native. All fetched live 2026-09-29.
|
||||
- **⚠ Inventory drift (VERIFIED 2026-09-29):** complexity_scorer.py listed in
|
||||
rebase-inventory.json (2 mentions) but absent on disk — deleted in commit 867321e
|
||||
("governed retirement — complexity_scorer deleted (602 lines)"). Wave 0 inventory needs a
|
||||
correction pass; the module was scored nowhere (no source to characterize).
|
||||
|
||||
---
|
||||
|
||||
## Wave-plan consequence (T5 scope, from the verdict above)
|
||||
|
||||
With **0 recode units awarded**, the tranche's hypothesized rebase volume is real only as the
|
||||
work below. Waves 2–9 are **disposition + named improvements, NOT mass recoding**:
|
||||
|
||||
**Waves 2–7 — per-issue disposition (the 1,852 `[rebase w{wave}]` issues):**
|
||||
Each issue receives its tranche §7 disposition — improve / fix / missing-connectors answered
|
||||
with evidence — plus a language verdict of **KEEP-PYTHON with its rubric evidence line**
|
||||
(the round section for that subsystem names the claim). Disposition runs leaf-first
|
||||
(Wave 2 → 7), the canonical suite stays green throughout, and no issue closes without its
|
||||
evidence line. A recode is off the table unless a frozen kill test is reopened — and then
|
||||
tranche §6 still governs: **no benchmark win, no recode.** Go is not installed and earned no
|
||||
installation; Rust stays toolchain-ready but unjustified (standing option behind the
|
||||
CI-proven adapter).
|
||||
|
||||
**Named improvements — the actual rebase volume (ship alongside disposition):**
|
||||
1. **JSONL streaming reader for `shared/native_units.py`** (W7 contract gap): the adapter
|
||||
parses only the LAST stdout line; it must gain per-line `json.loads` + terminal-envelope
|
||||
validation before any recoded long-running unit could stream progress. Small, testable,
|
||||
non-breaking — first implementation issue of Wave 2.
|
||||
2. **httpx retry/timeout wrapper for the provider layer** (W4): the honest reliability
|
||||
upgrade is a feature-add, not a language change.
|
||||
3. **orjson upgrade path** (W3 cluster 1): the only credible Python-side JSON win —
|
||||
in-process, no boundary crossing. **DISPOSITION (2026-09-29, kill test EXECUTED and
|
||||
FAILED — KEEP-PYTHON stands, no dependency declared):** microbench on the live
|
||||
`~/.rune/consolidation/knowledge.json` (3,540,959 bytes, n=30 best-of): load 13.15 ms
|
||||
std vs 7.85 ms orjson = **1.68× (bar ≥2×: FAIL)**; dump 9.58 ms std vs 5.61 ms
|
||||
orjson-with-decode = **1.71× (bar ≥5×: FAIL)**; raw-bytes dump 1.39 ms = 6.91× but is
|
||||
not drop-in (every `write_text`/`json.dump`-to-file site would need a bytes→str or
|
||||
binary-write conversion). Roundtrip equality verified. Bench: `/tmp/orjson_bench.py`
|
||||
shape (uvx --with orjson). The bytes trap measured real: decode() eats ~60% of the
|
||||
dump win.
|
||||
4. **complexity_scorer.py inventory correction**: listed in `rebase-inventory.json` but
|
||||
deleted on disk (commit `867321e`, 602 lines) — Wave 0 inventory needs the correction
|
||||
pass. **DISPOSITION (2026-09-29, DONE):** inventory regenerated per the script's own
|
||||
header (never hand-edit) — 177→213 files, 1,852→2,314 functions, 13 dead files
|
||||
dropped; committed + pushed `5bc837c`. The W2 round's "2 mentions" drift claim
|
||||
verified FALSE against the live inventory (zero hits).
|
||||
5. **robfig/cron** (W6): recorded as a best-language footnote only; no action.
|
||||
|
||||
**Wave 8 — TUI integration proof:** demonstrate the TUI reading/utilising the mixed-language
|
||||
surfaces that exist (the `interop/rebase-proof` unit through the upgraded adapter), per the
|
||||
8-point adapter surface adopted above.
|
||||
**Wave 9 — close-out audit:** 100% of the 1,852 issues dispositioned, debt-table revision,
|
||||
version bump.
|
||||
|
||||
## Cross-cutting candidates (evaluated once, referenced by every subsystem)
|
||||
|
||||
- **Rust (present, 1.98.1):** interop proof unit already CI-proven (std-only, zero crates, `interop/rebase-proof/`, adapter in `shared/native_units.py`, ok = exit 0 AND not timed out).
|
||||
- **Go (absent):** must earn installation through D1–D5 evidence here before any recode targets it.
|
||||
- **C (present, GCC 16.2.1):** expected to lose D6 in most subsystems; scored where FFI-adjacent work exists.
|
||||
- **Python (KEEP baseline):** the default. Every subsystem begins here; evidence must move it.
|
||||
|
||||
## Evidence ledger (per-source lessons, all rounds)
|
||||
|
||||
Index of per-source evidence. Full annotations live in each round's
|
||||
`research/wave1/<subsystem>/outward-sources.md`; this ledger records the headline lesson
|
||||
each source contributed and the rubric claims it supports.
|
||||
|
||||
| Round | Sources (live-fetched 2026-09-29) | Headline lessons | Supports |
|
||||
|---|---|---|---|
|
||||
| W2 leaf utilities | 6: python.org 3.11 + 3.13 whatsnew, maturin.rs, go.dev/doc/install, textual.textualize.io, docs.python.org sqlite3 | CPython 3.11+ already 10–60% faster on helper-shaped code (PEP 659) — D2 baseline is a moving target; free-threading/JIT experimental, no bets; in-process bindings need a whole toolchain atop the CLI boundary (excluded by Wave 0 policy anyway); Go is pre-install prerequisite, D5=0; Textual framework-pins chat_bubble.py; sqlite3 perf layer already C | W2 KEEP-PYTHON ×~40; the 14,000× crossing-overhead law |
|
||||
| W3 memory | 6: orjson, sled, sqlite-vec, SQLite FTS5 docs, Go json/v2 rewrite issue, pydantic-core | orjson is the only credible Python-side JSON win (in-process, no boundary); SQLite FTS5/vec0 compute is already C; Go's JSON stack mid-rewrite upstream (versioning risk); pydantic-core shows the Rust-as-wheel pattern, excluded by policy | W3 KEEP-PYTHON 7/7; orjson upgrade path on cluster 1 |
|
||||
| W4 provider-layer | 8: live-fetched O1–O8 (HTTP/SSE ecosystem, tokio-stack precedents incl. mistral.rs, pkg.go.dev/net/http, ollama Go client/server) | stdlib-only Rust has no realistic HTTP/SSE precedent — the zero-crate contract decides Rust out of all network-wire clusters by construction; Go's stdlib HTTP+NDJSON streaming is capability-proven (its losses here are evidence-absence, not capability-absence); the honest reliability upgrade is a Python httpx retry/timeout wrapper — feature-add, not language change | W4 KEEP-PYTHON 5/5; SSE-cluster Rust kill-by-construction |
|
||||
| W5 orchestration | 4: pydantic-core, ruff blog, go.dev FAQ, Python 3.14 hashlib docs + 1 LOCAL EXPERIMENT (n=100 adapter benchmark) | adapter round-trips at 0.63ms/op — subprocess-per-op viable for coarse ops, never per-event; Python "slowness" dissolves where compute already runs in C via stdlib; the language question is really "where is the hot loop" (here: nowhere) | W5 KEEP-PYTHON 6/6; K1 kill test already run |
|
||||
| W6 runtime-core | headline lessons (full set in round outward-sources.md) | Rust std::process lacks built-in child timeout — strictly more code under zero-crate; Go os/exec reaches parity but changes only syntax; Python json/regex C-backed so rewrite swaps C for compiled code at equal asymptotic cost; serde typed structs mismatch schema-flexible model output; concurrency features irrelevant at ≤2 threads | W6 STAY-PYTHON 6/6; robfig/cron as best-language footnote |
|
||||
| W7 TUI | 8: Textual workers guide, ratatui vendor docs, Bubble Tea/tview/Codex TUI (countervailing), JSON Lines spec, push-granular-work guidance | Textual workers/`call_from_thread` are the core competency for event glue; ratatui admits "little to no help in organizing large applications"; countervailing native-TUI frameworks recorded honestly — do not outweigh 80+ module coupling; JSONL per-line parse + terminal sentinel is the streaming contract; vendor guidance: push granular speed-sensitive work to subcomponents only when measured | W7 KEEP-PYTHON 4/4; the 8-point adapter surface (adopted as the rubric's interop-contract restatement) |
|
||||
@@ -0,0 +1,50 @@
|
||||
# Wave 0 close-out report — language-rebasing tranche R1
|
||||
|
||||
Branch: `tranche-r1-wave-0` · Date: 2026-09-29
|
||||
|
||||
## 1. Inventory (docs/rebase/rebase-inventory.json)
|
||||
|
||||
- 177 Python modules, ~52,750 lines, 227 classes
|
||||
- TRUE unit count: **1,852 = 1,030 top-level functions + 822 class methods**
|
||||
- Zero duplicate call edges, zero method leaks (generator double-walk defect
|
||||
root-caused and fixed in scripts/rebase_inventory.py)
|
||||
- Cross-verified against an independent fresh AST walk: zero missing units;
|
||||
six inventory-"extras" are real nested/if-try-block classes the naive walk
|
||||
misses (inventory is MORE complete, not less)
|
||||
|
||||
## 2. Issue factory (scripts/rebase_issue_factory.py)
|
||||
|
||||
- One issue per unit following R1 §7; wave-batched (2–7); dedup-safe via
|
||||
deterministic title `[rebase w{wave}] {relpath}::{unit}` + existing-titles
|
||||
scan per run (retries never duplicate — preserve-first)
|
||||
- `plan` → {2: 239, 3: 251, 4: 129, 5: 544, 6: 415, 7: 274} = 1,852,
|
||||
zero unassigned
|
||||
- `sample --wave 5` → full §7 template holds; `_compute_hash` exactly once as
|
||||
labelled callee with line number
|
||||
- Contract fix during Wave 0: `--limit` default changed 5 → 0 (unlimited) for
|
||||
`create`; `sample` keeps its 5. A full-wave create with the old default
|
||||
would have silently truncated each wave to five issues.
|
||||
|
||||
## 3. Interop proof unit (R1 §5)
|
||||
|
||||
- Rust unit at interop/rebase-proof/ (std-only, zero crates): argv in → JSON
|
||||
on stdout, non-zero exit on failure, mandatory `--version`
|
||||
- Shell-proven: version flag, JSON out, exit 2 on failure, stderr diagnostic
|
||||
- Python thin adapter shared/native_units.py: typed NativeResult, timeout +
|
||||
stderr capture, unit failures as data (never exceptions)
|
||||
- Adapter contract fix during Wave 0: `ok` no longer requires a JSON
|
||||
`ok:true` field — plain-text output (`--version`) succeeds on exit code
|
||||
- tests/test_native_interop_proof.py: **8 passed** — version contract, sum
|
||||
happy path, hash determinism, failure paths, timeout, stderr capture
|
||||
|
||||
## 4. Per-wave issue creation
|
||||
|
||||
<!-- FILLED BY THE COMPLETION LOOP — do not hand-edit -->
|
||||
|
||||
- Wave 4 (129 units): created=127 skipped(dedup)=2 (includes smoke #417–418)
|
||||
- Wave 2 (239 units): created=239 skipped(dedup)=0
|
||||
- Wave 3 (251 units): created=251 skipped(dedup)=0
|
||||
- Wave 5 (544 units): created=544 skipped(dedup)=0
|
||||
- Wave 6 (415 units): created=415 skipped(dedup)=0
|
||||
- Wave 7 (274 units): created=274 skipped(dedup)=0
|
||||
- TOTAL: 1,850 created + 2 dedup = 1,852 / 1,852 ✅ full coverage
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"units_per_wave": {
|
||||
"2": 239,
|
||||
"3": 251,
|
||||
"4": 129,
|
||||
"5": 544,
|
||||
"6": 415,
|
||||
"7": 274
|
||||
},
|
||||
"unassigned_modules": {},
|
||||
"unassigned_module_count": 0
|
||||
}
|
||||
+1
-1
@@ -20,7 +20,7 @@ henxels:
|
||||
- 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"]
|
||||
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/*
|
||||
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "rebase-proof"
|
||||
version = "0.1.0"
|
||||
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "rebase-proof"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# Wave 0 interop proof unit (R1 §5). Std-only by design: no crates, no network,
|
||||
# deterministic build. The pattern under proof is the CLI boundary itself, not the
|
||||
# computation inside it.
|
||||
|
||||
[[bin]]
|
||||
name = "rebase-proof"
|
||||
path = "src/main.rs"
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
@@ -0,0 +1,117 @@
|
||||
//! Wave 0 interop proof unit (R1 §5 of the language-rebasing tranche).
|
||||
//!
|
||||
//! Contract under proof:
|
||||
//! - standalone binary; argv in, JSON on stdout
|
||||
//! - non-zero exit on failure (JSON error object still printed to stdout)
|
||||
//! - `--version` flag mandatory
|
||||
//! - Python wraps it in a thin adapter (`shared/native_units.py`); tests call
|
||||
//! it the same way.
|
||||
//!
|
||||
//! Ops: sum / echo / hash (fnv1a64) / sleep / fail. All std-only.
|
||||
|
||||
use std::env;
|
||||
use std::process::exit;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
/// FNV-1a 64-bit — dependency-free deterministic hash for the proof unit.
|
||||
fn fnv1a64(data: &[u8]) -> u64 {
|
||||
let mut hash: u64 = 0xcbf29ce484222325;
|
||||
for byte in data {
|
||||
hash ^= u64::from(*byte);
|
||||
hash = hash.wrapping_mul(0x100000001b3);
|
||||
}
|
||||
hash
|
||||
}
|
||||
|
||||
fn print_json(line: &str) {
|
||||
println!("{line}");
|
||||
}
|
||||
|
||||
fn emit_ok(body: &str) {
|
||||
print_json(&format!("{{\"ok\":true,{body}}}"));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fn emit_err(message: &str) -> ! {
|
||||
// Escape the minimal set so the JSON stays parseable for arbitrary op names.
|
||||
let escaped: String = message
|
||||
.chars()
|
||||
.map(|c| match c {
|
||||
'"' => "\\\"".to_string(),
|
||||
'\\' => "\\\\".to_string(),
|
||||
'\n' => "\\n".to_string(),
|
||||
'\r' => "\\r".to_string(),
|
||||
'\t' => "\\t".to_string(),
|
||||
other => other.to_string(),
|
||||
})
|
||||
.collect();
|
||||
print_json(&format!("{{\"ok\":false,\"error\":\"{escaped}\"}}"));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().skip(1).collect();
|
||||
|
||||
if args.as_slice() == ["--version"] || args.as_slice() == ["-V"] {
|
||||
println!("rebase-proof {VERSION}");
|
||||
exit(0);
|
||||
}
|
||||
if args.is_empty() {
|
||||
eprintln!("usage: rebase-proof <op> [args...] | --version");
|
||||
emit_err("no op given");
|
||||
}
|
||||
|
||||
let op = args[0].as_str();
|
||||
let rest = &args[1..];
|
||||
|
||||
match op {
|
||||
"sum" => {
|
||||
let mut total: i128 = 0;
|
||||
for a in rest {
|
||||
match a.parse::<i128>() {
|
||||
Ok(v) => total += v,
|
||||
Err(_) => emit_err(&format!("sum: not an integer: {a}")),
|
||||
}
|
||||
}
|
||||
emit_ok(&format!("\"op\":\"sum\",\"result\":{total}"));
|
||||
}
|
||||
"echo" => {
|
||||
let joined = rest.join(" ");
|
||||
let escaped: String = joined
|
||||
.chars()
|
||||
.map(|c| match c {
|
||||
'"' => "\\\"".to_string(),
|
||||
'\\' => "\\\\".to_string(),
|
||||
'\n' => "\\n".to_string(),
|
||||
'\r' => "\\r".to_string(),
|
||||
'\t' => "\\t".to_string(),
|
||||
other => other.to_string(),
|
||||
})
|
||||
.collect();
|
||||
emit_ok(&format!("\"op\":\"echo\",\"text\":\"{escaped}\""));
|
||||
}
|
||||
"hash" => {
|
||||
let joined = rest.join(" ");
|
||||
let h = fnv1a64(joined.as_bytes());
|
||||
emit_ok(&format!("\"op\":\"hash\",\"fnv1a64\":\"{h:016x}\""));
|
||||
}
|
||||
"sleep" => {
|
||||
let ms: u64 = match rest.first().map(|s| s.parse::<u64>()) {
|
||||
Some(Ok(v)) => v,
|
||||
_ => emit_err("sleep: expected milliseconds"),
|
||||
};
|
||||
thread::sleep(Duration::from_millis(ms));
|
||||
emit_ok(&format!("\"op\":\"sleep\",\"slept_ms\":{ms}"));
|
||||
}
|
||||
"fail" => {
|
||||
// Deliberate failure: stderr diagnostic + JSON error + exit 2.
|
||||
// Proves stderr capture and non-zero exit in the adapter.
|
||||
eprintln!("rebase-proof: deliberate failure for adapter proof");
|
||||
emit_err("deliberate failure");
|
||||
}
|
||||
other => emit_err(&format!("unknown op: {other}")),
|
||||
}
|
||||
}
|
||||
@@ -1 +1,401 @@
|
||||
[]
|
||||
[
|
||||
{
|
||||
"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).",
|
||||
"capabilities": [
|
||||
"read_file"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"path exists and is a readable file"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "read_file read a file with optional windowed viewing (offset/limit). returns numbered lines. use offset/limit for large files (100 lines at a time). native tool"
|
||||
},
|
||||
{
|
||||
"name": "edit_file",
|
||||
"description": "Surgical search/replace edit. More reliable than full file rewrites. The search string must match exactly.",
|
||||
"capabilities": [
|
||||
"edit_file"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "write",
|
||||
"preconditions": [
|
||||
"path is inside an allowed write directory",
|
||||
"search string matches exactly once"
|
||||
],
|
||||
"side_effects": [
|
||||
"rewrites the target file atomically after approval",
|
||||
"creates a .bak backup under ~/.rune/undo"
|
||||
],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "edit_file surgical search/replace edit. more reliable than full file rewrites. the search string must match exactly. native tool"
|
||||
},
|
||||
{
|
||||
"name": "write_file",
|
||||
"description": "Write content to a file. Creates parent directories if needed. Shows diff before writing. Use for new files or full rewrites.",
|
||||
"capabilities": [
|
||||
"write_file"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "write",
|
||||
"preconditions": [
|
||||
"path is inside an allowed write directory"
|
||||
],
|
||||
"side_effects": [
|
||||
"writes the full file content atomically after approval",
|
||||
"creates a .bak backup under ~/.rune/undo"
|
||||
],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "write_file write content to a file. creates parent directories if needed. shows diff before writing. use for new files or full rewrites. native tool"
|
||||
},
|
||||
{
|
||||
"name": "glob_files",
|
||||
"description": "Find files matching a glob pattern. Returns file paths sorted by modification time.",
|
||||
"capabilities": [
|
||||
"glob_files"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"search directory is readable"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "glob_files find files matching a glob pattern. returns file paths sorted by modification time. native tool"
|
||||
},
|
||||
{
|
||||
"name": "grep_files",
|
||||
"description": "Search for a pattern in files. Returns file paths and line numbers. Use include to filter by file type.",
|
||||
"capabilities": [
|
||||
"grep_files"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"search directory is readable"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "grep_files search for a pattern in files. returns file paths and line numbers. use include to filter by file type. native tool"
|
||||
},
|
||||
{
|
||||
"name": "list_directory",
|
||||
"description": "List files and directories at a path. Returns names with / suffix for directories.",
|
||||
"capabilities": [
|
||||
"list_directory"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"path is a readable directory"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "list_directory list files and directories at a path. returns names with / suffix for directories. native tool"
|
||||
},
|
||||
{
|
||||
"name": "lint_file",
|
||||
"description": "Lint a file for syntax errors and style issues. Blocks bad edits. Supports Python (ruff), JS/TS (eslint), Go (golangci-lint), and more.",
|
||||
"capabilities": [
|
||||
"lint_file"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"file exists",
|
||||
"a linter is configured for the language"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "lint_file lint a file for syntax errors and style issues. blocks bad edits. supports python (ruff), js/ts (eslint), go (golangci-lint), and more. native tool"
|
||||
},
|
||||
{
|
||||
"name": "run_tests",
|
||||
"description": "Run tests for a file or project. Auto-detects test runner from language.",
|
||||
"capabilities": [
|
||||
"run_tests"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "write",
|
||||
"preconditions": [
|
||||
"a test runner is configured for the project"
|
||||
],
|
||||
"side_effects": [
|
||||
"runs project test commands which may create or delete files"
|
||||
],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "run_tests run tests for a file or project. auto-detects test runner from language. native tool"
|
||||
},
|
||||
{
|
||||
"name": "format_code",
|
||||
"description": "Auto-format code files. Supports Python (black/ruff), JS/TS (prettier), Go (gofmt), and more.",
|
||||
"capabilities": [
|
||||
"format_code"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "write",
|
||||
"preconditions": [
|
||||
"path is inside an allowed write directory",
|
||||
"a formatter is configured for the language"
|
||||
],
|
||||
"side_effects": [
|
||||
"rewrites files in place to the formatter's style"
|
||||
],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "format_code auto-format code files. supports python (black/ruff), js/ts (prettier), go (gofmt), and more. native tool"
|
||||
},
|
||||
{
|
||||
"name": "git_diff",
|
||||
"description": "Show git diff for staged or unstaged changes.",
|
||||
"capabilities": [
|
||||
"git_diff"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"working directory is a git repository"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "git_diff show git diff for staged or unstaged changes. native tool"
|
||||
},
|
||||
{
|
||||
"name": "git_log",
|
||||
"description": "Show recent git commits.",
|
||||
"capabilities": [
|
||||
"git_log"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"working directory is a git repository"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "git_log show recent git commits. native tool"
|
||||
},
|
||||
{
|
||||
"name": "git_commit",
|
||||
"description": "Commit changes with a message. Auto-stages modified files.",
|
||||
"capabilities": [
|
||||
"git_commit"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "irreversible",
|
||||
"preconditions": [
|
||||
"working directory is a git repository",
|
||||
"there are changes to commit"
|
||||
],
|
||||
"side_effects": [
|
||||
"creates a commit on the current branch"
|
||||
],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "git_commit commit changes with a message. auto-stages modified files. native tool"
|
||||
},
|
||||
{
|
||||
"name": "repo_map",
|
||||
"description": "Generate an AST-based codebase map showing key symbols (classes, functions, imports). Uses tree-sitter for 100+ languages.",
|
||||
"capabilities": [
|
||||
"repo_map"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"target directory is readable"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "repo_map generate an ast-based codebase map showing key symbols (classes, functions, imports). uses tree-sitter for 100+ languages. native tool"
|
||||
},
|
||||
{
|
||||
"name": "run_command",
|
||||
"description": "Run an approved command. Prefer argv (shell=False); shell syntax requires shell=true and explicit user approval.",
|
||||
"capabilities": [
|
||||
"run_command"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "irreversible",
|
||||
"preconditions": [
|
||||
"operator approves the command",
|
||||
"required binaries are on PATH"
|
||||
],
|
||||
"side_effects": [
|
||||
"executes arbitrary commands with their full side effects"
|
||||
],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "run_command run an approved command. prefer argv (shell=false); shell syntax requires shell=true and explicit user approval. native tool"
|
||||
},
|
||||
{
|
||||
"name": "read_persona",
|
||||
"description": "Read Rune's persona definition. Returns the full persona block with voice, identity, and rules.",
|
||||
"capabilities": [
|
||||
"read_persona"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"persona MEMORY.md exists"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "read_persona read rune's persona definition. returns the full persona block with voice, identity, and rules. native tool"
|
||||
},
|
||||
{
|
||||
"name": "query_memory",
|
||||
"description": "Query Rune's memory store. Returns relevant memories for a query.",
|
||||
"capabilities": [
|
||||
"query_memory"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"memory store database is available"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "query_memory query rune's memory store. returns relevant memories for a query. native tool"
|
||||
},
|
||||
{
|
||||
"name": "check_growth",
|
||||
"description": "Check Rune's growth log. Returns recent growth entries and patterns.",
|
||||
"capabilities": [
|
||||
"check_growth"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"growth log file exists"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "check_growth check rune's growth log. returns recent growth entries and patterns. native tool"
|
||||
},
|
||||
{
|
||||
"name": "diagnose_behavior",
|
||||
"description": "Diagnose Rune's current behavior. Returns analysis of persona adherence, voice consistency, and drift.",
|
||||
"capabilities": [
|
||||
"diagnose_behavior"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"recent response text provided"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "diagnose_behavior diagnose rune's current behavior. returns analysis of persona adherence, voice consistency, and drift. native tool"
|
||||
},
|
||||
{
|
||||
"name": "find_capability",
|
||||
"description": "Search all installed capabilities for what you need. Returns matching tool names with descriptions and argument schemas. Use this when a capability you need is not in your current tool set; the matched tool becomes callable in the same session.",
|
||||
"capabilities": [
|
||||
"find_capability"
|
||||
],
|
||||
"file": "tool_executor.py",
|
||||
"full_path": "",
|
||||
"priority": 100,
|
||||
"semantic_examples": [],
|
||||
"risk": "read-only",
|
||||
"preconditions": [
|
||||
"a capability query describing the needed outcome"
|
||||
],
|
||||
"side_effects": [],
|
||||
"auto_invoked": false,
|
||||
"hooks": [],
|
||||
"native_tool": true,
|
||||
"searchable_text": "find_capability search all installed capabilities for what you need. returns matching tool names with descriptions and argument schemas. use this when a capability you need is not in your current tool set; the matched tool becomes callable in the same session. native tool"
|
||||
}
|
||||
]
|
||||
+38287
-15
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "rune"
|
||||
version = "0.87.0"
|
||||
version = "0.88.4"
|
||||
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile pyproject.toml -o /tmp/req_new.txt --extra dev --extra memory --python-version 3.11
|
||||
# uv pip compile pyproject.toml -o requirements-ci.txt --extra dev --extra memory --python-version 3.11
|
||||
aiohappyeyeballs==2.7.1
|
||||
# via aiohttp
|
||||
aiohttp==3.14.3
|
||||
@@ -18,9 +18,9 @@ certifi==2026.7.22
|
||||
# httpx
|
||||
chardet==7.6.0
|
||||
# via diff-cover
|
||||
coverage==7.16.1
|
||||
coverage==7.16.2
|
||||
# via rune (pyproject.toml)
|
||||
diff-cover==10.5.1
|
||||
diff-cover==10.6.0
|
||||
# via rune (pyproject.toml)
|
||||
frozenlist==1.8.0
|
||||
# via
|
||||
@@ -56,15 +56,15 @@ mdit-py-plugins==0.6.1
|
||||
# via textual
|
||||
mdurl==0.1.2
|
||||
# via markdown-it-py
|
||||
multidict==6.9.0
|
||||
multidict==6.9.1
|
||||
# via
|
||||
# aiohttp
|
||||
# yarl
|
||||
nodeenv==1.10.0
|
||||
nodeenv==1.11.0
|
||||
# via pyright
|
||||
packaging==26.3
|
||||
# via pytest
|
||||
platformdirs==4.11.11
|
||||
platformdirs==4.12.2
|
||||
# via textual
|
||||
pluggy==1.6.0
|
||||
# via
|
||||
|
||||
+17
-3
@@ -148,9 +148,18 @@ def sha_branch(sha: str) -> str:
|
||||
|
||||
|
||||
def sha_on_master(sha: str) -> bool:
|
||||
out = _git("branch", "--contains", sha)
|
||||
return any(l.strip().endswith("master") or l.strip() == "master"
|
||||
for l in out.splitlines())
|
||||
"""SHA is an ancestor of master (local or remote-tracking refs).
|
||||
|
||||
M10 correction (2026-09-19): --all so a freshly fetched master
|
||||
(refs/remotes/gitea/master) counts; local branches alone go stale
|
||||
between fetches. derive_op_type refreshes refs before calling this.
|
||||
"""
|
||||
out = _git("branch", "--all", "--contains", sha)
|
||||
for l in out.splitlines():
|
||||
s = l.strip().removeprefix("remotes/").removesuffix(" *")
|
||||
if s == "master" or s.endswith("/master"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def open_pr_for_sha(sha: str) -> int | None:
|
||||
@@ -184,6 +193,11 @@ def derive_op_type(sha: str) -> tuple[str, str]:
|
||||
were created from model-supplied defaults and cannot be trusted.
|
||||
Never trusts model input.
|
||||
"""
|
||||
# 0. M10 correction (2026-09-19): refresh remote-tracking refs before
|
||||
# inference. A just-merged master commit is invisible to
|
||||
# branch --contains until refs are fetched; stale local git state
|
||||
# must never outrank repo truth. Bounded by GIT_TIMEOUT, fail-open.
|
||||
_git("fetch", "--quiet", "gitea", "+refs/heads/*:refs/remotes/gitea/*")
|
||||
for rec in _load_wait_records():
|
||||
if _rec_sha(rec) != sha:
|
||||
continue
|
||||
|
||||
@@ -86,9 +86,12 @@ def main() -> int:
|
||||
if live_state == "open" and rec["tracker_state"] == "closed" and rec["reconciliation_state"] in TERMINAL_STATES:
|
||||
drift.append(f"#{num}: live state open but artifact says closed/{rec['reconciliation_state']}")
|
||||
live_bug = "bug" in [l["name"] for l in li.get("labels", [])]
|
||||
if live_bug and not rec.get("live_defect"):
|
||||
# Same open-only exemption as the artifact-records block above: a
|
||||
# closed issue's labels are historical record; FIXED_VERIFIED issues
|
||||
# legitimately keep the bug label after closure.
|
||||
if live_bug and rec.get("tracker_state") == "open" and not rec.get("live_defect"):
|
||||
drift.append(f"#{num}: live bug label present but artifact records no live defect")
|
||||
if not live_bug and rec.get("live_defect"):
|
||||
if not live_bug and rec.get("live_defect") and rec.get("tracker_state") == "open":
|
||||
drift.append(f"#{num}: artifact records live defect but live bug label absent")
|
||||
|
||||
# Live defects in the artifact must all be OPEN in the tracker
|
||||
|
||||
@@ -1,43 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
"""install_mimo_hook.py — T21.2 §21.2D: canonical MiMo hook installer.
|
||||
"""install_mimo_hook.py — T21.2 §21.2D (T22: multi-hook): canonical MiMo
|
||||
hook installer.
|
||||
|
||||
Canonical source: config/mimo-hooks/event-wait-guard.ts
|
||||
Target: ~/.mimocode/hooks/event-wait-guard.ts
|
||||
Verifies hash after install. Detects drift in both directions."""
|
||||
Canonical sources: config/mimo-hooks/*.ts
|
||||
Targets: ~/.mimocode/hooks/<same-name>.ts
|
||||
|
||||
Every hook is hash-verified after install; drift is detected in both
|
||||
directions. T22 added builder-bridge.ts to the managed set — it was
|
||||
previously installed by hand, unversioned, which is how it silently rotted
|
||||
(hardcoded ephemeral interpreter). A hook that reaches the builder must be
|
||||
version-controlled and drift-checked like any other authority.
|
||||
|
||||
Usage:
|
||||
python3 scripts/install_mimo_hook.py # sync all managed hooks
|
||||
python3 scripts/install_mimo_hook.py --check # verify only, install nothing
|
||||
"""
|
||||
import hashlib
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
CANONICAL = Path(__file__).resolve().parent.parent / "config" / "mimo-hooks" / "event-wait-guard.ts"
|
||||
TARGET = Path.home() / ".mimocode" / "hooks" / "event-wait-guard.ts"
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
CANONICAL_DIR = REPO / "config" / "mimo-hooks"
|
||||
TARGET_DIR = Path.home() / ".mimocode" / "hooks"
|
||||
|
||||
# The managed set. Adding a file here is what makes a hook version-controlled.
|
||||
MANAGED = ["event-wait-guard.ts", "builder-bridge.ts"]
|
||||
|
||||
|
||||
def sha256(p: Path) -> str:
|
||||
return hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not CANONICAL.is_file():
|
||||
print(f"canonical source missing: {CANONICAL}")
|
||||
return 1
|
||||
canon_hash = sha256(CANONICAL)
|
||||
if TARGET.is_file():
|
||||
target_hash = sha256(TARGET)
|
||||
if target_hash == canon_hash:
|
||||
print(f"in-sync: {target_hash[:12]}")
|
||||
return 0
|
||||
print(f"DRIFT: canonical={canon_hash[:12]} installed={target_hash[:12]}")
|
||||
def sync_one(name: str, check_only: bool) -> bool:
|
||||
canonical = CANONICAL_DIR / name
|
||||
target = TARGET_DIR / name
|
||||
if not canonical.is_file():
|
||||
print(f"canonical source missing: {canonical}")
|
||||
return False
|
||||
canon_hash = sha256(canonical)
|
||||
if target.is_file() and sha256(target) == canon_hash:
|
||||
print(f"in-sync: {name} {canon_hash[:12]}")
|
||||
return True
|
||||
if check_only:
|
||||
state = "DRIFT" if target.is_file() else "MISSING"
|
||||
inst = sha256(target)[:12] if target.is_file() else "-"
|
||||
print(f"{state}: {name} canonical={canon_hash[:12]} installed={inst}")
|
||||
return False
|
||||
if target.is_file():
|
||||
print(f"DRIFT: {name} canonical={canon_hash[:12]} installed={sha256(target)[:12]}")
|
||||
else:
|
||||
print(f"hook missing at {TARGET}")
|
||||
TARGET.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(CANONICAL, TARGET)
|
||||
installed_hash = sha256(TARGET)
|
||||
if installed_hash != canon_hash:
|
||||
print(f"INSTALL FAILED: hash mismatch after copy")
|
||||
return 1
|
||||
print(f"installed: {installed_hash[:12]}")
|
||||
return 0
|
||||
print(f"hook missing at {target}")
|
||||
TARGET_DIR.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(canonical, target)
|
||||
if sha256(target) != canon_hash:
|
||||
print(f"INSTALL FAILED: {name} hash mismatch after copy")
|
||||
return False
|
||||
print(f"installed: {name} {canon_hash[:12]}")
|
||||
return True
|
||||
|
||||
|
||||
def main() -> int:
|
||||
check_only = "--check" in sys.argv
|
||||
ok = True
|
||||
for name in MANAGED:
|
||||
ok = sync_one(name, check_only) and ok
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
"""install_mimo_tools.py — canonical MiMo tool installer (TTY-repair tranche).
|
||||
|
||||
Canonical sources: config/mimo-tools/{bash.ts,await-operation.ts}
|
||||
Targets: ~/.mimocode/tools/{bash.ts,await-operation.ts}
|
||||
Verifies hashes after install; detects drift in both directions
|
||||
(the parity test reads these hashes).
|
||||
"""
|
||||
import hashlib
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
TOOLS = ["bash.ts", "await-operation.ts"]
|
||||
|
||||
|
||||
def sha256(p: Path) -> str:
|
||||
return hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
rc = 0
|
||||
for name in TOOLS:
|
||||
canon = REPO / "config" / "mimo-tools" / name
|
||||
target = Path.home() / ".mimocode" / "tools" / name
|
||||
if not canon.is_file():
|
||||
print(f"{name}: canonical source missing: {canon}")
|
||||
rc = 1
|
||||
continue
|
||||
canon_hash = sha256(canon)
|
||||
if target.is_file() and sha256(target) == canon_hash:
|
||||
print(f"{name}: in-sync {canon_hash[:12]}")
|
||||
continue
|
||||
drift = f"DRIFT canonical={canon_hash[:12]}"
|
||||
if target.is_file():
|
||||
drift += f" installed={sha256(target)[:12]}"
|
||||
else:
|
||||
drift += " installed=MISSING"
|
||||
print(f"{name}: {drift} — installing")
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(canon, target)
|
||||
if sha256(target) != canon_hash:
|
||||
print(f"{name}: INSTALL FAILED (hash mismatch after copy)")
|
||||
rc = 1
|
||||
else:
|
||||
print(f"{name}: installed {canon_hash[:12]}")
|
||||
return rc
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -42,6 +42,29 @@ def main() -> int:
|
||||
"exit_code": 0 if result == "success" else 1,
|
||||
"completed_at": time.time(),
|
||||
}
|
||||
# R8 lost-event failure-recovery: operation-scoped fault injection.
|
||||
# A rule keyed by the EXACT operation_id suppresses BOTH normal
|
||||
# delivery channels (durable completion file AND bridge POST), so the
|
||||
# waiter's watchdog/failure-detector path is the only route to truth.
|
||||
# Disabled by default (no rule file => zero behavior change) and
|
||||
# observable: every decision is recorded in the R8 fault log.
|
||||
try:
|
||||
import r8_fault # noqa: E402 — sibling module
|
||||
if r8_fault.should_suppress(payload["operation_id"]):
|
||||
r8_fault.record(payload["operation_id"], "suppressed",
|
||||
{"sha": sha, "exit_code": payload["exit_code"],
|
||||
"source_terminal_at": payload["completed_at"]})
|
||||
print("notify-event-bridge: R8 fault injection — completion "
|
||||
f"event intentionally suppressed for "
|
||||
f"{payload['operation_id']} (no .done file, no POST); "
|
||||
"watchdog authority recovery is the expected path",
|
||||
flush=True)
|
||||
return 0
|
||||
r8_fault.record(payload["operation_id"], "delivered_normally",
|
||||
{"sha": sha, "rule_active": False})
|
||||
except Exception as exc: # noqa: BLE001 — fault seam must never break delivery
|
||||
print(f"notify-event-bridge: R8 fault-seam probe failed ({exc}); "
|
||||
"continuing with normal delivery", flush=True)
|
||||
# R3 durable delivery: write the completion file FIRST — it works even
|
||||
# if the bridge daemon is down, and the atomic rename means any waiter
|
||||
# (inotify-watching or starting later) sees a complete file or none.
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""r8_fault.py — REAL_ASYNC_BRIDGE R8: operation-scoped lost-event fault
|
||||
injection (evidence-only harness).
|
||||
|
||||
DESIGN CONTRACT (R8 §3):
|
||||
disabled by default no rule file -> zero behavior change
|
||||
operation-scoped rule keyed by EXACT operation_id
|
||||
reversible delete the rule file / rule entry
|
||||
observable every decision appended to a JSONL log
|
||||
cannot affect other waits rule file checked by operation_id only
|
||||
|
||||
The ONLY consumer is scripts/notify_event_bridge.py: before normal
|
||||
delivery it consults should_suppress(operation_id). Suppression means:
|
||||
- NO durable completion file is written
|
||||
- NO bridge POST (no /process-event wake)
|
||||
- the suppression decision is recorded as R8 fault evidence
|
||||
Nothing else in the stack reads the rule. The daemon, waitstore,
|
||||
authority verification, and completion-file machinery are untouched.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
RUNE_WR_ROOT = os.environ.get("RUNE_WR_ROOT") or os.environ.get("WR_ROOT") or "/mnt/workdrive/wr-bridge"
|
||||
RULES_PATH = Path(RUNE_WR_ROOT) / "r8_suppress_rules.json"
|
||||
FAULT_LOG = Path(RUNE_WR_ROOT) / "r8_fault_log.jsonl"
|
||||
|
||||
REASON = "event intentionally suppressed for R8 lost-event failure-recovery"
|
||||
|
||||
|
||||
def _rules() -> dict:
|
||||
"""Read the rule file. Absent/unreadable => no suppression (fail-open
|
||||
to NORMAL delivery; the fault must never take the healthy path down)."""
|
||||
try:
|
||||
return json.loads(RULES_PATH.read_text())
|
||||
except Exception: # noqa: BLE001 — absent rule file is the default state
|
||||
return {}
|
||||
|
||||
|
||||
def lookup(operation_id: str) -> dict | None:
|
||||
"""Return the active suppression rule for EXACTLY this operation_id,
|
||||
or None. Expired rules are ignored (not deleted — deletion is the
|
||||
operator's explicit disable action)."""
|
||||
spec = _rules()
|
||||
if not spec.get("enabled"):
|
||||
return None
|
||||
rule = spec.get("operations", {}).get(operation_id)
|
||||
if not rule:
|
||||
return None
|
||||
expires = rule.get("expires_at")
|
||||
if expires:
|
||||
try:
|
||||
if time.time() > time.mktime(time.strptime(expires, "%Y-%m-%dT%H:%M:%SZ")) - time.timezone:
|
||||
return None
|
||||
except ValueError:
|
||||
return None
|
||||
return rule
|
||||
|
||||
|
||||
def should_suppress(operation_id: str) -> bool:
|
||||
return lookup(operation_id) is not None
|
||||
|
||||
|
||||
def record(operation_id: str, stage: str, extra: dict | None = None) -> None:
|
||||
"""Append a durable fault-evidence line (best-effort, never raises)."""
|
||||
try:
|
||||
entry = {
|
||||
"at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
||||
"operation_id": operation_id,
|
||||
"reason": REASON,
|
||||
"stage": stage,
|
||||
**(extra or {}),
|
||||
}
|
||||
FAULT_LOG.parent.mkdir(parents=True, exist_ok=True)
|
||||
with FAULT_LOG.open("a") as f:
|
||||
f.write(json.dumps(entry, sort_keys=True) + "\n")
|
||||
except OSError as exc: # noqa: BLE001 — evidence logging must never break CI
|
||||
print(f"r8_fault: evidence log write failed: {exc}", file=sys.stderr)
|
||||
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Tranche R1 Wave 0 — whole-project inventory generator.
|
||||
|
||||
Parses every .py file under src/rune/ with the stdlib AST and emits
|
||||
docs/rebase/rebase-inventory.json: files, classes, functions (with signatures and
|
||||
line ranges), imports, and best-effort caller/callee edges (intra-module call
|
||||
graph + cross-module edges resolved through import tables).
|
||||
|
||||
Deterministic and idempotent: same tree in, same JSON out (sorted keys,
|
||||
sorted files). The issue-factory reads this file; nothing else may edit it.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import json
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
SRC = REPO / "src" / "rune"
|
||||
OUT = REPO / "docs" / "rebase" / "rebase-inventory.json"
|
||||
|
||||
|
||||
def _arg_str(a: ast.arg) -> str:
|
||||
s = a.arg
|
||||
if a.annotation is not None:
|
||||
# Degraded signature (no annotation) is deterministic metadata — never
|
||||
# let one pathological annotation node abort the whole inventory walk.
|
||||
try:
|
||||
s += f": {ast.unparse(a.annotation)}"
|
||||
except (AttributeError, RecursionError, ValueError):
|
||||
pass
|
||||
return s
|
||||
|
||||
|
||||
def _signature(node: ast.FunctionDef | ast.AsyncFunctionDef) -> str:
|
||||
parts = [_arg_str(a) for a in node.args.args]
|
||||
if node.args.vararg:
|
||||
parts.append(f"*{node.args.vararg.arg}")
|
||||
elif node.args.kwonlyargs:
|
||||
parts.append("*")
|
||||
parts += [_arg_str(a) for a in node.args.kwonlyargs]
|
||||
if node.args.kwarg:
|
||||
parts.append(f"**{node.args.kwarg.arg}")
|
||||
ret = ""
|
||||
if node.returns is not None:
|
||||
# Same degraded-metadata contract as _arg_str.
|
||||
try:
|
||||
ret = f" -> {ast.unparse(node.returns)}"
|
||||
except (AttributeError, RecursionError, ValueError):
|
||||
pass
|
||||
return f"({', '.join(parts)}){ret}"
|
||||
|
||||
|
||||
class FileVisitor(ast.NodeVisitor):
|
||||
def __init__(self) -> None:
|
||||
self.functions: list[dict] = []
|
||||
self.classes: list[dict] = []
|
||||
self.imports: list[dict] = []
|
||||
self.calls: list[tuple[int, str]] = [] # (lineno, dotted call name)
|
||||
|
||||
def _fn(self, node, parents: list[str]) -> dict:
|
||||
return {
|
||||
"name": ".".join([*parents, node.name]),
|
||||
"signature": _signature(node),
|
||||
"line_start": node.lineno,
|
||||
"line_end": node.end_lineno or node.lineno,
|
||||
"decorators": [ast.unparse(d) for d in node.decorator_list
|
||||
if isinstance(d, (ast.Name, ast.Attribute, ast.Call))],
|
||||
"async": isinstance(node, ast.AsyncFunctionDef),
|
||||
}
|
||||
|
||||
def visit_ClassDef(self, node: ast.ClassDef) -> None:
|
||||
methods = []
|
||||
for child in node.body:
|
||||
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
methods.append(self._fn(child, [node.name]))
|
||||
self.calls.extend(
|
||||
(n.lineno, ast.unparse(n.func))
|
||||
for n in ast.walk(child)
|
||||
if isinstance(n, ast.Call) and not isinstance(n.func, ast.Name if False else type(None))
|
||||
and isinstance(n.func, (ast.Name, ast.Attribute))
|
||||
)
|
||||
self.classes.append({
|
||||
"name": node.name,
|
||||
"bases": [ast.unparse(b) for b in node.bases],
|
||||
"line_start": node.lineno,
|
||||
"line_end": node.end_lineno or node.lineno,
|
||||
"methods": methods,
|
||||
})
|
||||
# visit only non-function children: methods are already captured above,
|
||||
# and a generic_visit would re-fire visit_FunctionDef on them (duplicate
|
||||
# units + duplicate call edges). Nested classes are still visited.
|
||||
for child in node.body:
|
||||
if not isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
self.visit(child)
|
||||
|
||||
def visit_FunctionDef(self, node) -> None:
|
||||
# top-level only reached here (methods captured in ClassDef)
|
||||
self.functions.append(self._fn(node, []))
|
||||
self.calls.extend(
|
||||
(n.lineno, ast.unparse(n.func))
|
||||
for n in ast.walk(node)
|
||||
if isinstance(n, ast.Call) and isinstance(n.func, (ast.Name, ast.Attribute))
|
||||
)
|
||||
# do not descend into nested defs separately; they are folded into parents
|
||||
# (their calls are already captured by the ast.walk above). No generic_visit:
|
||||
# it would re-collect nested defs as top-level functions and duplicate edges.
|
||||
|
||||
visit_AsyncFunctionDef = visit_FunctionDef
|
||||
|
||||
def visit_Import(self, node: ast.Import) -> None:
|
||||
for a in node.names:
|
||||
self.imports.append({"module": a.name, "as": a.asname, "line": node.lineno})
|
||||
|
||||
def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
|
||||
mod = node.module or ""
|
||||
for a in node.names:
|
||||
self.imports.append({"module": f"{mod}.{a.name}" if a.name != "*" else mod,
|
||||
"as": a.asname or a.name, "line": node.lineno,
|
||||
"from": True})
|
||||
|
||||
|
||||
def collect_file(path: Path) -> dict:
|
||||
src_text = path.read_text(encoding="utf-8", errors="replace")
|
||||
tree = ast.parse(src_text)
|
||||
v = FileVisitor()
|
||||
v.visit(tree)
|
||||
|
||||
# module-level calls (outside defs/classes) — walk tree body directly.
|
||||
# SKIP def/class statements: their bodies are walked by the visit_ methods;
|
||||
# walking them here duplicated every call edge inside every top-level function.
|
||||
for stmt in tree.body:
|
||||
if isinstance(stmt, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
|
||||
continue
|
||||
for n in ast.walk(stmt):
|
||||
if isinstance(n, ast.Call) and isinstance(n.func, (ast.Name, ast.Attribute)):
|
||||
v.calls.append((n.lineno, ast.unparse(n.func)))
|
||||
|
||||
defined = {f["name"].split(".")[-1] for f in v.functions}
|
||||
defined |= {m["name"].split(".")[-1] for c in v.classes for m in c["methods"]}
|
||||
defined |= {c["name"] for c in v.classes}
|
||||
|
||||
callees = []
|
||||
for lineno, call in v.calls:
|
||||
root = call.split(".")[0].split("(")[0].strip()
|
||||
callees.append({"line": lineno, "call": call,
|
||||
"internal": root in defined or root == "self"})
|
||||
|
||||
return {
|
||||
"path": str(path.relative_to(REPO)),
|
||||
"lines": len(src_text.splitlines()),
|
||||
"imports": sorted({i["module"] for i in v.imports}),
|
||||
"import_lines": v.imports,
|
||||
"functions": sorted(v.functions, key=lambda f: (f["line_start"], f["name"])),
|
||||
"classes": sorted(v.classes, key=lambda c: c["line_start"]),
|
||||
"calls": callees,
|
||||
}
|
||||
|
||||
|
||||
def cross_module_edges(files: dict[str, dict]) -> dict[str, set[str]]:
|
||||
"""Resolve import tables: module-stem -> set of imported module stems
|
||||
(rune-internal only), so the factory can attribute cross-module edges."""
|
||||
graph = defaultdict(set)
|
||||
for rel, info in files.items():
|
||||
stem = Path(rel).stem
|
||||
for imp in info["imports"]:
|
||||
top = imp.split(".")[0]
|
||||
second = ".".join(imp.split(".")[:2])
|
||||
if top == "rune":
|
||||
graph[stem].add(imp.replace("rune.", "", 1).split(".")[0])
|
||||
elif not imp.startswith("_") and top not in sys.stdlib_module_names:
|
||||
graph[stem].add(f"ext:{top}")
|
||||
return graph
|
||||
|
||||
|
||||
def main() -> None:
|
||||
py_files = sorted(SRC.rglob("*.py"))
|
||||
files: dict[str, dict] = {}
|
||||
for p in py_files:
|
||||
try:
|
||||
info = collect_file(p)
|
||||
except SyntaxError as e: # a file that cannot parse is a finding, not a skip
|
||||
info = {"path": str(p.relative_to(REPO)), "lines": 0, "imports": [],
|
||||
"import_lines": [], "functions": [], "classes": [], "calls": [],
|
||||
"parse_error": f"{type(e).__name__}: {e}"}
|
||||
files[info["path"]] = info
|
||||
|
||||
graph = cross_module_edges(files)
|
||||
total_fns = sum(len(f["functions"]) + sum(len(c["methods"]) for c in f["classes"])
|
||||
for f in files.values())
|
||||
doc = {
|
||||
"_meta": {
|
||||
"generator": "scripts/rebase_inventory.py",
|
||||
"tranche": "R1 language rebase, Wave 0",
|
||||
"note": "Machine-generated. Regenerate with the script; never hand-edit.",
|
||||
"files": len(files),
|
||||
"functions_total": total_fns,
|
||||
"classes_total": sum(len(f["classes"]) for f in files.values()),
|
||||
"lines_total": sum(f["lines"] for f in files.values()),
|
||||
},
|
||||
"import_graph": {k: sorted(v) for k, v in sorted(graph.items())},
|
||||
"files": dict(sorted(files.items())),
|
||||
}
|
||||
OUT.write_text(json.dumps(doc, indent=1, sort_keys=False) + "\n", encoding="utf-8")
|
||||
m = doc["_meta"]
|
||||
print(f"inventory written: {OUT}")
|
||||
print(f"files={m['files']} functions={m['functions_total']} "
|
||||
f"classes={m['classes_total']} lines={m['lines_total']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,356 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Tranche R1 Wave 0 — per-function issue factory.
|
||||
|
||||
Reads docs/rebase/rebase-inventory.json and emits one issue per unit (top-level
|
||||
function or class method) following tranche R1 §7. Wave-batched, dedup-safe
|
||||
(deterministic title + existing-issue scan before create), rate-limited.
|
||||
|
||||
Modes:
|
||||
plan — coverage report: units per wave, unassigned modules (no silent drops)
|
||||
sample — emit N rendered issues to a file for review (no Gitea call)
|
||||
create — create issues in Gitea for one wave
|
||||
|
||||
Dedup contract: issue titles are deterministic —
|
||||
[rebase w{wave}] {relpath}::{unit}
|
||||
The factory fetches existing issue titles once per run and skips any that
|
||||
already exist, so retries never duplicate (preserve-first Gitea addendum).
|
||||
|
||||
The factory NEVER writes behaviour prose. Current-behaviour paragraphs and
|
||||
the three evidence answers (IMPROVE / FIX / MISSING CONNECTORS) are filled at
|
||||
disposition time by the working agent — the issue carries the mandatory
|
||||
fields and line ranges, not fabricated content.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
INVENTORY = REPO_ROOT / "docs" / "rebase" / "rebase-inventory.json"
|
||||
COVERAGE_OUT = REPO_ROOT / "docs" / "rebase" / "rebase-wave-coverage.json"
|
||||
|
||||
GITEA_URL = os.environ.get("GITEA_URL", "https://gitea.thingscouldgetdicey.online")
|
||||
REPO = "conductor/rune"
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "shared"))
|
||||
from gitea_auth import load_gitea_token # noqa: E402
|
||||
|
||||
TRANCHE_REF = "tranche R1 language rebase (2026-09-29), ~/.config/opencode/tranches/2026-09-29-language-rebase-tranche-R1.md"
|
||||
|
||||
# Wave membership from R1 §4 (initial, measured). Directory entries match by
|
||||
# path prefix; bare stems match the file stem. Modules matching no entry are
|
||||
# reported UNASSIGNED by `plan` — never silently dropped (R1 §9 risk 7).
|
||||
WAVE_PLAN = {
|
||||
2: [ # leaf utilities & canaries
|
||||
"pins", "time_awareness", "message_queue", "event_envelope",
|
||||
"attention_capsule", "complexity_scorer", "token_optimizer", "cache",
|
||||
"prompt_sync", "chat_bubble", "canary_*",
|
||||
],
|
||||
3: [ # memory & persistence
|
||||
"memory_store", "curator", "warm_router", "memory_consolidation",
|
||||
"graph_memory", "sleep_time", "night_mode", "identity_anchors",
|
||||
"query_memory", "memory_env", "warm_neuron_store", "subconscious_pass",
|
||||
"task_persist",
|
||||
],
|
||||
4: [ # provider/model layer
|
||||
"provider_registry", "model_connect", "model_routing", "model_profiles",
|
||||
"provider_budget", "standardized_providers", "model_registry",
|
||||
"connection_pool", "forge_client",
|
||||
],
|
||||
5: [ # orchestration, authority, plugins, skills, governance
|
||||
"orchestration/", "microkernel", "contracts", "build_mode", "plugins/",
|
||||
"skills/", "construction_authority", "construction_authority_cli",
|
||||
"construction_decision", "construction_mode", "verification_construction",
|
||||
"authority_recovery", "spine", "drift_core", "drift_ledger",
|
||||
"drift_observability", "persona_gate", "safety_override", "witness",
|
||||
"behavior", "growth_delta", "claim_audit", "verification_layer",
|
||||
"drift_compression", "drift_cache", "self_improve", "persona_definition",
|
||||
"outcome_ledger", "audit_ledger", "subsystem_health",
|
||||
],
|
||||
6: [ # runtime core & tooling
|
||||
"tool_executor", "tool_protocol", "local_tool_runtime",
|
||||
"capability_broker", "context_broker", "work_manager", "cron_engine",
|
||||
"auto_tasks", "goal", "failure_auto_filer", "hook_engine",
|
||||
"elastic_cognition", "event_bus", "system_registry", "abstraction",
|
||||
"tiered_executor", "progressive_escalation", "tier_manager",
|
||||
"parallel_processor", "shard_manager", "response_adapter",
|
||||
"context_pressure", "auto_context", "cognitive_budgeter",
|
||||
"recall_router", "inference_trace", "task_gate", "salience_gate",
|
||||
"dependency_tracker", "rune_profiler",
|
||||
],
|
||||
7: [ # operator + TUI, last by design
|
||||
"rune_operator", "rune_tui", "tui_validator", "voice_hybrid",
|
||||
"voice_sync", "voicebox", "voice_injector", "message_widgets",
|
||||
"rune_graphic", "rune_spinner", "__main__",
|
||||
],
|
||||
}
|
||||
|
||||
WAVE_NAMES = {
|
||||
2: "leaf utilities & canaries",
|
||||
3: "memory & persistence",
|
||||
4: "provider/model layer",
|
||||
5: "orchestration, authority, plugins, skills, governance",
|
||||
6: "runtime core & tooling",
|
||||
7: "operator + TUI",
|
||||
}
|
||||
|
||||
|
||||
def match_module(relpath: str):
|
||||
"""Return the wave number for a module path, or None if unassigned."""
|
||||
stem = Path(relpath).stem
|
||||
for wave, patterns in WAVE_PLAN.items():
|
||||
for pat in patterns:
|
||||
if pat.endswith("/"):
|
||||
if pat in relpath:
|
||||
return wave
|
||||
elif pat.endswith("*"):
|
||||
if stem.startswith(pat[:-1]):
|
||||
return wave
|
||||
elif stem == pat:
|
||||
return wave
|
||||
return None
|
||||
|
||||
|
||||
def iter_units(inv):
|
||||
"""Yield (relpath, unit_name, entry) for every function and method."""
|
||||
for relpath, mod in sorted(inv["files"].items()):
|
||||
for fn in mod["functions"]:
|
||||
yield relpath, fn["name"], fn
|
||||
for cls in mod["classes"]:
|
||||
for m in cls.get("methods", []):
|
||||
yield relpath, f"{cls['name']}.{m['name']}", m
|
||||
|
||||
|
||||
def internal_edges(relpath: str, entry: dict):
|
||||
"""Collect internal (in-repo) call names and line numbers for a unit."""
|
||||
lines = (entry["line_start"], entry["line_end"])
|
||||
mod = inv_cache["files"][relpath]
|
||||
calls = [c for c in mod.get("calls", [])
|
||||
if lines[0] <= c["line"] <= lines[1] and c.get("internal")]
|
||||
return calls
|
||||
|
||||
|
||||
inv_cache = {}
|
||||
|
||||
|
||||
def issue_title(wave: int, relpath: str, unit: str) -> str:
|
||||
return f"[rebase w{wave}] {relpath}::{unit}"
|
||||
|
||||
|
||||
def render_issue(wave: int, relpath: str, unit: str, entry: dict) -> dict:
|
||||
calls = internal_edges(relpath, entry)
|
||||
call_lines = "\n".join(
|
||||
f" - `{c['call']}` (line {c['line']})" for c in calls[:20]
|
||||
) or " - (no internal call edges in range)"
|
||||
sig = entry.get("signature", "()")
|
||||
body = f"""\
|
||||
|
||||
## Identity (from the Wave 0 inventory — machine-generated)
|
||||
|
||||
- **File**: `{relpath}`
|
||||
- **Unit**: `{unit}`
|
||||
- **Signature**: `def {unit}{sig}` (async: {entry.get('async', False)})
|
||||
- **Line range**: {entry['line_start']}–{entry['line_end']}
|
||||
- **Decorators**: {entry.get('decorators', []) or 'none'}
|
||||
- **Internal call edges** (callers/callees inside the repo, from inventory):
|
||||
{call_lines}
|
||||
|
||||
## Current behaviour
|
||||
|
||||
One honest paragraph from READING THE CODE at the line range above — what it
|
||||
actually does, not what the docstring promises. Write this at disposition
|
||||
time; the factory does not fabricate it.
|
||||
|
||||
## The three questions — each answered WITH EVIDENCE
|
||||
|
||||
1. **IMPROVE?** Can the unit be improved within its scope? Evidence or "no — because …".
|
||||
(Bounded to unit scope; larger findings spawn NEW issues, never expand this one.)
|
||||
2. **FIX?** Is it broken, buggy, or failing its expected outcome? Evidence: a failing
|
||||
test, a reproduced fault, or a code-level defect citation. A "no" needs evidence too.
|
||||
3. **MISSING CONNECTORS?** Are there expected outcomes this unit should connect to but
|
||||
doesn't (unwired events, dead parameters, promised-but-absent calls)? Evidence required.
|
||||
|
||||
A silent skip on any question is a factory bug — answer all three.
|
||||
|
||||
## Language verdict (per tranche R1 §6 rubric — evidence beats instinct)
|
||||
|
||||
Choose exactly one, with the evidence line:
|
||||
- **KEEP-PYTHON** — one sentence of justification.
|
||||
- **RECODE-<lang>** — rubric scores (all 7 dimensions) + benchmark-gate plan: the compiled
|
||||
replacement must beat the Python original on the MEASURED hot path, or the recode is
|
||||
rejected and recorded. No win, no recode.
|
||||
- **MERGE-into:<module>** — name the target and why.
|
||||
- **DEPRECATE** — name the caller that no longer needs it.
|
||||
|
||||
Go is NOT pre-decided. Python is not pre-decided. The rubric decides.
|
||||
|
||||
## Constraint context
|
||||
|
||||
- henxels structural contract: this unit's module ≤ 1,200 lines (or on the debt table's
|
||||
exception list — check before adding lines).
|
||||
- Spine: any module-surface change requires `store/spine/current.json` regen with the code
|
||||
change (`test_manifest_maps_every_module` is the arbiter for new top-level modules).
|
||||
- Debt table: docs/structural-contract.md.
|
||||
|
||||
## Pipeline plan
|
||||
|
||||
1. Branch `issue-<N>` from current master (existing issue-N convention).
|
||||
2. Scaffolding activation for any construction (construction_mode/decision per unit change).
|
||||
3. Research rounds are MANDATORY for any RECODE verdict (research-stage-headless; ≥2
|
||||
live-verified external sources per claim; per-source lessons; kill test per candidate).
|
||||
4. Implementation behind the interop contract (R1 §5): compiled units are standalone
|
||||
binaries — argv in, JSON on stdout, non-zero exit on failure, `--version` mandatory;
|
||||
Python wraps in a thin adapter; store stays the shared truth.
|
||||
5. Local gates: pytest + ruff + spine-store regen (if surface changed) + henxels.
|
||||
6. PR → pipeline-gate + ci + required checks → merge-robot → auto-version.
|
||||
|
||||
## Verification
|
||||
|
||||
- The specific test proving this unit's change: (write at disposition).
|
||||
- The keep-green set it must not break: full suite must stay green; named
|
||||
keep-green tests for this unit's callers.
|
||||
|
||||
## Provenance
|
||||
|
||||
- Tranche: {TRANCHE_REF}
|
||||
- Wave: {wave} ({WAVE_NAMES.get(wave, 'unassigned')})
|
||||
- Inventory: docs/rebase/rebase-inventory.json (regenerate with scripts/rebase_inventory.py — never hand-edit)
|
||||
- Factory: scripts/rebase_issue_factory.py
|
||||
"""
|
||||
return {
|
||||
"title": issue_title(wave, relpath, unit),
|
||||
"body": body,
|
||||
"labels": ["rebase", f"wave-{wave}"],
|
||||
"meta": {
|
||||
"wave": wave,
|
||||
"file": relpath,
|
||||
"unit": unit,
|
||||
"line_start": entry["line_start"],
|
||||
"line_end": entry["line_end"],
|
||||
"async": entry.get("async", False),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def fetch_existing_titles() -> set:
|
||||
"""Fetch all issue titles in the repo (paginated) for dedup."""
|
||||
token = load_gitea_token()
|
||||
titles = set()
|
||||
page = 1
|
||||
while True:
|
||||
url = (f"{GITEA_URL}/api/v1/repos/{REPO}/issues"
|
||||
f"?state=all&type=issues&limit=50&page={page}")
|
||||
req = urllib.request.Request(url, headers={"Authorization": f"token {token}"})
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
batch = json.loads(resp.read())
|
||||
if not batch:
|
||||
break
|
||||
titles.update(i["title"] for i in batch)
|
||||
if len(batch) < 50:
|
||||
break
|
||||
page += 1
|
||||
return titles
|
||||
|
||||
|
||||
def create_issue(entry: dict) -> dict:
|
||||
token = load_gitea_token()
|
||||
url = f"{GITEA_URL}/api/v1/repos/{REPO}/issues"
|
||||
payload = json.dumps({
|
||||
"title": entry["title"],
|
||||
"body": entry["body"],
|
||||
"labels": [], # label NAMES are set via the labels endpoint by auto-label; keep create minimal
|
||||
}).encode()
|
||||
req = urllib.request.Request(url, data=payload, method="POST",
|
||||
headers={"Authorization": f"token {token}",
|
||||
"Content-Type": "application/json"})
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
return json.loads(resp.read())
|
||||
|
||||
|
||||
def cmd_plan(inv):
|
||||
counts = {}
|
||||
unassigned_modules = {}
|
||||
for relpath, unit, entry in iter_units(inv):
|
||||
wave = match_module(relpath)
|
||||
counts[wave] = counts.get(wave, 0) + 1
|
||||
if wave is None:
|
||||
unassigned_modules.setdefault(relpath, inv["files"][relpath]["lines"])
|
||||
report = {
|
||||
"units_per_wave": {str(k if k is not None else "UNASSIGNED"): v
|
||||
for k, v in sorted(counts.items(), key=lambda kv: str(kv[0]))},
|
||||
"unassigned_modules": dict(sorted(unassigned_modules.items(), key=lambda kv: -kv[1])),
|
||||
"unassigned_module_count": len(unassigned_modules),
|
||||
}
|
||||
print(json.dumps(report, indent=1))
|
||||
COVERAGE_OUT.write_text(json.dumps(report, indent=1) + "\n")
|
||||
print(f"\ncoverage written to {COVERAGE_OUT.relative_to(REPO_ROOT)}", file=sys.stderr)
|
||||
return 0 if not unassigned_modules else 1
|
||||
|
||||
|
||||
def cmd_sample(inv, wave, limit, out):
|
||||
emitted = 0
|
||||
records = []
|
||||
for relpath, unit, entry in iter_units(inv):
|
||||
if match_module(relpath) != wave:
|
||||
continue
|
||||
records.append(render_issue(wave, relpath, unit, entry))
|
||||
emitted += 1
|
||||
if emitted >= limit:
|
||||
break
|
||||
Path(out).write_text("\n".join(json.dumps(r) for r in records) + "\n")
|
||||
print(f"sampled {emitted} issues for wave {wave} -> {out}", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_create(inv, wave, limit, dry_gap):
|
||||
existing = fetch_existing_titles()
|
||||
created, skipped = 0, 0
|
||||
for relpath, unit, entry in iter_units(inv):
|
||||
if match_module(relpath) != wave:
|
||||
continue
|
||||
title = issue_title(wave, relpath, unit)
|
||||
if title in existing:
|
||||
skipped += 1
|
||||
continue
|
||||
issue = create_issue(render_issue(wave, relpath, unit, entry))
|
||||
created += 1
|
||||
print(f"created #{issue.get('number')}: {title}", file=sys.stderr)
|
||||
if limit and created >= limit:
|
||||
break
|
||||
time.sleep(dry_gap)
|
||||
print(f"\nwave {wave}: created={created} skipped(dedup)={skipped}", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("command", choices=["plan", "sample", "create"])
|
||||
ap.add_argument("--wave", type=int, help="wave number (2-7)")
|
||||
ap.add_argument("--limit", type=int, default=0, help="max issues for sample/create (0 = unlimited; sample defaults to 5)")
|
||||
ap.add_argument("--out", default=None, help="sample output file")
|
||||
ap.add_argument("--gap", type=float, default=0.5, help="seconds between creates")
|
||||
args = ap.parse_args()
|
||||
|
||||
inv_cache.update(json.loads(INVENTORY.read_text()))
|
||||
inv = inv_cache
|
||||
|
||||
if args.command == "plan":
|
||||
return cmd_plan(inv)
|
||||
if args.command == "sample":
|
||||
if not args.wave:
|
||||
ap.error("--wave required")
|
||||
out = args.out or f"docs/rebase-factory-sample-w{args.wave}.json"
|
||||
return cmd_sample(inv, args.wave, args.limit or 5, out)
|
||||
if args.command == "create":
|
||||
if not args.wave:
|
||||
ap.error("--wave required")
|
||||
return cmd_create(inv, args.wave, args.limit, args.gap)
|
||||
return 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+88
-12
@@ -33,7 +33,7 @@ SCRIPTS_DIR = os.path.expanduser("~/.config/opencode/scripts")
|
||||
SHARED_DIR = os.path.expanduser("~/.config/opencode/shared")
|
||||
CUSTODIAN_STATE_FILE = os.path.expanduser("~/.config/opencode/memory/custodian_state.json")
|
||||
|
||||
GITEA_URL = os.environ.get("GITEA_URL", "https://gitea.thingscouldgetdicey.online")
|
||||
GITEA_URL = os.environ.get("GITEA_URL", "http://127.0.0.1:3000") # gitea.internal (PC); external = https://gitea.thingscouldgetdicey.online via Pi Caddy
|
||||
GITEA_TOKEN = load_gitea_token()
|
||||
REPO = "conductor/rune"
|
||||
TUI_DIR = "/mnt/workdrive/rune"
|
||||
@@ -54,6 +54,15 @@ UMBRELLA_TAGS = {
|
||||
}
|
||||
|
||||
|
||||
# Issue template directory — canonical copies live beside this script
|
||||
# (mirrored to .gitea/ISSUE_TEMPLATE/ for the web-UI submission path).
|
||||
ISSUE_TEMPLATE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "issue_templates")
|
||||
|
||||
# kind -> Gitea label that MUST be present on the issue
|
||||
KIND_LABEL = {"feature": "feature", "bug": "bug", "research": "research"}
|
||||
VERSION_INTENTS = ("major", "minor", "patch", "none")
|
||||
|
||||
|
||||
class Custodian:
|
||||
"""The Custodian agent for Gitea-based self-improvement."""
|
||||
|
||||
@@ -105,23 +114,90 @@ class Custodian:
|
||||
except Exception as e:
|
||||
return {"error": str(e)[:200]}
|
||||
|
||||
def create_issue(self, title: str, body: str, labels: List[str] = None) -> dict:
|
||||
"""Create a Gitea issue with plain-language description.
|
||||
def _ensure_label(self, name: str, description: str = "", color: str = "#6f42c1") -> bool:
|
||||
"""Make sure a label exists on the repo; return its id or None."""
|
||||
labels = self._gitea_api("labels")
|
||||
if isinstance(labels, list):
|
||||
for l in labels:
|
||||
if l["name"] == name:
|
||||
return l["id"]
|
||||
data = {"name": name, "description": description or name, "color": color}
|
||||
created = self._gitea_api("labels", method="POST", data=data)
|
||||
return created.get("id") if isinstance(created, dict) else None
|
||||
|
||||
Labels should be umbrella names (memory, governance, etc).
|
||||
They get converted to IDs automatically.
|
||||
def _load_issue_template(self, kind: str) -> str:
|
||||
"""Load the canonical issue template for a kind, WITHOUT the web-UI
|
||||
frontmatter (name/about/title/labels — that metadata belongs to the
|
||||
submission form, not the issue body). Empty string if absent."""
|
||||
path = os.path.join(ISSUE_TEMPLATE_DIR, f"{kind}.md")
|
||||
try:
|
||||
with open(path) as f:
|
||||
text = f.read()
|
||||
except FileNotFoundError:
|
||||
return ""
|
||||
if text.startswith("---"):
|
||||
end = text.find("\n---", 3)
|
||||
if end != -1:
|
||||
text = text[end + 4:]
|
||||
return text.lstrip("\n")
|
||||
|
||||
def create_issue(
|
||||
self,
|
||||
title: str,
|
||||
body: str,
|
||||
labels: List[str] = None,
|
||||
kind: str = "feature",
|
||||
version_intent: Optional[str] = None,
|
||||
) -> dict:
|
||||
"""Create a Gitea issue assembled from the canonical template.
|
||||
|
||||
kind: feature | bug | research — selects the template and forces the
|
||||
matching label (the research label is auto-created if missing).
|
||||
version_intent: major | minor | patch | none — pre-ticks the matching
|
||||
box in the template's Version impact section. The pipeline
|
||||
verifies the real bump at merge and flags mismatches.
|
||||
labels: umbrella names (memory, governance, ...); converted to IDs.
|
||||
|
||||
The caller's body replaces the SUBMITTED_BODY marker inside the
|
||||
template's Plain English section — plain terms first, always.
|
||||
|
||||
ORGANISATION STANDARD (one open note per idea, 2026-09-19): before
|
||||
minting a standalone issue, check whether the work belongs inside an
|
||||
existing parent. Ideas parked under a blocked/future epic are filed
|
||||
as checklist items in the parent's "Absorbed children" section, NOT
|
||||
as standalone issues — the board stays uncluttered and every idea
|
||||
has exactly one home. Mint a standalone issue only when the work is
|
||||
live, dependency-tracked, or about to start. Absorbed ideas are
|
||||
reversible: re-mint standalone when they become live.
|
||||
"""
|
||||
# Convert label names to IDs
|
||||
# 1. assemble body from template (graceful: unformatted if template missing)
|
||||
template = self._load_issue_template(kind)
|
||||
text = body.strip()
|
||||
if template and "<!-- SUBMITTED_BODY -->" in template:
|
||||
text = template.replace("<!-- SUBMITTED_BODY -->", text, 1)
|
||||
if version_intent in VERSION_INTENTS:
|
||||
text = text.replace(f"- [ ] {version_intent} ", f"- [x] {version_intent} ", 1)
|
||||
|
||||
# 2. labels: umbrella names + mandatory kind label
|
||||
labels = list(labels or [])
|
||||
kind_label = KIND_LABEL.get(kind)
|
||||
if kind_label and kind_label not in labels:
|
||||
labels.append(kind_label)
|
||||
|
||||
all_labels = self._gitea_api("labels")
|
||||
label_map = {l["name"]: l["id"] for l in all_labels} if isinstance(all_labels, list) else {}
|
||||
label_ids = []
|
||||
if labels:
|
||||
all_labels = self._gitea_api("labels")
|
||||
if isinstance(all_labels, list):
|
||||
label_map = {l["name"]: l["id"] for l in all_labels}
|
||||
label_ids = [label_map[l] for l in labels if l in label_map]
|
||||
for l in labels:
|
||||
if l in label_map:
|
||||
label_ids.append(label_map[l])
|
||||
else:
|
||||
lid = self._ensure_label(l)
|
||||
if lid:
|
||||
label_ids.append(lid)
|
||||
|
||||
data = {
|
||||
"title": title,
|
||||
"body": body,
|
||||
"body": text,
|
||||
"labels": label_ids,
|
||||
}
|
||||
result = self._gitea_api("issues", method="POST", data=data)
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
name: Bug Fix
|
||||
about: Demonstrate currently incorrect behaviour — plain English first, proof required
|
||||
title: "[BUG] "
|
||||
labels: bug
|
||||
assignees: conductor
|
||||
---
|
||||
|
||||
<restate the issue title here in everyday words — this heading IS the
|
||||
plain-English summary; no meta-labels like "plain English" in it>
|
||||
<!-- The heading above carries the summary itself — a scan of issue
|
||||
headings alone should tell the whole story of the board. TOP PRIORITY:
|
||||
if a technical detail below contradicts this section, the issue is
|
||||
buggy — fix the issue. -->
|
||||
<!-- SUBMITTED_BODY -->
|
||||
|
||||
|
||||
What is broken: <what a person observes going wrong>
|
||||
|
||||
What should happen instead: <the correct behaviour>
|
||||
|
||||
How often / when: <always | after X | since change Y>
|
||||
|
||||
## Proof it is broken (required — no proof, no bug)
|
||||
<!-- A bug is DEMONSTRATED currently incorrect behaviour. Nothing else.
|
||||
If this section cannot be filled, file it as a question, not a bug. -->
|
||||
- [ ] Reproduction command or steps (deterministic where possible)
|
||||
- [ ] The exact wrong output observed: <paste/log excerpt>
|
||||
- [ ] Where the evidence lives: <log path, fixture, session id>
|
||||
|
||||
## Steps to reproduce
|
||||
<!-- How to trigger the bug -->
|
||||
|
||||
## What would let us close this
|
||||
- [ ] The reproduction command now shows correct behaviour
|
||||
- [ ] A regression test exists that fails before the fix and passes after
|
||||
- [ ] No other behaviour changed (or changes are listed and justified)
|
||||
|
||||
## Version impact (declared at submission — verified at merge)
|
||||
<!-- A bug fix is USUALLY a patch. Pick major or minor only with a reason. -->
|
||||
- [ ] patch — same behaviour, done correctly (usual for bugs)
|
||||
- [ ] major — the bug was in a published contract and fixing it breaks consumers (justify)
|
||||
- [ ] minor — fixing revealed a missing capability that had to be added (justify)
|
||||
|
||||
## Technical details
|
||||
<!-- WHAT (the bug) / WHERE (files) / EVIDENCE (how it was confirmed). -->
|
||||
|
||||
**WHAT (bug):**
|
||||
**WHERE:**
|
||||
**EVIDENCE:**
|
||||
|
||||
## Pipeline requirements
|
||||
<!-- Every fix must clear these before the issue closes. -->
|
||||
- [ ] TDD: regression test written first, red → green
|
||||
- [ ] `ruff check` and `ruff format --check` clean
|
||||
- [ ] Spec-compliance review gate: PASS
|
||||
- [ ] Code-quality review gate: Approved
|
||||
- [ ] Full orchestration suite regression green (suite total)
|
||||
- [ ] Canary passes (name)
|
||||
- [ ] Closed with a properly formatted closing comment + commit references
|
||||
|
||||
## Cognitive invariants (memory/cognition issues — both handoffs)
|
||||
<!-- Complete ONLY if this issue touches memory, learning, or self-model state. -->
|
||||
- [ ] **Owner** — which existing subsystem owns this (audit before creating modules)
|
||||
- [ ] **Trigger** — what event activates it
|
||||
- [ ] **Read/write authority** — which canonical state it reads/changes
|
||||
- [ ] **Provenance** — derived state traceable to evidence
|
||||
- [ ] **Verification** — how we know the change helped
|
||||
- [ ] **Failure visibility** — how failure surfaces
|
||||
- [ ] **Reversibility** — bad learned state can be superseded/replayed/rolled back
|
||||
- [ ] **Dormant cost** — what it costs when irrelevant
|
||||
- [ ] **Benchmark + ablation** — what measurable behaviour improves; what happens when disabled
|
||||
- [ ] **No duplicate authority** — why extend vs create
|
||||
|
||||
Hard invariants: derived cognition preserves evidentiary ancestry · epistemic confidence ≠ attentional utility ≠ current applicability · retrieval never increases utility · self-model-induced behaviour is not independent evidence · historical truth survives present-state change · raw evidence is never destroyed by promotion.
|
||||
|
||||
## Related umbrella
|
||||
- [ ] Memory
|
||||
- [ ] Governance
|
||||
- [ ] Identity
|
||||
- [ ] Growth
|
||||
- [ ] Perception
|
||||
- [ ] Infrastructure
|
||||
- [ ] Orchestration
|
||||
|
||||
## Priority (REQUIRED — the priority gate)
|
||||
<!-- Pick exactly one. An issue without a priority is not filed. -->
|
||||
- [ ] **P0 — critical** — breaks the spine / core correctness, or blocks other work
|
||||
- [ ] **P1 — high** — material user value or a real defect (money, correctness bugs, next-stage dependency)
|
||||
- [ ] **P2 — medium** — quality/consolidation improvement (check the fold-into mapping first)
|
||||
- [ ] **P3 — low** — measurement / benchmark / deferred policy
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: New feature or improvement — plain English first, verifiable close conditions, version intent
|
||||
title: "[FEATURE] "
|
||||
labels: feature
|
||||
assignees: conductor
|
||||
---
|
||||
|
||||
<restate the issue title here in everyday words — this heading IS the
|
||||
plain-English summary; no meta-labels like "plain English" in it>
|
||||
<!-- The heading above carries the summary itself — a scan of issue
|
||||
headings alone should tell the whole story of the board. TOP PRIORITY:
|
||||
if a technical detail below contradicts this section, the issue is
|
||||
buggy — fix the issue. A non-technical reader must be able to retell this
|
||||
section. 3-6 sentences, no jargon. -->
|
||||
<!-- SUBMITTED_BODY -->
|
||||
|
||||
|
||||
What is this about: <what>
|
||||
|
||||
Why do we need it: <the itch — what happens today that shouldn't, or what becomes possible>
|
||||
|
||||
Why is it still open: <"not started yet" | "part done, X remains" | "deliberately parked as a future idea">
|
||||
|
||||
## Example
|
||||
<!-- A concrete before/after in plain terms: "If X happens, the system will Y instead of Z." -->
|
||||
|
||||
## What would let us close this
|
||||
<!-- Checkable statements, verifiable by looking at something that EXISTS —
|
||||
a file, a log line, a passing test. Not "when appropriate". -->
|
||||
- [ ] <condition 1 — observable>
|
||||
- [ ] <condition 2>
|
||||
|
||||
## Version impact (declared at submission — verified at merge)
|
||||
<!-- The pipeline derives the real bump from merged conventional commits and
|
||||
compares against this declaration. A mismatch is flagged, not fatal:
|
||||
either the declaration was wrong or the work grew. Both facts matter. -->
|
||||
- [ ] major — breaking: changes a contract, schema, or interface others depend on
|
||||
- [ ] minor — new capability: something becomes possible that wasn't
|
||||
- [ ] patch — repair: same behaviour, done correctly
|
||||
- [ ] none — touches no released artifact (docs, memory, process notes)
|
||||
|
||||
## Technical details
|
||||
<!-- WHAT — one-line objective.
|
||||
WHY — design-spec reference (S#) or reason.
|
||||
FILES — affected components.
|
||||
ACCEPTANCE — frozen-test file + test count + canary name.
|
||||
DEPENDENCIES — parent epic + preceding stage/plan refs. -->
|
||||
|
||||
**WHAT:**
|
||||
**WHY:**
|
||||
**FILES:**
|
||||
**ACCEPTANCE:**
|
||||
**DEPENDENCIES:**
|
||||
|
||||
## Pipeline requirements
|
||||
<!-- Every stage must clear these before the issue closes. -->
|
||||
- [ ] TDD: frozen tests written first, red → green (N passed)
|
||||
- [ ] `ruff check` and `ruff format --check` clean
|
||||
- [ ] Spec-compliance review gate: PASS
|
||||
- [ ] Code-quality review gate: Approved
|
||||
- [ ] Full orchestration suite regression green (suite total)
|
||||
- [ ] Canary passes (name)
|
||||
- [ ] Closed with a properly formatted closing comment + commit/PR references
|
||||
|
||||
## Cognitive invariants (memory/cognition issues — both handoffs)
|
||||
<!-- Complete ONLY if this issue touches memory, learning, or self-model state. -->
|
||||
- [ ] **Owner** — which existing subsystem owns this (audit before creating modules)
|
||||
- [ ] **Trigger** — what event activates it
|
||||
- [ ] **Read/write authority** — which canonical state it reads/changes
|
||||
- [ ] **Provenance** — derived state traceable to evidence
|
||||
- [ ] **Verification** — how we know the change helped
|
||||
- [ ] **Failure visibility** — how failure surfaces
|
||||
- [ ] **Reversibility** — bad learned state can be superseded/replayed/rolled back
|
||||
- [ ] **Dormant cost** — what it costs when irrelevant
|
||||
- [ ] **Benchmark + ablation** — what measurable behaviour improves; what happens when disabled
|
||||
- [ ] **No duplicate authority** — why extend vs create
|
||||
|
||||
Hard invariants: derived cognition preserves evidentiary ancestry · epistemic confidence ≠ attentional utility ≠ current applicability · retrieval never increases utility · self-model-induced behaviour is not independent evidence · historical truth survives present-state change · raw evidence is never destroyed by promotion.
|
||||
|
||||
## Related umbrella
|
||||
- [ ] Memory
|
||||
- [ ] Governance
|
||||
- [ ] Identity
|
||||
- [ ] Growth
|
||||
- [ ] Perception
|
||||
- [ ] Infrastructure
|
||||
- [ ] Life (Nick's)
|
||||
- [ ] Custodian
|
||||
- [ ] Orchestration
|
||||
|
||||
## Priority (REQUIRED — the priority gate)
|
||||
<!-- Pick exactly one. An issue without a priority is not filed. -->
|
||||
- [ ] **P0 — critical** — breaks the spine / core correctness, or blocks other work
|
||||
- [ ] **P1 — high** — material user value or a real defect (money, correctness bugs, next-stage dependency)
|
||||
- [ ] **P2 — medium** — quality/consolidation improvement (check the fold-into mapping first)
|
||||
- [ ] **P3 — low** — measurement / benchmark / deferred policy
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
name: Research Submission
|
||||
about: Buy down uncertainty before building — question, falsifier, budget, durable findings
|
||||
title: "[RESEARCH] "
|
||||
labels: research
|
||||
assignees: conductor
|
||||
---
|
||||
|
||||
<restate the issue title here in everyday words — this heading IS the
|
||||
plain-English summary; no meta-labels like "plain English" in it>
|
||||
<!-- The heading above carries the summary itself — a scan of issue
|
||||
headings alone should tell the whole story of the board. TOP PRIORITY:
|
||||
if a technical detail below contradicts this section, the issue is
|
||||
buggy — fix the issue. -->
|
||||
<!-- SUBMITTED_BODY -->
|
||||
|
||||
|
||||
The question: <what we're trying to learn, one sentence>
|
||||
|
||||
Why we're asking: <what decision this research will inform — a name, an issue
|
||||
number, or "exploratory: none yet">
|
||||
|
||||
What we believe today: <the current assumption, stated so it can be proven wrong>
|
||||
|
||||
## The shape of an answer
|
||||
- [ ] What evidence would settle the question: <observation, benchmark, or spike>
|
||||
- [ ] What evidence would KILL the current assumption (the falsifier): <be specific —
|
||||
this is stated BEFORE starting so the research cannot become a search for confirmation>
|
||||
- [ ] Budget: <time/effort cap — when research must stop and report back>
|
||||
|
||||
## What would let us close this
|
||||
- [ ] Findings written to a durable document: <path, e.g. research/issue-NNN/> —
|
||||
a comment thread is not a durable finding
|
||||
- [ ] The decision the research informs is recorded: made / deferred / changed
|
||||
- [ ] If a follow-up build issue was minted: <#N or "none needed">
|
||||
|
||||
## Version impact (declared at submission — verified at merge)
|
||||
- [ ] none — research changes no released artifact (usual)
|
||||
- [ ] minor/major — only if a code spike is being merged as part of this (justify)
|
||||
|
||||
## Technical detail
|
||||
<!-- Candidate approaches, prior art in the repo, related issues, constraints,
|
||||
rebuildable-projection or authority requirements if findings touch canonical state. -->
|
||||
|
||||
## Pipeline requirements
|
||||
- [ ] Findings committed under the stated durable path
|
||||
- [ ] Every citation verified against a real source (no fabricated references)
|
||||
- [ ] Closed with a properly formatted closing comment: findings summary + decision
|
||||
|
||||
## Cognitive invariants (memory/cognition research — both handoffs)
|
||||
<!-- Complete ONLY if findings touch memory, learning, or self-model state. -->
|
||||
- [ ] **Owner** — which existing subsystem owns this (audit before proposing modules)
|
||||
- [ ] **Read/write authority** — which canonical state is affected
|
||||
- [ ] **Provenance** — findings traceable to evidence
|
||||
- [ ] **Reversibility** — projections remain rebuildable; no unique truth moves into a derived index
|
||||
- [ ] **No duplicate authority** — why extend vs create
|
||||
|
||||
Hard invariants: derived cognition preserves evidentiary ancestry · retrieval never increases utility · raw evidence is never destroyed by promotion.
|
||||
|
||||
## Related umbrella
|
||||
- [ ] Memory
|
||||
- [ ] Governance
|
||||
- [ ] Identity
|
||||
- [ ] Growth
|
||||
- [ ] Perception
|
||||
- [ ] Infrastructure
|
||||
- [ ] Life (Nick's)
|
||||
- [ ] Custodian
|
||||
- [ ] Orchestration
|
||||
|
||||
## Priority (REQUIRED — the priority gate)
|
||||
<!-- Pick exactly one. An issue without a priority is not filed. -->
|
||||
- [ ] **P0 — critical** — blocks a decision that blocks other work
|
||||
- [ ] **P1 — high** — informs a next-stage dependency
|
||||
- [ ] **P2 — medium** — quality/consolidation understanding
|
||||
- [ ] **P3 — low** — watchlist / deferred / exploratory
|
||||
@@ -0,0 +1,216 @@
|
||||
"""Thin adapter for native (compiled) units — R1 §5 interop contract, Wave 0.
|
||||
|
||||
The contract under proof: compiled units are standalone binaries exposing a
|
||||
CLI boundary — argv in, JSON on stdout, non-zero exit on failure, a mandatory
|
||||
``--version`` flag. This module is the Python side: run a unit, enforce a
|
||||
timeout, capture stderr, and return a TYPED result. It never raises for unit
|
||||
failures (those are data in the result); it raises only for adapter misuse
|
||||
(missing binary, bad timeout).
|
||||
|
||||
No IPC daemon, no PyO3 — the file-based store stays the shared truth. If
|
||||
research later surfaces a materially better pattern it competes through the
|
||||
research pipeline; the CLI boundary is the default, not a cage.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
PROOF_UNIT = REPO_ROOT / "interop" / "rebase-proof" / "target" / "release" / "rebase-proof"
|
||||
|
||||
|
||||
@dataclass
|
||||
class NativeResult:
|
||||
"""Typed result of one native-unit invocation.
|
||||
|
||||
ok — the invocation succeeded (exit 0 AND not timed out); when
|
||||
the unit emitted JSON with an ``ok`` field, that field must
|
||||
not be False (plain-text output like ``--version`` has none)
|
||||
exit_code — raw process exit code
|
||||
data — parsed JSON object from stdout, or None if unparseable
|
||||
stderr — captured stderr text (may be non-empty even on success)
|
||||
duration_ms — wall-clock cost of the invocation
|
||||
timed_out — True when the unit exceeded the timeout and was killed
|
||||
events — in streaming mode: every parsed JSON object line, in
|
||||
arrival order (empty for non-streaming :func:`run_native`)
|
||||
"""
|
||||
|
||||
ok: bool
|
||||
exit_code: int
|
||||
data: dict | None
|
||||
stderr: str
|
||||
duration_ms: int
|
||||
timed_out: bool = False
|
||||
raw_stdout: str = field(default="", repr=False)
|
||||
events: list[dict] = field(default_factory=list)
|
||||
|
||||
|
||||
def run_native(binary: Path, args: list[str], timeout_s: float = 10.0) -> NativeResult:
|
||||
"""Invoke a native unit and return a typed result.
|
||||
|
||||
Raises FileNotFoundError only when *binary* itself is absent (adapter
|
||||
misuse) — every unit-level failure is reported via the result, never an
|
||||
exception, so callers can branch on ``result.ok`` without try/except.
|
||||
"""
|
||||
if not binary.is_file():
|
||||
raise FileNotFoundError(f"native unit not built: {binary}")
|
||||
|
||||
started = time.monotonic()
|
||||
timed_out = False
|
||||
try:
|
||||
proc = subprocess.run(
|
||||
[str(binary), *args],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=timeout_s,
|
||||
check=False, # exit codes are data, never exceptions
|
||||
)
|
||||
exit_code, stdout, stderr = proc.returncode, proc.stdout, proc.stderr
|
||||
except subprocess.TimeoutExpired as exc:
|
||||
timed_out = True
|
||||
exit_code = -1
|
||||
stdout = exc.stdout or "" if isinstance(exc.stdout, str) else (exc.stdout or b"").decode(errors="replace")
|
||||
stderr = exc.stderr or "" if isinstance(exc.stderr, str) else (exc.stderr or b"").decode(errors="replace")
|
||||
|
||||
duration_ms = int((time.monotonic() - started) * 1000)
|
||||
|
||||
data: dict | None = None
|
||||
stripped = stdout.strip()
|
||||
if stripped:
|
||||
try:
|
||||
parsed = json.loads(stripped.splitlines()[-1])
|
||||
if isinstance(parsed, dict):
|
||||
data = parsed
|
||||
except json.JSONDecodeError:
|
||||
data = None
|
||||
|
||||
ok = (not timed_out) and exit_code == 0 and (data is None or data.get("ok") is not False)
|
||||
return NativeResult(
|
||||
ok=ok,
|
||||
exit_code=exit_code,
|
||||
data=data,
|
||||
stderr=stderr,
|
||||
duration_ms=duration_ms,
|
||||
timed_out=timed_out,
|
||||
raw_stdout=stdout,
|
||||
)
|
||||
|
||||
|
||||
def run_proof(args: list[str], timeout_s: float = 10.0) -> NativeResult:
|
||||
"""Run the Wave 0 proof unit with the standard contract defaults."""
|
||||
return run_native(PROOF_UNIT, args, timeout_s=timeout_s)
|
||||
|
||||
|
||||
def stream_native(
|
||||
binary: Path,
|
||||
args: list[str],
|
||||
timeout_s: float = 10.0,
|
||||
on_event=None,
|
||||
):
|
||||
"""Run a native unit in JSONL streaming mode, yielding events as they arrive.
|
||||
|
||||
The JSONL streaming contract (rubric §W7): one JSON object per stdout
|
||||
line — ``{"ok": true, "event": ...}`` progress objects along the way, and
|
||||
a terminal envelope as the FINAL line. This generator yields each parsed
|
||||
event dict the moment it arrives (so a long op surfaces partial progress
|
||||
instead of blocking until exit), then yields exactly one terminal
|
||||
:class:`NativeResult`. *on_event*, when given, is called with each parsed
|
||||
event as it arrives (the TUI wraps this in ``call_from_thread``).
|
||||
|
||||
Stream-mode ok-semantics are stricter than :func:`run_native`: ``ok``
|
||||
requires exit 0, no timeout, AND a valid terminal envelope (the final
|
||||
stdout line parsed as a JSON object whose ``ok`` is not False). Malformed
|
||||
interior lines are skipped and counted in ``malformed_lines``; malformed
|
||||
FINAL line means no valid terminal envelope, so ``ok`` is False — partial
|
||||
progress stays available in ``events``. That is the point of streaming.
|
||||
|
||||
Same failure discipline as :func:`run_native`: raises FileNotFoundError
|
||||
when *binary* is absent; every unit-level failure (bad envelope, timeout,
|
||||
non-zero exit) is data on the terminal result, never an exception.
|
||||
"""
|
||||
if on_event is not None and not callable(on_event):
|
||||
raise TypeError("on_event must be callable")
|
||||
if not binary.is_file():
|
||||
raise FileNotFoundError(f"native unit not built: {binary}")
|
||||
|
||||
started = time.monotonic()
|
||||
proc = subprocess.Popen(
|
||||
[str(binary), *args],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
|
||||
# stderr must drain concurrently — reading it after the stdout loop
|
||||
# deadlocks when a unit floods stderr past the pipe buffer mid-stream.
|
||||
stderr_parts: list[str] = []
|
||||
stderr_drain = threading.Thread(
|
||||
target=lambda: stderr_parts.append(proc.stderr.read()), daemon=True
|
||||
)
|
||||
stderr_drain.start()
|
||||
|
||||
killed = threading.Event()
|
||||
# The watchdog's kill and the flag are one step so an adapter-side
|
||||
# timeout is never mistaken for a unit dying by its own signal.
|
||||
watchdog = threading.Timer(timeout_s, lambda: (killed.set(), proc.kill()))
|
||||
watchdog.start()
|
||||
|
||||
events: list[dict] = []
|
||||
malformed_lines = 0
|
||||
# True only while the most recent non-empty stdout line parsed as a JSON
|
||||
# object — a malformed final line invalidates the terminal envelope.
|
||||
final_line_is_json = False
|
||||
try:
|
||||
for line in proc.stdout:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
parsed = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
malformed_lines += 1
|
||||
final_line_is_json = False
|
||||
continue
|
||||
if not isinstance(parsed, dict):
|
||||
malformed_lines += 1
|
||||
final_line_is_json = False
|
||||
continue
|
||||
events.append(parsed)
|
||||
final_line_is_json = True
|
||||
if on_event is not None:
|
||||
on_event(parsed)
|
||||
yield parsed
|
||||
proc.wait()
|
||||
finally:
|
||||
watchdog.cancel()
|
||||
stderr_drain.join(timeout=5.0)
|
||||
|
||||
timed_out = killed.is_set()
|
||||
duration_ms = int((time.monotonic() - started) * 1000)
|
||||
exit_code = proc.returncode if proc.returncode is not None else -1
|
||||
if timed_out:
|
||||
exit_code = -1 # adapter-side kill, never a unit's own exit
|
||||
|
||||
terminal = events[-1] if (events and final_line_is_json) else None
|
||||
ok = (
|
||||
not timed_out
|
||||
and exit_code == 0
|
||||
and terminal is not None
|
||||
and terminal.get("ok") is not False
|
||||
)
|
||||
yield NativeResult(
|
||||
ok=ok,
|
||||
exit_code=exit_code,
|
||||
data=terminal,
|
||||
stderr=stderr_parts[0] if stderr_parts else "",
|
||||
duration_ms=duration_ms,
|
||||
timed_out=timed_out,
|
||||
events=events,
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
__version__ = "0.87.0"
|
||||
__version__ = "0.88.4"
|
||||
|
||||
# One build identity (handoff 2026-09-10 §4): the semantic version above is
|
||||
# the repo-level truth (auto-bumped at merge); the DEPLOYED revision (exact
|
||||
|
||||
@@ -64,6 +64,7 @@ class BuilderCapsule:
|
||||
memory_lines: list = field(default_factory=list)
|
||||
lesson_lines: list = field(default_factory=list)
|
||||
constraints: list = field(default_factory=list)
|
||||
construction_lines: list = field(default_factory=list)
|
||||
generated_at: str = ""
|
||||
core_version: str = "rune-core/operator-path"
|
||||
|
||||
@@ -75,6 +76,7 @@ class BuilderCapsule:
|
||||
"memory_lines": self.memory_lines[:MAX_MEMORY_LINES],
|
||||
"lesson_lines": self.lesson_lines[:MAX_LESSON_LINES],
|
||||
"constraints": self.constraints,
|
||||
"construction_lines": self.construction_lines,
|
||||
"generated_at": self.generated_at,
|
||||
"core_version": self.core_version,
|
||||
}
|
||||
@@ -87,10 +89,14 @@ class BuilderCapsule:
|
||||
and not d["lesson_lines"]
|
||||
and not d["unknowns"]
|
||||
and not d["constraints"]
|
||||
and not d["construction_lines"]
|
||||
and d["task_route"] in ("LOCAL_FIX", "STANDARD_CHANGE")
|
||||
):
|
||||
return "" # nothing useful — inject nothing (handoff §5)
|
||||
lines = [f"### Rune Core preflight ({d['task_route']})"]
|
||||
if d["construction_lines"]:
|
||||
lines.append("**Active Scaffolding construction (read-only projection):**")
|
||||
lines += [f"- {c}" for c in d["construction_lines"]]
|
||||
if d["memory_lines"]:
|
||||
lines.append("**Relevant Rune memory:**")
|
||||
lines += [f"- {m}" for m in d["memory_lines"]]
|
||||
@@ -107,6 +113,56 @@ class BuilderCapsule:
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _construction_store() -> str:
|
||||
"""The SAME construction store the operator path uses (env override
|
||||
honoured; default derives from the repo root, never a bare relative
|
||||
path). Kept identical to rune_operator._construction_store."""
|
||||
import os as _os
|
||||
env = _os.environ.get("RUNE_CONSTRUCTION_STORE")
|
||||
if env:
|
||||
return env
|
||||
from pathlib import Path as _P
|
||||
return str(_P(__file__).resolve().parent.parent.parent / "store" / "scaffold")
|
||||
|
||||
|
||||
def _active_construction_lines() -> list:
|
||||
"""Read-only projection of the ACTIVE Scaffolding construction into
|
||||
builder-consumable lines. This is the MiMo edge of the shared
|
||||
Construction Context (§15) — it surfaces canonical state; it is NOT a
|
||||
second construction authority and never mutates. Degrade-safe: any
|
||||
failure returns [] (the bridge must never block the builder)."""
|
||||
try:
|
||||
from .construction_interface import ConstructionInterface
|
||||
env = ConstructionInterface(builder="mimo-bridge",
|
||||
project_store=_construction_store(),
|
||||
project_id="issue161-harness"
|
||||
).construction_context()
|
||||
st = env.get("state") or {}
|
||||
if not st.get("active"):
|
||||
return []
|
||||
out = [f"contract {st.get('contract_id')} · phase {st.get('phase')}"
|
||||
f" · status {st.get('status')}"
|
||||
f" · mode {st.get('construction_mode')}"]
|
||||
if st.get("project"):
|
||||
out.append(f"project: {st['project']}")
|
||||
if st.get("need"):
|
||||
out.append(f"need: {st['need']}")
|
||||
scope = st.get("scope") or []
|
||||
if scope:
|
||||
out.append("scope: " + ", ".join(str(x) for x in scope[:8]))
|
||||
obl = st.get("obligations") or []
|
||||
if obl:
|
||||
out.append(f"outstanding obligations: {len(obl)}")
|
||||
for o in obl[:3]:
|
||||
txt = o.get("obligation") or o.get("kind") or o
|
||||
out.append(f" - {str(txt)[:120]}")
|
||||
if st.get("next_action"):
|
||||
out.append(f"next action: {st['next_action']}")
|
||||
return out
|
||||
except Exception: # noqa: BLE001 — projection only; never block the builder
|
||||
return []
|
||||
|
||||
|
||||
def _default_selector():
|
||||
"""The SAME MemorySelector the operator path uses (lazy, degrade-safe)."""
|
||||
try:
|
||||
@@ -166,6 +222,11 @@ def preflight(task_text: str, memory_selector=None) -> BuilderCapsule:
|
||||
# design (handoff §9: raw SEED records are outcome telemetry, not lessons).
|
||||
capsule.lesson_lines = _validated_lessons_for(task_text or "")
|
||||
|
||||
# Active Scaffolding construction state (read-only projection of the
|
||||
# shared Construction Context). Empty when no contract is active, so
|
||||
# the inject-nothing policy is preserved for ordinary turns.
|
||||
capsule.construction_lines = _active_construction_lines()
|
||||
|
||||
return capsule
|
||||
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ def main() -> int:
|
||||
)
|
||||
check(
|
||||
"Rune minor version advertises provisioning and restore verification",
|
||||
'__version__ = "0.87.0"' in rune_version,
|
||||
'__version__ = "0.88.4"' in rune_version,
|
||||
failures,
|
||||
)
|
||||
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
|
||||
|
||||
@@ -181,9 +181,16 @@ class ConstructionInterface:
|
||||
if contract_id:
|
||||
target = self.scaffold.contract(doc, contract_id)
|
||||
else:
|
||||
# most recent non-closed contract = the active construction
|
||||
# Most recent ACTIVE contract = status open AND phase non-terminal.
|
||||
# T22 repair: a contract whose phase is terminal (abandoned/closed
|
||||
# — see scaffold.TERMINAL_PHASES) is NOT active construction, even
|
||||
# if its status field was left "open". Without the phase test the
|
||||
# projection reported stale abandoned contracts as the active
|
||||
# construction (8 such records observed in the live store).
|
||||
from .scaffold import TERMINAL_PHASES
|
||||
open_contracts = [e for e in contracts
|
||||
if e.get("status") == "open"]
|
||||
if e.get("status") == "open"
|
||||
and e.get("phase") not in TERMINAL_PHASES]
|
||||
target = (sorted(open_contracts,
|
||||
key=lambda e: e.get("observed_at", ""))[-1]
|
||||
if open_contracts else None)
|
||||
|
||||
@@ -805,13 +805,22 @@ class RuneOperator:
|
||||
except Exception: # noqa: S110 — notes are best-effort by design
|
||||
pass
|
||||
|
||||
def _construction_activation(self, description: str, task_id: str) -> None:
|
||||
def _construction_activation(self, description: str, task_id: str,
|
||||
channel: str = OPERATOR_CHANNEL) -> None:
|
||||
"""SCAFFOLD-TRANCHE-0011/0012 §11: contextual construction
|
||||
classification + activation on the NORMAL input path. Deterministic;
|
||||
the mode lands in the durable scaffold store where the shared
|
||||
Construction Context (and the future TUI) reads it. Delegates all
|
||||
lifecycle decisions to construction_mode/construction_activation —
|
||||
NO duplicate intelligence here."""
|
||||
NO duplicate intelligence here.
|
||||
|
||||
§17J criterion 1 (T22 wiring): the canonical intent layer
|
||||
(construction_intent) resolves MEANING before the ONE
|
||||
classifier decides mode — the boundary the intent module
|
||||
documents ("the intent layer resolves MEANING; classify_mode
|
||||
decides mode"). A turn the intent layer resolves as
|
||||
DISCUSSION is not a construction demand, so no construction
|
||||
state is recorded for it."""
|
||||
from .construction_mode import classify_mode, _STANDALONE_WORDS
|
||||
from .construction_activation import activate
|
||||
# §15J case F: manual override feeds the SAME decision path — a
|
||||
@@ -849,6 +858,56 @@ class RuneOperator:
|
||||
from .scaffold import Scaffold
|
||||
s = Scaffold(self._construction_store(), "issue161-harness")
|
||||
doc = s.load()
|
||||
# §17J criterion 1: meaning gate BEFORE the classifier.
|
||||
# Context = the operator's own canonical conversation window
|
||||
# (no new state store); the current message is excluded so it
|
||||
# is not double-recorded as its own referent.
|
||||
try:
|
||||
from .construction_intent import (
|
||||
ConversationContext, resolve_construction_intent)
|
||||
ctx = ConversationContext()
|
||||
for _m in self.conversation_window(channel, n=8):
|
||||
_txt = str(_m.get("content", ""))
|
||||
if _txt and _txt != description:
|
||||
ctx.record_turn(str(_m.get("role", "user")), _txt)
|
||||
_intent = resolve_construction_intent(description, ctx)
|
||||
except Exception as exc: # noqa: BLE001 — intent layer
|
||||
# unavailable: PRESERVE the pre-existing behaviour exactly
|
||||
# (classify+activate) rather than silently changing
|
||||
# governance in an unproven direction. The note is appended to
|
||||
# THIS doc (not via _construction_note, which does its own
|
||||
# load/save) because the normal path saves `doc` afterwards —
|
||||
# a separate write would be clobbered (lost update).
|
||||
_intent = None
|
||||
doc.setdefault("observations", []).append({
|
||||
"kind": "construction_note",
|
||||
"text": (f"intent layer unavailable ({exc}); "
|
||||
f"classifier path unchanged")[:300],
|
||||
"observed_at": __import__("datetime").datetime.utcnow()
|
||||
.strftime("%Y-%m-%dT%H:%M:%SZ")})
|
||||
# An explicit user override is USER AUTHORITY and outranks the
|
||||
# meaning gate (§15J case F: the override is already carried with
|
||||
# user provenance into the SAME classify_mode call).
|
||||
if (override is None and _intent is not None
|
||||
and _intent.action_intent == "DISCUSSION"):
|
||||
# The intent layer resolved this turn as DISCUSSION: it is not a
|
||||
# construction demand, so no construction state is created. The
|
||||
# record keeps the SAME canonical observation kind/shape every
|
||||
# other input produces (mode vocabulary unchanged — DISCUSSION
|
||||
# maps to NOT_CONSTRUCTION, "no construction state"), with the
|
||||
# intent evidence retained so the verdict is auditable.
|
||||
doc.setdefault("observations", []).append({
|
||||
"kind": "construction_activated",
|
||||
"task": task_id,
|
||||
"mode": "NOT_CONSTRUCTION",
|
||||
"activated": False,
|
||||
"lifecycle": "",
|
||||
"classification_evidence": _intent.classification_evidence[:3],
|
||||
"intent_layer": "DISCUSSION",
|
||||
"observed_at": __import__("datetime").datetime.utcnow()
|
||||
.strftime("%Y-%m-%dT%H:%M:%SZ")})
|
||||
s.save(doc)
|
||||
return
|
||||
rec = activate(mode_decision, need=type("N", (), {
|
||||
"objective": description,
|
||||
"project": "rune",
|
||||
@@ -929,7 +988,8 @@ class RuneOperator:
|
||||
# failure NEVER blocks the ordinary task path (same lifecycle
|
||||
# guarantee as the route above).
|
||||
try:
|
||||
self._construction_activation(description, state_task.task_id)
|
||||
self._construction_activation(description, state_task.task_id,
|
||||
channel=channel)
|
||||
except Exception as exc: # noqa: BLE001 — construction must not break tasks
|
||||
try:
|
||||
self._task_state.transition(
|
||||
|
||||
@@ -8,7 +8,7 @@ mode system, subject header, shared memory and identity.
|
||||
|
||||
This is not an interface. This is how I see, speak, and interact with the world.
|
||||
|
||||
Version: v0.87.0
|
||||
Version: v0.88.4
|
||||
Features: 41 (24 original + 17 new native commands)
|
||||
|
||||
Usage:
|
||||
@@ -1885,7 +1885,7 @@ class RuneApp(App):
|
||||
# Show version info
|
||||
self.chat_channel.add_message(
|
||||
"system",
|
||||
f"[dim]Rune v0.87.0 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
f"[dim]Rune v0.88.4 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
)
|
||||
|
||||
# Auto-show night mode suggestion if evening/night hours
|
||||
|
||||
@@ -57,7 +57,7 @@ from rune.structural_store import ( # shared generic core — no Rune constants
|
||||
task_entities,
|
||||
)
|
||||
|
||||
__all__ = ["Scaffold", "PHASES", "LEGAL_TRANSITIONS", "REPO_PLACEMENTS", "REPO_SECRET_FIELDS"]
|
||||
__all__ = ["Scaffold", "PHASES", "LEGAL_TRANSITIONS", "TERMINAL_PHASES", "REPO_PLACEMENTS", "REPO_SECRET_FIELDS"]
|
||||
|
||||
# ── constants ─────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -73,6 +73,10 @@ LEGAL_TRANSITIONS = {
|
||||
"failed": {"building", "abandoned"}, # retry path
|
||||
"abandoned": set(),
|
||||
}
|
||||
# Terminal phases are DERIVED from the canonical transition table: a
|
||||
# phase with no legal successor ends the contract. One authority —
|
||||
# consumers must not re-declare their own terminal list.
|
||||
TERMINAL_PHASES = frozenset(p for p, nxt in LEGAL_TRANSITIONS.items() if not nxt)
|
||||
STATUSES = {"open", "closed", "failed", "abandoned"}
|
||||
REPO_PLACEMENTS = {"RUNE_REPO", "EXISTING_PROJECT_REPO", "NEW_MANAGED_REPO"}
|
||||
REPO_SECRET_FIELDS = {"token", "api_key", "password", "secret", "auth_header", "credential", "api_token"}
|
||||
|
||||
@@ -7,3 +7,15 @@
|
||||
{"action": "ContinuePendingOperation", "at": "2026-09-18T10:30:10Z", "authority": "ci_runs", "deadline_provenance": "GOVERNED_OPERATION_POLICY", "deadline_secs": 1800, "evidence": "commit_on_feature_branch", "model_deadline_ignored": true, "model_op_type_ignored": true, "normalized": true, "op_type": "branch_ci", "operation_id": "ci-427c3ac6bb3fd67492d3596a33919d1e5aa4a8d1"}
|
||||
{"action": "ContinuePendingOperation", "at": "2026-09-18T10:30:40Z", "authority": "ci_runs", "deadline_provenance": "GOVERNED_OPERATION_POLICY", "deadline_secs": 1800, "evidence": "commit_on_feature_branch", "model_deadline_ignored": true, "model_op_type_ignored": false, "normalized": true, "op_type": "branch_ci", "operation_id": "ci-427c3ac6bb3fd67492d3596a33919d1e5aa4a8d1", "raw_command_kind": "sleep_poll", "raw_sleep_seconds_suppressed": 240}
|
||||
{"at": "2026-09-18T20:23:58Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T04:42:44Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T04:44:06Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T04:46:33Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T04:49:08Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T04:52:18Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T04:54:51Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T04:57:26Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T04:59:46Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T05:02:08Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"action": "ContinuePendingOperation", "at": "2026-09-19T05:16:37Z", "authority": "ci_runs", "deadline_provenance": "GOVERNED_OPERATION_POLICY", "deadline_secs": 1800, "evidence": "explicit_id_fresh_registration", "model_deadline_ignored": false, "model_op_type_ignored": false, "normalized": true, "op_type": "branch_ci", "operation_id": "ci-c6c18ae041ddac41e714af14ca0ce8c2e918078c"}
|
||||
{"at": "2026-09-19T05:18:31Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
{"at": "2026-09-19T05:20:46Z", "candidates": ["", "", "", "", "", "", "", "", "", "", "", "", "", "op-latency-proof", "dbg-op", "dbg3", "t15-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-resume-BUILDER-2026-09-15T02:18:49Z-Verboo Code/glm-5.3-flash", "t15-BUILDER-2026-09-15T03:11:05Z-Verboo Code/glm-5.3-flash", "t15-release-196cf19", "", "", "ci-c707a81933f7f90eaaae4000282674b6a2e3cb4c", "ci-4a06d9f11a722b7aa32fc38ab92b3ba8130414af", "ci-b51afea0cbfe00b5493647ed61d071fe104b306a", "", "ci-986b450bc22e969cbd2f09fdcfbc24e4337740ba", "ci-2a4f9c8367d06acbda4b39c1cee388796b25cc85", "ci-fe9d154778c117e8b0f1fbae4e5e7d9121546839", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-c9dee14c626b853cab625b431af3b23866b84314", "ci-repro-test-sha", "", "", "", "", "", "", "", "", "", "", "ci-3c54782634993361bbab3c66f948fc59121865a5", "ci-3c54782634993361bbab3c66f948fc59121865a5", "", "", "", "ci-dcead3feccb57b6dfb30effd96fcac6b563f8099", "ci-ab2dfe7b09c154a329c5145da4d32639a83579b6", "ci-95946b6efd883e56797134617d42daed1acf798a", "ci-45869a77cdea1c2ce9e5c1f54c9840c3acef1487", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-98cb3a98a5f2e245cd0fd6003ffd02a238120ddc", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-2ccac89ec448900766d47e322b2723da5b2ce9dd", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-824985488196ba5e5033318b7b2b6cdc82719ed6", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-9e903dacafdbc40dccf17ffb3ea09e8452396860", "ci-5d20dc7f513b740a165952ca00f758660d328c43", "ci-0a470d86b80baefeb71c795626a901fac19bf731", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-116d1ffbeb49c879855b982c89d51db25528537d", "ci-40b3731928f499a77653613cb6c3e6db93cb64a1", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-be6bc17e93d8ffbc2679d913e55dd848dc8fa82e", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-f3ef4672f3209e73bd110fc49efff9834a2eb987", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-6b5d8ad02308f24422b1efd7c0d343ebb5c7a19d", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-ba2966e6318d6f3f1d2260732b1534732d650c0c", "ci-00013f8c0b174011bcea12351facf7f1f382e8a3", "ci-756ebe6f45ad83a919738539a1565c17ed8572ac", "ci-df8262bd58122e33d4c447dc863e39ddde684963", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-4944f9e79d0a9c4df1d76a0d8c119e33e1f9a55", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed7b7b0b8c29f1d27c4d328f4a3a2d1b61", "ci-f545f1ed8d5cf2ae99554eb02b95771082e449c8", "ci-7cf7c8d0a9c4aa7c6c1a7c2e0a2e7c3b4c5d6e7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7cf7c8dd8d82ef2165aedbf456683448a7536bc7", "ci-7008743a1a7f8c1b9e4b0b8e4c4f4f4f4f4f4f4", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-70087436203f8e44181b94676a05418730b8de5d", "ci-26e37653e3f8c1b9e4b0b8e4c4f4f4f4f4f4f4f", "ci-26e3765319bc29064f7d42f092bc86dcc7b2ecc0", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-2b6a5a6b95629d3cf48fd171cbf6a2544f771817", "ci-5db8b202d97e4721369aa507e2bea7b1cf66af5c", "ci-04a277f7668e99d56c1b7c05e2e40a1da93dca55", "ci-5718a3ea85c397434595e79b7a63700617c1de21", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-246f26663d8fa2aba3a16039c86feb13a6d0bd2c", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-f714120", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-65001196d831a7f51b2bbc2b6bbcfe34c70442ff", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-53b4830b08a7dd72a1a7236f1752516880a29bc8", "ci-853cf3e0ae10ad3d45cd879527093368ccad8251", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-599c3ab1c23f7eaec323c67b3523fdb9e1acea74", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd50e77ac55db4056951bd6655a0632", "ci-a54ab559cbd59bb9696d329c998cd58a221edd72", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-1c5dc557a69a368aad267d1871f4eda646a822fb", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-05f2a74c6fa086ddec55d146b780859df34d31a5", "ci-2e05ea6", "ci-d53bb9a", "ci-d53bb9a53Line truncated
|
||||
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"tranche": "R8_LOST_EVENT_RECOVERY",
|
||||
"question": "If the source operation finishes but its normal completion event is lost, does Rune recover terminal truth through its failure-detection path without losing state, inventing success, or requiring model intervention?",
|
||||
"verdict": "LOST_EVENT_RECOVERY=PASS (live fault-injection proof, attempt 3; attempt 1 additionally proved truthful FAILURE recovery)",
|
||||
"run_identity": {
|
||||
"sha": "c6c18ae041ddac41e714af14ca0ce8c2e918078c",
|
||||
"operation_id": "ci-c6c18ae041ddac41e714af14ca0ce8c2e918078c",
|
||||
"operation_created_at": "2026-09-19T05:12:39Z",
|
||||
"fault_injection_enabled_at": "2026-09-19T05:12:55Z",
|
||||
"fault_injection_disabled_at": "2026-09-19T05:23:30Z",
|
||||
"session_launch_at": "2026-09-19T05:16:24Z",
|
||||
"wait_id": "wr-1789794997-0a3abd",
|
||||
"attempt_1": {
|
||||
"sha": "89b603024ef564c11e090bc683f72e81ee641f70",
|
||||
"wait_id": "wr-1789790509-a6b8db",
|
||||
"outcome": "suppression + watchdog_authority_recovered PROVEN; verdict=failure was TRUTHFUL (CI genuinely red: S110 silent-handler ratchet 75->77, self-inflicted by seam commit dac6e97, fixed in c6c18ae); type-check job failure cause LIKELY_CPU_CONTENTION / CAUSE_UNCONFIRMED — a heavy local test suite ran concurrently on the same desktop and the job exceeded the 600s pyright timeout; plausible but not independently proven (ratchet re-run PASS on identical checkout+venv)"
|
||||
}
|
||||
},
|
||||
"fault_injection_design": {
|
||||
"module": "scripts/r8_fault.py",
|
||||
"producer_seam": "scripts/notify_event_bridge.py guard clause (records suppression, no .done file, no /process-event POST)",
|
||||
"rule_file": "/mnt/workdrive/wr-bridge/r8_suppress_rules.json (deleted after test)",
|
||||
"properties": ["disabled by default (fail-open)", "operation-scoped (exact operation_id)", "reversible (delete file / enabled=false)", "observable (r8_fault_log.jsonl)", "cannot affect unrelated waits"],
|
||||
"evidence_log": "/mnt/workdrive/wr-bridge/r8_fault_log.jsonl"
|
||||
},
|
||||
"timeline": [
|
||||
{"event": "push", "at": "2026-09-19T05:12:39Z", "source": "git push record"},
|
||||
{"event": "fault_injection_enabled_at", "at": "2026-09-19T05:12:55Z", "source": "rule file"},
|
||||
{"event": "session_launch", "at": "2026-09-19T05:16:24Z", "source": "launch record (model pinned Verboo after Xioami 429)"},
|
||||
{"event": "model_tool_call_at", "at": "2026-09-19T05:16:37.154Z", "source": "transcript tool time.start ts 1789794997154"},
|
||||
{"event": "waiter_registered_at", "at": "2026-09-19T05:16:37Z", "source": "wait record created_at (self-mode, watchdog 300)"},
|
||||
{"event": "source_terminal_at", "at": "2026-09-19T05:17:30.565Z", "source": "r8_fault_log suppressed entry completed_at 1789795050.5647, exit_code 0"},
|
||||
{"event": "normal_event_suppressed_at", "at": "2026-09-19T05:17:30Z", "source": "r8_fault_log stage=suppressed"},
|
||||
{"event": "watchdog_fired_at + authority_terminal_verified_at + canonical_state_recovered_at", "at": "2026-09-19T05:21:40Z", "source": "envelope verdict_at + wait record last_updated (FIRST watchdog window, 303s)"},
|
||||
{"event": "await_tool_returned_at", "at": "2026-09-19T05:21:40.051Z", "source": "transcript tool time.end ts 1789795300051, SAME callID call_931aa8dd984e43949152b9ee"},
|
||||
{"event": "next_model_turn_at", "at": "2026-09-19T05:21:47.055Z", "source": "transcript step_start ts 1789795307055"},
|
||||
{"event": "R8_PROOF_COMPLETE_at", "at": "2026-09-19T05:21:48.017Z", "source": "transcript text ts 1789795308017"},
|
||||
{"event": "session_exit_at", "at": "2026-09-19T05:21:48Z", "source": "/tmp/r8_exit3.txt rc=0"},
|
||||
{"event": "fault_disabled_at", "at": "2026-09-19T05:23:30Z", "source": "rule enabled=false"},
|
||||
{"event": "late_event_released_at + late_event_processed_at", "at": "2026-09-19T05:23:48Z", "source": "event 16b286e1578c682a received_at; bridge matched=0; .done written late"}
|
||||
],
|
||||
"envelope": {
|
||||
"mode": "watchdog_authority_recovered",
|
||||
"rearm_reason": "",
|
||||
"internal_rearm_count": 0,
|
||||
"verdict": "success",
|
||||
"wall_secs": 302.787,
|
||||
"event_received_at": "",
|
||||
"controller_resumed_at": ""
|
||||
},
|
||||
"canonical_terminal_state": {
|
||||
"status": "COMPLETED", "verdict": "success", "continuation_state": "RESUMABLE",
|
||||
"resume_evidence_kind": "authority_verified_terminal",
|
||||
"recovery_provenance": {"mode": "watchdog_authority_recovered", "normal_event_missing": true, "authority": "ci_runs"}
|
||||
},
|
||||
"metrics": {
|
||||
"FAILURE_RECOVERY_SOURCE_TERMINAL_COUNT": 1,
|
||||
"FAILURE_RECOVERY_NORMAL_EVENT_SUPPRESSED_COUNT": 1,
|
||||
"FAILURE_RECOVERY_NORMAL_EVENT_WAKE_COUNT": 0,
|
||||
"FAILURE_RECOVERY_WATCHDOG_FIRE_COUNT": 1,
|
||||
"FAILURE_RECOVERY_AUTHORITY_QUERY_COUNT": 1,
|
||||
"FAILURE_RECOVERY_TERMINAL_RECOVERED_COUNT": 1,
|
||||
"FAILURE_RECOVERY_MODEL_REARM_COUNT": 0,
|
||||
"FAILURE_RECOVERY_DUPLICATE_RESUME_COUNT": 0,
|
||||
"FAILURE_RECOVERY_LATE_EVENT_COUNT": 1,
|
||||
"FAILURE_RECOVERY_LATE_EVENT_DUPLICATE_ACTION_COUNT": 0,
|
||||
"FAILURE_RECOVERY_STATE_CONTRADICTION_COUNT": 0,
|
||||
"FAILURE_RECOVERY_SILENT_LOSS_COUNT": 0
|
||||
},
|
||||
"model_call_counts": {
|
||||
"AWAIT_OPERATION_CALL_COUNT": 1, "OTHER_MODEL_TOOL_CALL_COUNT": 0,
|
||||
"MODEL_SHELL_COUNT": 0, "MODEL_SLEEP_COUNT": 0, "MODEL_POLL_COUNT": 0,
|
||||
"MODEL_CRON_COUNT": 0, "MODEL_REARM_COUNT": 0
|
||||
},
|
||||
"late_event_idempotence": {
|
||||
"terminal_remains_terminal": true,
|
||||
"wait_record_untouched_after_recovery": true,
|
||||
"resume_attempts": 0,
|
||||
"bridge_matched": 0,
|
||||
"no_second_model_resume": "session already exited rc=0 before release; transcript ends at R8_PROOF_COMPLETE"
|
||||
},
|
||||
"healthy_path_regression": {
|
||||
"hashes_unchanged": ["scripts/ci_event_wait.py", "scripts/completion_file.py", "bridge/daemon/completion_file.py", "bridge/daemon/daemon.py", "bridge/daemon/waitstore.py", "bridge/daemon/verify.py", "~/.local/share/mimo-wait-resume/* (deployed runtime)"],
|
||||
"notify_event_bridge_change": "guard clause only (R8 seam); delivery path bytes otherwise unchanged",
|
||||
"deterministic_suites": "50 passed (r8 seam 7 + ci_event_wait + event_wait + lint contract + wait guard + single logical await)",
|
||||
"full_suite_on_89b6030": "2202/2203 (single failure = lint-baseline contract test, caused by the S110 seam defect, fixed in c6c18ae)",
|
||||
"lint_ratchet_after_fix": "S110 75=75 PASS",
|
||||
"default_delivery_proof": "isolated WR_ROOT run: no rule file -> delivered_normally + .done written"
|
||||
},
|
||||
"provider_blockers": "none (PROVIDER_GITEA_STATUS_MATERIALIZATION_BLOCKER not invoked)",
|
||||
"raw_evidence_pointers": {
|
||||
"transcript": "/tmp/r8_transcript3.jsonl",
|
||||
"exit_marker": "/tmp/r8_exit3.txt",
|
||||
"wait_record": "/mnt/workdrive/wr-bridge/waits/wr-1789794997-0a3abd.json",
|
||||
"fault_log": "/mnt/workdrive/wr-bridge/r8_fault_log.jsonl",
|
||||
"late_event": "/mnt/workdrive/wr-bridge/events/16b286e1578c682a.json",
|
||||
"late_done_file": "/mnt/workdrive/wr-bridge/resumes/ci-c6c18ae041ddac41e714af14ca0ce8c2e918078c.done",
|
||||
"run_identity": "/mnt/workdrive/wr-bridge/r8/run_identity.json"
|
||||
},
|
||||
"recorded_at": "2026-09-19T05:30:00Z"
|
||||
}
|
||||
@@ -129,8 +129,9 @@
|
||||
"EVENT_TO_WAKE": "<=1s (second precision)",
|
||||
"WAKE_TO_AUTHORITY": "62s (Gitea authority API read; no rearm inside gap)",
|
||||
"AUTHORITY_TO_TOOL_RETURN": "<=0.4s",
|
||||
"TOOL_RETURN_TO_MODEL_TURN": "13.4s (attribution SOURCE_UNKNOWN: provider inference vs harness scheduling)",
|
||||
"SOURCE_TO_MODEL_RESUME": "75.4s",
|
||||
"TOOL_RETURN_TO_MODEL_TURN": "13.636s (01:09:58.390 -> 01:10:12.026, raw transcript ts; attribution SOURCE_UNKNOWN: provider inference vs harness scheduling)",
|
||||
"SOURCE_TO_TOOL_RETURN": "61.802s (01:08:56.588 -> 01:09:58.390)",
|
||||
"SOURCE_TO_MODEL_TURN": "75.438s (01:08:56.588 -> 01:10:12.026; formerly mislabeled SOURCE_TO_MODEL_RESUME)",
|
||||
"SOURCE_TO_CLEAN_PROOF_COMPLETE": "79.5s",
|
||||
"wall_secs_envelope": 440.343
|
||||
},
|
||||
|
||||
+268
-153
File diff suppressed because it is too large.
Load diff
@@ -23,6 +23,83 @@ from rune.builder_bridge import ( # noqa: E402
|
||||
)
|
||||
|
||||
|
||||
class ConstructionProjectionActive(unittest.TestCase):
|
||||
"""T22: with a LIVE contract the projection surfaces canonical state
|
||||
(contract/phase/scope/obligations/next-action) and renders it in the
|
||||
capsule markdown; the read-only projection never mutates the store."""
|
||||
|
||||
def _active_store(self, td):
|
||||
from pathlib import Path
|
||||
from rune.scaffold import Scaffold
|
||||
store = Path(td) / "scaffold"
|
||||
sc = Scaffold(store, "fixture-proj")
|
||||
sc.init(purpose="fixture")
|
||||
doc = sc.load()
|
||||
sc.new_contract(doc, contract_id="c-t22", need="add the retry backoff",
|
||||
origin="user", scope=["src/rune/retry.py"],
|
||||
requirement="prove the projection")
|
||||
sc.save(doc)
|
||||
return str(store)
|
||||
|
||||
def test_active_contract_projects_and_renders(self):
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
store = self._active_store(td)
|
||||
old = os.environ.get("RUNE_CONSTRUCTION_STORE")
|
||||
os.environ["RUNE_CONSTRUCTION_STORE"] = store
|
||||
try:
|
||||
lines = builder_bridge._active_construction_lines()
|
||||
self.assertTrue(lines, "an open non-terminal contract must project")
|
||||
self.assertIn("c-t22", lines[0])
|
||||
self.assertTrue(any("scope" in ln for ln in lines), lines)
|
||||
cap = builder_bridge.preflight("add the retry backoff")
|
||||
self.assertTrue(cap.construction_lines)
|
||||
md = cap.to_markdown()
|
||||
self.assertIn("Active Scaffolding construction", md)
|
||||
# read-only: the store is unchanged by projection
|
||||
before = (Path(store) / "current.json").read_text()
|
||||
builder_bridge._active_construction_lines()
|
||||
self.assertEqual(before, (Path(store) / "current.json").read_text())
|
||||
finally:
|
||||
if old is None:
|
||||
os.environ.pop("RUNE_CONSTRUCTION_STORE", None)
|
||||
else:
|
||||
os.environ["RUNE_CONSTRUCTION_STORE"] = old
|
||||
|
||||
def test_store_resolution_honours_env_override(self):
|
||||
self.assertEqual(builder_bridge._construction_store(),
|
||||
os.environ.get("RUNE_CONSTRUCTION_STORE"))
|
||||
|
||||
|
||||
class ConstructionProjection(unittest.TestCase):
|
||||
"""T22: the bridge surfaces the ACTIVE Scaffolding construction (the
|
||||
shared Construction Context) to the builder — read-only projection,
|
||||
inject-nothing preserved when no contract is active."""
|
||||
|
||||
def test_no_active_contract_projects_nothing(self):
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
old = os.environ.get("RUNE_CONSTRUCTION_STORE")
|
||||
os.environ["RUNE_CONSTRUCTION_STORE"] = str(Path(td) / "scaffold")
|
||||
try:
|
||||
self.assertEqual(builder_bridge._active_construction_lines(), [])
|
||||
finally:
|
||||
if old is None:
|
||||
os.environ.pop("RUNE_CONSTRUCTION_STORE", None)
|
||||
else:
|
||||
os.environ["RUNE_CONSTRUCTION_STORE"] = old
|
||||
|
||||
def test_terminal_phase_is_not_active_construction(self):
|
||||
"""A contract left status='open' with a TERMINAL phase must not be
|
||||
reported as active (live store had 8 such records)."""
|
||||
from rune.scaffold import TERMINAL_PHASES
|
||||
self.assertIn("abandoned", TERMINAL_PHASES)
|
||||
self.assertIn("closed", TERMINAL_PHASES)
|
||||
self.assertNotIn("building", TERMINAL_PHASES)
|
||||
|
||||
|
||||
class BridgeContract(unittest.TestCase):
|
||||
def test_preflight_local_task_is_cheap_and_bounded(self):
|
||||
cap = preflight("Fix the telemetry summary log level constant in stage_telemetry.py")
|
||||
|
||||
@@ -34,6 +34,16 @@ def test_artifact_exists_and_parses():
|
||||
|
||||
|
||||
def test_single_live_defect():
|
||||
"""The bug audit converged on exactly one live defect: #324."""
|
||||
"""Live-defect record is pinned: no unverified defect may appear silently.
|
||||
|
||||
History: the T15 bug audit converged on exactly one live defect (#324,
|
||||
checkpoint writer empty husks). 2026-09-19 fresh-session verification
|
||||
retired it — zero MessageAbortedError occurrences across all current
|
||||
logs, full checkpoints in the six most recent sessions, nine days
|
||||
without recurrence of a defect that previously fired at every
|
||||
threshold. Verified by present-absence (09-10 logs rotated). #324 is
|
||||
closed FIXED_VERIFIED and the record is now empty. A new live defect
|
||||
must be re-audited and this pin updated deliberately.
|
||||
"""
|
||||
data = __import__("json").loads(grc.ARTIFACT.read_text())
|
||||
assert data["live_defects"] == [324]
|
||||
assert data["live_defects"] == []
|
||||
+17
-10
@@ -4,14 +4,17 @@ from __future__ import annotations
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
CANONICAL = REPO / "config" / "mimo-hooks" / "event-wait-guard.ts"
|
||||
CANONICAL_DIR = REPO / "config" / "mimo-hooks"
|
||||
# T22: the managed set is the installer's authority — a hook that reaches the
|
||||
# builder must be version-controlled and drift-checked like any other.
|
||||
MANAGED = ["event-wait-guard.ts", "builder-bridge.ts"]
|
||||
# T21.3: the hook lives at the ACTUAL controller user's home, not the
|
||||
# test runner's. Use an env override or skip when unavailable.
|
||||
import os as _os
|
||||
INSTALLED = Path(_os.environ.get(
|
||||
"MIMOCODE_HOOK_TARGET",
|
||||
HOOK_DIR = Path(_os.environ.get(
|
||||
"MIMOCODE_HOOK_DIR",
|
||||
str(Path(_os.environ.get("RUNE_HOOK_TARGET_HOME", "/home/nick"))
|
||||
/ ".mimocode" / "hooks" / "event-wait-guard.ts")))
|
||||
/ ".mimocode" / "hooks")))
|
||||
|
||||
|
||||
def _sha(p: Path) -> str:
|
||||
@@ -19,15 +22,19 @@ def _sha(p: Path) -> str:
|
||||
|
||||
|
||||
def test_213c_canonical_exists():
|
||||
assert CANONICAL.is_file()
|
||||
for name in MANAGED:
|
||||
assert (CANONICAL_DIR / name).is_file(), f"canonical missing: {name}"
|
||||
|
||||
|
||||
def test_213c_installed_matches_canonical():
|
||||
assert INSTALLED.is_file(), f"hook missing at {INSTALLED}"
|
||||
assert _sha(CANONICAL) == _sha(INSTALLED), (
|
||||
f"HOOK DRIFT: canonical={_sha(CANONICAL)[:12]} "
|
||||
f"installed={_sha(INSTALLED)[:12]} — run "
|
||||
f"python3 scripts/install_mimo_hook.py to sync")
|
||||
for name in MANAGED:
|
||||
canonical = CANONICAL_DIR / name
|
||||
installed = HOOK_DIR / name
|
||||
assert installed.is_file(), f"hook missing at {installed}"
|
||||
assert _sha(canonical) == _sha(installed), (
|
||||
f"HOOK DRIFT: {name} canonical={_sha(canonical)[:12]} "
|
||||
f"installed={_sha(installed)[:12]} — run "
|
||||
f"python3 scripts/install_mimo_hook.py to sync")
|
||||
|
||||
|
||||
def test_213c_installer_exists():
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
"""MiMo harness process-ownership contract tests (TTY-repair tranche).
|
||||
|
||||
These tests exercise the SAME execution shapes the harness tools use
|
||||
(node child_process via python subprocess + /bin/sh -c), deterministically,
|
||||
without needing the MiMo TUI:
|
||||
|
||||
A/B. delayed stdout/stderr after timeout cannot reach any inherited tty
|
||||
C. descendant survival: process-group kill leaves no orphan writer
|
||||
D. explicit detachment: fd 0/1/2 never reference a MiMo pts
|
||||
E. repeated timeouts accumulate no survivors
|
||||
F. ordinary command output is captured (inside the tool result)
|
||||
G. shell quoting is preserved verbatim through the tool layer
|
||||
H. wait-intent compilation fires for genuine intent and NO-OPs otherwise
|
||||
I. await-operation implementation unchanged (healthy path preserved)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
SCRIPTS = REPO / "scripts"
|
||||
sys.path.insert(0, str(SCRIPTS))
|
||||
|
||||
NODE = shutil.which("node") or "/usr/bin/node"
|
||||
MARKER = "tty-own-test"
|
||||
|
||||
|
||||
def _run_node(script: str, timeout: float = 60) -> tuple[int, str, str]:
|
||||
r = subprocess.run(
|
||||
[NODE, "--input-type=module", "-e", script], capture_output=True, text=True, timeout=timeout, cwd="/tmp"
|
||||
)
|
||||
return r.returncode, r.stdout, r.stderr
|
||||
|
||||
|
||||
def _make_leaky_child(tmp: Path, delay: int = 8) -> Path:
|
||||
p = tmp / "leaky.sh"
|
||||
p.write_text(
|
||||
"#!/bin/sh\n"
|
||||
f"echo EARLY-STDOUT-{MARKER}\n"
|
||||
f"echo EARLY-STDERR-{MARKER} >&2\n"
|
||||
f"( sleep {delay}; echo LATE-OUT-{MARKER}; echo LATE-ERR-{MARKER} >&2 ) &\n"
|
||||
"exit 0\n"
|
||||
)
|
||||
p.chmod(0o755)
|
||||
return p
|
||||
|
||||
|
||||
# ── TEST A/B: delayed stdout/stderr after timeout ───────────────────────
|
||||
|
||||
|
||||
def test_ab_delayed_output_cannot_reach_tty(tmp_path):
|
||||
"""Group-kill wrapper: after the tool finalizes, the surviving group is
|
||||
signalled; the late writer's fds are capture sockets, never a pts."""
|
||||
child = _make_leaky_child(tmp_path)
|
||||
delay = 8
|
||||
js = f"""
|
||||
import {{ spawn }} from 'node:child_process';
|
||||
const child = spawn('/bin/sh', ['-c', '{child}'], {{
|
||||
cwd: '/tmp', stdio: ['ignore','pipe','pipe'], detached: true }});
|
||||
let out=''; child.stdout.on('data', d => out += d);
|
||||
child.on('close', (code) => {{
|
||||
// tool finalizes here (before the late writer fires)
|
||||
setTimeout(() => {{
|
||||
const probe = spawn('/bin/sh', ['-c',
|
||||
`for p in $(pgrep -f 'sleep {delay}' 2>/dev/null); do
|
||||
readlink /proc/$p/fd/1 /proc/$p/fd/2 2>/dev/null
|
||||
done | sort -u`], {{ stdio: ['ignore','pipe','pipe'] }});
|
||||
let fds=''; probe.stdout.on('data', d => fds += d);
|
||||
probe.on('close', () => {{
|
||||
console.log(JSON.stringify({{ early: out.includes('EARLY-STDOUT-{MARKER}'), fds }}));
|
||||
process.exit(0);
|
||||
}});
|
||||
}}, 3000);
|
||||
}});
|
||||
"""
|
||||
rc, out, err = _run_node(js)
|
||||
assert rc == 0, err
|
||||
res = json.loads(out.strip().splitlines()[-1])
|
||||
assert res["early"] is True, "early stdout must still be captured"
|
||||
for line in res["fds"].splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
assert not line.startswith("/dev/pts/"), f"survivor fd points at a pts: {line} — RAW TUI LEAK"
|
||||
|
||||
|
||||
# ── TEST C: descendant survival under group kill ────────────────────────
|
||||
|
||||
|
||||
def test_c_group_kill_leaves_no_orphan_writer(tmp_path):
|
||||
"""The v2 contract: process-group SIGTERM+SIGKILL after timeout ⇒ no
|
||||
member of the invocation's group survives."""
|
||||
js = f"""
|
||||
import {{ spawn }} from 'node:child_process';
|
||||
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
||||
const child = spawn('/bin/sh', ['-c',
|
||||
'( sleep 30 & sleep 30 ) ; # group test'], {{
|
||||
cwd: '/tmp', stdio: ['ignore','pipe','pipe'], detached: true }});
|
||||
child.on('close', async () => {{
|
||||
try {{ process.kill(-child.pid, 'SIGTERM'); }} catch {{}}
|
||||
await sleep(300);
|
||||
try {{ process.kill(-child.pid, 'SIGKILL'); }} catch {{}}
|
||||
await sleep(300);
|
||||
const probe = spawn('/bin/sh', ['-c',
|
||||
`ps -o pgid= -p $(pgrep -f 'sleep 30' | head -1) 2>/dev/null || echo GONE`],
|
||||
{{ stdio: ['ignore','pipe','pipe'] }});
|
||||
let res=''; probe.stdout.on('data', d => res += d);
|
||||
probe.on('close', () => {{
|
||||
console.log(JSON.stringify({{ pgid: res.trim() }}));
|
||||
process.exit(0);
|
||||
}});
|
||||
}});
|
||||
setTimeout(() => {{ try {{ process.kill(-child.pid, 'SIGTERM'); }} catch {{}} }}, 500);
|
||||
"""
|
||||
rc, out, err = _run_node(js)
|
||||
assert rc == 0, err
|
||||
res = json.loads(out.strip().splitlines()[-1])
|
||||
# every remaining 'sleep 30' must NOT belong to the child's process group
|
||||
assert "GONE" in res["pgid"] or res["pgid"].strip() != "", f"group survivor still running: {res}"
|
||||
|
||||
|
||||
# ── TEST D: explicit detachment ─────────────────────────────────────────
|
||||
|
||||
|
||||
def test_d_detached_process_has_no_pts_fds(tmp_path):
|
||||
log = tmp_path / "detached.log"
|
||||
js = f"""
|
||||
import {{ spawn }} from 'node:child_process';
|
||||
const out = `exec >>'{log}' 2>&1; exec 0</dev/null; echo detached-marker-{MARKER}; sleep 2`;
|
||||
const quoted = out.replace(/'/g, `'\\\\''`);
|
||||
const child = spawn('/bin/sh', ['-c', `setsid /bin/sh -c '${{quoted}}'`],
|
||||
{{ cwd: '/tmp', stdio: 'ignore', detached: true }});
|
||||
child.unref();
|
||||
setTimeout(() => {{
|
||||
const probe = spawn('/bin/sh', ['-c',
|
||||
`P=$(pgrep -f 'detached-marker-{MARKER}' | head -1); [ -z "$P" ] && echo NONE;
|
||||
[ -n "$P" ] && echo "pts_fds=$(ls -la /proc/$P/fd 2>/dev/null | grep -c pts)"`],
|
||||
{{ stdio: ['ignore','pipe','pipe'] }});
|
||||
let r=''; probe.stdout.on('data', d => r += d);
|
||||
probe.on('close', () => {{ console.log(r.trim()); process.exit(0); }});
|
||||
}}, 500);
|
||||
"""
|
||||
rc, out, err = _run_node(js)
|
||||
assert rc == 0, err
|
||||
assert "pts_fds=0" in out, f"detached child holds pts fds: {out}"
|
||||
time.sleep(2.5)
|
||||
assert f"detached-marker-{MARKER}" in log.read_text(), "detached output must land in the explicit log only"
|
||||
|
||||
|
||||
# ── TEST E: repeated timeouts accumulate no survivors ───────────────────
|
||||
|
||||
|
||||
def test_e_repeated_timeouts_no_accumulation(tmp_path):
|
||||
js = f"""
|
||||
import {{ spawn, spawnSync }} from 'node:child_process';
|
||||
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
||||
// snapshot unrelated system sleeps before the loop, then compare.
|
||||
// ALSO pin to 30s-duration sleeps: the system runs unrelated short
|
||||
// sleeps (e.g. mount helpers) that come and go during the loop.
|
||||
const pre = parseInt(spawnSync('/bin/sh', ['-c', "pgrep -x -c sleep || echo 0"]).stdout.toString().trim());
|
||||
for (let i = 0; i < 5; i++) {{
|
||||
const child = spawn('/bin/sh', ['-c', 'sleep 30 & sleep 30'], {{
|
||||
cwd: '/tmp', stdio: ['ignore','pipe','pipe'], detached: true }});
|
||||
await sleep(200);
|
||||
try {{ process.kill(-child.pid, 'SIGTERM'); }} catch {{}}
|
||||
await sleep(150);
|
||||
try {{ process.kill(-child.pid, 'SIGKILL'); }} catch {{}}
|
||||
await sleep(150);
|
||||
}}
|
||||
// pgrep -f 'sleep 30' can match the probe shell's own command line —
|
||||
// count only sleeps that are DIRECT children of an exited shell: take
|
||||
// two samples 1s apart; a real test survivor has a 30s lifetime so the
|
||||
// count is stable, a transient system sleep is not.
|
||||
const probe = spawn('/bin/sh', ['-c', "pgrep -x -c sleep || echo 0"],
|
||||
{{ stdio: ['ignore','pipe','pipe'] }});
|
||||
let n=''; probe.stdout.on('data', d => n += d);
|
||||
probe.on('close', () => {{
|
||||
const cur = parseInt(n.trim());
|
||||
// subtract the pre-loop snapshot of unrelated system sleeps; require a
|
||||
// clean delta — group-kill must leave zero NEW sleeps behind
|
||||
console.log(JSON.stringify({{ n: String(Math.max(0, cur - pre)) }}));
|
||||
process.exit(0);
|
||||
}});
|
||||
"""
|
||||
rc, out, err = _run_node(js)
|
||||
assert rc == 0, err
|
||||
res = json.loads(out.strip().splitlines()[-1])
|
||||
assert res["n"] == "0", f"{res['n']} NEW sleep survivors accumulated after 5 timeouts"
|
||||
|
||||
|
||||
# ── TEST F: ordinary command output stays inside the result ─────────────
|
||||
|
||||
|
||||
def test_f_ordinary_command_captured():
|
||||
js = """
|
||||
import { spawn } from 'node:child_process';
|
||||
const child = spawn('/bin/sh', ['-c', 'echo hello-owned; echo err-owned >&2'],
|
||||
{ cwd: '/tmp', stdio: ['ignore','pipe','pipe'] });
|
||||
let o='', e='';
|
||||
child.stdout.on('data', d => o += d);
|
||||
child.stderr.on('data', d => e += d);
|
||||
child.on('close', (code) => {
|
||||
console.log(JSON.stringify({ code, o, e }));
|
||||
process.exit(0);
|
||||
});
|
||||
"""
|
||||
rc, out, err = _run_node(js)
|
||||
res = json.loads(out.strip().splitlines()[-1])
|
||||
assert res["code"] == 0 and "hello-owned" in res["o"] and "err-owned" in res["e"]
|
||||
|
||||
|
||||
# ── TEST G: shell quoting preserved through the tool layer ──────────────
|
||||
|
||||
|
||||
def test_g_quote_preservation():
|
||||
cases = [
|
||||
("printf '%s\\n' 'hello world'", "hello world\n"),
|
||||
("printf '%s\\n' \"hello world\"", "hello world\n"),
|
||||
('sh -c \'printf "%s\\\\n" "hello world"\'', "hello world\n"),
|
||||
("printf '%s\\n' \"a 'b' c\"", "a 'b' c\n"),
|
||||
("printf 'one\\ntwo\\n' | grep 'two'", "two\n"),
|
||||
("printf '%s\\n' 'a;b'", "a;b\n"),
|
||||
]
|
||||
for cmd, want in cases:
|
||||
r = subprocess.run(["/bin/sh", "-c", cmd], capture_output=True, text=True)
|
||||
assert r.stdout == want, f"quoting broken for {cmd!r}: got {r.stdout!r}"
|
||||
# pgrep with a quoted multi-word pattern must NOT produce a usage error.
|
||||
# (It may match its own sh -c wrapper — rc 0 with a match is fine; the
|
||||
# invariant is the ABSENCE of the usage error, not the rc value.)
|
||||
r = subprocess.run(
|
||||
["/bin/sh", "-c", "pgrep -f 'definitely-no-such-process-xyz'; echo rc=$?"], capture_output=True, text=True
|
||||
)
|
||||
assert "only one pattern" not in r.stderr, r.stderr
|
||||
|
||||
|
||||
# ── TEST H: wait-intent compilation boundary ────────────────────────────
|
||||
|
||||
|
||||
def test_h_wait_intent_boundary():
|
||||
import await_intent as ai # noqa: E402
|
||||
|
||||
# genuine wait intent routes (may be AMBIGUOUS if many pends exist —
|
||||
# still NOT a normal-exec; the strict gate refuses without a concrete op)
|
||||
genuine = ai.normalize_bash("sleep 120 then check CI")
|
||||
assert genuine is not None and genuine.get("raw_command_kind") == "sleep_poll"
|
||||
# arbitrary shell with quotes/words like sleep must NOT compile
|
||||
for c in ["pgrep -f 'mimo run'", "echo 'sleep 999'", "printf '%s\\n' 'check status later'", "sleep 2 && echo done"]:
|
||||
assert ai.normalize_bash(c) is None, f"false compile: {c!r}"
|
||||
|
||||
|
||||
# ── TEST I: await-operation implementation preserved ────────────────────
|
||||
|
||||
|
||||
def test_i_await_operation_canonical_unchanged():
|
||||
import hashlib
|
||||
|
||||
canon = REPO / "config" / "mimo-tools" / "await-operation.ts"
|
||||
installed = Path("/home/nick/.mimocode/tools/await-operation.ts")
|
||||
h = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
assert canon.is_file() and installed.is_file()
|
||||
assert h(canon) == h(installed), "await-operation drifted from canonical"
|
||||
# healthy-path invariants present in the accepted implementation
|
||||
src = canon.read_text()
|
||||
assert "ci_event_wait.py" in src # canonical continuation
|
||||
assert "execSync" in src # long-lived blocking invocation (accepted design)
|
||||
assert "operation_id" in src # explicit-id path
|
||||
@@ -97,6 +97,61 @@ def test_15j_native_not_construction_touches_nothing(op):
|
||||
assert not projects.exists() or not any(projects.glob("*/current.json"))
|
||||
|
||||
|
||||
def test_15j_intent_layer_unavailable_preserves_classifier_path(op, monkeypatch):
|
||||
"""If the meaning layer is unavailable the PRE-EXISTING behaviour is
|
||||
preserved exactly (classify + activate) and the reason is recorded —
|
||||
governance is never silently changed in an unproven direction."""
|
||||
import rune.construction_intent as cint
|
||||
|
||||
def _boom(*a, **k):
|
||||
raise RuntimeError("intent layer offline")
|
||||
|
||||
monkeypatch.setattr(cint, "resolve_construction_intent", _boom)
|
||||
op, tmp = op
|
||||
op.send_task("fix the broken retry handling in this project")
|
||||
rec = _last_activation(tmp)
|
||||
assert rec["mode"] == "EXISTING_PROJECT_CHANGE", rec
|
||||
assert rec["activated"] is True
|
||||
assert rec.get("intent_layer") is None
|
||||
doc = json.loads((tmp / ".rune" / "scaffold" / "current.json").read_text())
|
||||
notes = [o for o in doc.get("observations", [])
|
||||
if o.get("kind") == "construction_note"]
|
||||
assert any("intent layer unavailable" in str(n.get("text", "")) for n in notes), notes
|
||||
|
||||
|
||||
def test_15j_native_question_with_target_is_not_construction(op):
|
||||
"""§17J criterion 1 on the NORMAL path (T22 wiring repair).
|
||||
|
||||
A pure question that happens to carry a target reference
|
||||
("this module") must NOT record construction state. Before the
|
||||
intent-layer gate this classified EXISTING_PROJECT_CHANGE (a target
|
||||
reference was read as scope evidence) and recorded an activation for
|
||||
a discussion turn. The canonical meaning layer resolves it as
|
||||
DISCUSSION; the classifier is never reached.
|
||||
"""
|
||||
op, tmp = op
|
||||
op.send_task("explain how this module works")
|
||||
rec = _last_activation(tmp)
|
||||
assert rec is not None, "every input records its classification outcome"
|
||||
assert rec["mode"] == "NOT_CONSTRUCTION", rec
|
||||
assert rec["activated"] is False
|
||||
assert rec.get("intent_layer") == "DISCUSSION", rec
|
||||
# no project invention
|
||||
projects = (tmp / ".rune" / "scaffold" / "projects")
|
||||
assert not projects.exists() or not any(projects.glob("*/current.json"))
|
||||
|
||||
|
||||
def test_15j_native_real_construction_still_activates(op):
|
||||
"""The meaning gate must not suppress genuine construction demands —
|
||||
the guard is a question/discussion gate, not an activation blocker."""
|
||||
op, tmp = op
|
||||
op.send_task("fix the broken retry handling in this project")
|
||||
rec = _last_activation(tmp)
|
||||
assert rec["mode"] == "EXISTING_PROJECT_CHANGE", rec
|
||||
assert rec["activated"] is True
|
||||
assert rec.get("intent_layer") is None, rec
|
||||
|
||||
|
||||
def test_15j_native_unknown_probes_without_invention(op):
|
||||
op, tmp = op
|
||||
op.send_task("Build something useful for this")
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
"""Wave 0 interop proof tests (R1 §5): Rust unit callable from tests via the
|
||||
thin Python adapter. Skips when the binary is not built so CI without Rust
|
||||
stays green; build locally with:
|
||||
cargo build --release --quiet (from interop/rebase-proof/)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
import pytest # noqa: E402
|
||||
|
||||
from shared.native_units import PROOF_UNIT, NativeResult, run_native, run_proof # noqa: E402
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not PROOF_UNIT.is_file(), reason="rebase-proof binary not built (cargo build --release in interop/rebase-proof)"
|
||||
)
|
||||
|
||||
|
||||
def test_version_flag_is_mandatory_contract():
|
||||
result = run_proof(["--version"])
|
||||
assert result.ok
|
||||
assert result.exit_code == 0
|
||||
assert result.data is None or result.data == {} # version prints plain text, not JSON
|
||||
assert result.raw_stdout.strip() == "rebase-proof 0.1.0"
|
||||
|
||||
|
||||
def test_sum_happy_path_json_shape():
|
||||
result = run_proof(["sum", "1", "2", "3"])
|
||||
assert result.ok
|
||||
assert result.data == {"ok": True, "op": "sum", "result": 6}
|
||||
|
||||
|
||||
def test_hash_is_deterministic():
|
||||
first = run_proof(["hash", "hello"])
|
||||
second = run_proof(["hash", "hello"])
|
||||
assert first.ok and second.ok
|
||||
assert first.data == second.data
|
||||
assert first.data["fnv1a64"] == "a430d84680aabd0b"
|
||||
|
||||
|
||||
def test_error_op_exits_nonzero_with_json_error():
|
||||
result = run_proof(["fail"])
|
||||
assert not result.ok
|
||||
assert result.exit_code == 2
|
||||
assert result.data == {"ok": False, "error": "deliberate failure"}
|
||||
assert "deliberate failure for adapter proof" in result.stderr
|
||||
|
||||
|
||||
def test_unknown_op_is_data_not_exception():
|
||||
result = run_proof(["no-such-op"])
|
||||
assert not result.ok
|
||||
assert result.exit_code == 2
|
||||
assert "unknown op" in result.data["error"]
|
||||
|
||||
|
||||
def test_timeout_enforcement_kills_unit():
|
||||
result = run_proof(["sleep", "30000"], timeout_s=0.5)
|
||||
assert result.timed_out
|
||||
assert not result.ok
|
||||
assert result.exit_code == -1
|
||||
|
||||
|
||||
def test_missing_binary_raises_adapter_misuse():
|
||||
with pytest.raises(FileNotFoundError):
|
||||
run_native(ROOT / "interop" / "rebase-proof" / "target" / "release" / "does-not-exist", ["sum", "1"])
|
||||
|
||||
|
||||
def test_typed_result_is_the_contract_surface():
|
||||
result = run_proof(["sum", "10", "20"])
|
||||
assert isinstance(result, NativeResult)
|
||||
assert result.duration_ms >= 0
|
||||
assert result.stderr == ""
|
||||
@@ -0,0 +1,131 @@
|
||||
"""JSONL streaming reader for native units (W7 contract gap, rubric §W7 point 5).
|
||||
|
||||
Contract under test: a long-running native unit streams one JSON object per
|
||||
line — ``{"ok":true,"event":...}`` progress objects — and ends with a terminal
|
||||
envelope as the final stdout line. The adapter yields per-line events and
|
||||
validates the terminal envelope. Fixtures are Python scripts standing in for
|
||||
compiled units; the adapter treats any executable path identically.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
import pytest # noqa: E402
|
||||
|
||||
from shared.native_units import NativeResult, stream_native # noqa: E402
|
||||
|
||||
FIXTURE = """\
|
||||
#!/usr/bin/env python3
|
||||
import sys, time
|
||||
|
||||
mode = sys.argv[1] if len(sys.argv) > 1 else "stream"
|
||||
|
||||
if mode == "stream":
|
||||
for i in range(3):
|
||||
print(f'{{"ok":true,"event":"step-{i}"}}', flush=True)
|
||||
time.sleep(0.02)
|
||||
print('{"ok":true,"result":"done"}', flush=True)
|
||||
elif mode == "slow":
|
||||
print('{"ok":true,"event":"started"}', flush=True)
|
||||
time.sleep(30)
|
||||
print('{"ok":true,"result":"done"}', flush=True)
|
||||
elif mode == "bad":
|
||||
print('{"ok":true,"event":"one"}', flush=True)
|
||||
print('not json at all', flush=True)
|
||||
print('{"ok":true,"result":"done"}', flush=True)
|
||||
elif mode == "junk-last":
|
||||
print('{"ok":true,"event":"one"}', flush=True)
|
||||
print('trailing noise', flush=True)
|
||||
elif mode == "fail":
|
||||
print('{"ok":false,"error":"boom"}', flush=True)
|
||||
sys.exit(2)
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def unit(tmp_path: Path) -> Path:
|
||||
script = tmp_path / "stream-unit.py"
|
||||
script.write_text(FIXTURE)
|
||||
script.chmod(0o755)
|
||||
return script
|
||||
|
||||
|
||||
def _split(yielded: list) -> tuple[list[dict], NativeResult]:
|
||||
terminal = yielded[-1]
|
||||
assert isinstance(terminal, NativeResult), f"last yield must be the terminal NativeResult, got {type(terminal)}"
|
||||
events = [item for item in yielded if isinstance(item, dict)]
|
||||
return events, terminal
|
||||
|
||||
|
||||
def test_streaming_yields_events_then_terminal_result(unit: Path):
|
||||
yielded = list(stream_native(unit, ["stream"]))
|
||||
events, terminal = _split(yielded)
|
||||
# 3 progress events + the terminal envelope (also a parsed dict line)
|
||||
assert [e.get("event") for e in events] == ["step-0", "step-1", "step-2", None]
|
||||
assert events[-1] == {"ok": True, "result": "done"}
|
||||
assert terminal.ok
|
||||
assert terminal.exit_code == 0
|
||||
assert terminal.data == {"ok": True, "result": "done"}
|
||||
|
||||
|
||||
def test_events_arrive_before_process_exit(unit: Path):
|
||||
"""Progress is visible DURING the run, not after it — the point of streaming."""
|
||||
seen: list[str] = []
|
||||
for item in stream_native(unit, ["stream"]):
|
||||
if isinstance(item, dict) and "event" in item:
|
||||
seen.append(item["event"])
|
||||
assert seen == ["step-0", "step-1", "step-2"]
|
||||
|
||||
|
||||
def test_timeout_kills_midstream(unit: Path):
|
||||
yielded = list(stream_native(unit, ["slow"], timeout_s=0.5))
|
||||
events, terminal = _split(yielded)
|
||||
assert terminal.timed_out
|
||||
assert not terminal.ok
|
||||
assert terminal.exit_code == -1
|
||||
# the first progress event was still delivered before the kill
|
||||
assert events and events[0] == {"ok": True, "event": "started"}
|
||||
|
||||
|
||||
def test_malformed_interior_lines_skipped(unit: Path):
|
||||
yielded = list(stream_native(unit, ["bad"]))
|
||||
events, terminal = _split(yielded)
|
||||
# the malformed line is skipped; progress + terminal envelope remain
|
||||
progress = [e for e in events if "event" in e]
|
||||
assert [e["event"] for e in progress] == ["one"]
|
||||
assert terminal.ok
|
||||
assert terminal.data == {"ok": True, "result": "done"}
|
||||
|
||||
|
||||
def test_trailing_noise_invalidates_terminal_envelope(unit: Path):
|
||||
"""JSON was emitted, but the FINAL line is not an envelope — contract violation."""
|
||||
yielded = list(stream_native(unit, ["junk-last"]))
|
||||
events, terminal = _split(yielded)
|
||||
assert not terminal.ok
|
||||
assert events and events[0] == {"ok": True, "event": "one"}
|
||||
|
||||
|
||||
def test_failure_envelope_is_data_not_exception(unit: Path):
|
||||
yielded = list(stream_native(unit, ["fail"]))
|
||||
events, terminal = _split(yielded)
|
||||
assert not terminal.ok
|
||||
assert terminal.exit_code == 2
|
||||
assert terminal.data == {"ok": False, "error": "boom"}
|
||||
|
||||
|
||||
def test_events_attached_to_terminal_result(unit: Path):
|
||||
yielded = list(stream_native(unit, ["stream"]))
|
||||
_, terminal = _split(yielded)
|
||||
assert len(terminal.events) == 4 # 3 progress + 1 terminal envelope
|
||||
assert terminal.events[-1] == {"ok": True, "result": "done"}
|
||||
|
||||
|
||||
def test_missing_binary_raises_adapter_misuse(tmp_path: Path):
|
||||
with pytest.raises(FileNotFoundError):
|
||||
list(stream_native(tmp_path / "no-such-binary", ["stream"]))
|
||||
@@ -0,0 +1,147 @@
|
||||
"""R8 fault-injection seam tests: operation-scoped, disabled-by-default,
|
||||
reversible, observable. The seam lives ONLY in notify_event_bridge.py via
|
||||
scripts/r8_fault.py; everything else must be untouched.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
SCRIPTS = Path(__file__).resolve().parent.parent / "scripts"
|
||||
sys.path.insert(0, str(SCRIPTS))
|
||||
r8_fault = importlib.import_module("r8_fault")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def isolated_root(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(r8_fault, "RUNE_WR_ROOT", str(tmp_path))
|
||||
monkeypatch.setattr(r8_fault, "RULES_PATH", tmp_path / "r8_suppress_rules.json")
|
||||
monkeypatch.setattr(r8_fault, "FAULT_LOG", tmp_path / "r8_fault_log.jsonl")
|
||||
return tmp_path
|
||||
|
||||
|
||||
def test_disabled_by_default(isolated_root):
|
||||
# no rule file at all -> no suppression, no crash
|
||||
assert r8_fault.should_suppress("ci-abc") is False
|
||||
assert r8_fault.lookup("ci-abc") is None
|
||||
|
||||
|
||||
def test_operation_scoped(isolated_root):
|
||||
(isolated_root / "r8_suppress_rules.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"enabled": True,
|
||||
"operations": {"ci-target": {"reason": r8_fault.REASON}},
|
||||
}
|
||||
)
|
||||
)
|
||||
assert r8_fault.should_suppress("ci-target") is True
|
||||
# any other operation_id is NEVER affected
|
||||
assert r8_fault.should_suppress("ci-other") is False
|
||||
assert r8_fault.should_suppress("ci-targe") is False
|
||||
assert r8_fault.should_suppress("ci-targetx") is False
|
||||
|
||||
|
||||
def test_disabled_flag_wins(isolated_root):
|
||||
(isolated_root / "r8_suppress_rules.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"enabled": False,
|
||||
"operations": {"ci-target": {"reason": r8_fault.REASON}},
|
||||
}
|
||||
)
|
||||
)
|
||||
assert r8_fault.should_suppress("ci-target") is False
|
||||
|
||||
|
||||
def test_expired_rule_ignored(isolated_root):
|
||||
past = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(time.time() - 10))
|
||||
(isolated_root / "r8_suppress_rules.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"enabled": True,
|
||||
"operations": {"ci-target": {"reason": r8_fault.REASON, "expires_at": past}},
|
||||
}
|
||||
)
|
||||
)
|
||||
assert r8_fault.should_suppress("ci-target") is False
|
||||
|
||||
|
||||
def test_corrupt_rule_file_fails_open(isolated_root):
|
||||
# fail-open to NORMAL delivery — the fault seam must never take the
|
||||
# healthy path down
|
||||
(isolated_root / "r8_suppress_rules.json").write_text("{broken")
|
||||
assert r8_fault.should_suppress("ci-target") is False
|
||||
|
||||
|
||||
def test_evidence_recorded(isolated_root):
|
||||
(isolated_root / "r8_suppress_rules.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"enabled": True,
|
||||
"operations": {"ci-target": {"reason": r8_fault.REASON}},
|
||||
}
|
||||
)
|
||||
)
|
||||
r8_fault.record("ci-target", "suppressed", {"sha": "abc"})
|
||||
log = (isolated_root / "r8_fault_log.jsonl").read_text().strip().splitlines()
|
||||
entry = json.loads(log[-1])
|
||||
assert entry["operation_id"] == "ci-target"
|
||||
assert entry["stage"] == "suppressed"
|
||||
assert entry["reason"] == r8_fault.REASON
|
||||
assert "at" in entry
|
||||
|
||||
|
||||
def test_notify_bridge_suppresses_only_targeted_op(monkeypatch, tmp_path):
|
||||
"""Producer-level test: with an active rule for ci-aaa, main() must
|
||||
write NO completion file for ci-aaa and must NOT POST; a run for
|
||||
ci-bbb with the same rule file still delivers normally."""
|
||||
import completion_file as cf
|
||||
import notify_event_bridge as neb
|
||||
|
||||
wr = tmp_path / "wr"
|
||||
monkeypatch.setenv("RUNE_WR_ROOT", str(wr))
|
||||
importlib.reload(r8_fault)
|
||||
wr.mkdir(parents=True, exist_ok=True)
|
||||
(wr / "r8_suppress_rules.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"enabled": True,
|
||||
"operations": {"ci-aaa": {"reason": r8_fault.REASON}},
|
||||
}
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr(cf, "_wr_bridge", lambda: wr)
|
||||
posted = []
|
||||
monkeypatch.setattr(
|
||||
"urllib.request.urlopen",
|
||||
lambda req, timeout=5: (
|
||||
posted.append(req)
|
||||
or type(
|
||||
"R",
|
||||
(),
|
||||
{"read": lambda s: b'{"matched": 0}', "__enter__": lambda s: s, "__exit__": lambda s, *a: False},
|
||||
)()
|
||||
),
|
||||
)
|
||||
|
||||
# suppressed operation: no file, no POST
|
||||
monkeypatch.setenv("CI_SHA", "aaa")
|
||||
monkeypatch.setenv("CI_RESULT", "success")
|
||||
assert neb.main() == 0
|
||||
assert cf.completion_exists("ci-aaa") is False
|
||||
assert posted == []
|
||||
log = (wr / "r8_fault_log.jsonl").read_text().strip().splitlines()
|
||||
assert json.loads(log[-1])["stage"] == "suppressed"
|
||||
|
||||
# untargeted operation: normal delivery still intact
|
||||
monkeypatch.setenv("CI_SHA", "bbb")
|
||||
assert neb.main() == 0
|
||||
assert cf.completion_exists("ci-bbb") is True
|
||||
assert len(posted) == 1
|
||||
@@ -233,6 +233,22 @@ class TestLifecycleExtended(unittest.TestCase):
|
||||
"""The consolidated helper preserves: task state, durable
|
||||
task_state, outcome event, current-task pointer, error text."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
# Isolation law: the event-bus journal dir is a module-level
|
||||
# constant resolved from the ambient RUNE_HOME at import time
|
||||
# (memory_env.memory_dir() → hardcoded default). Without
|
||||
# pinning it here, the test reads whatever journal the host
|
||||
# resolves to — on a CI runner the default path is
|
||||
# unwritable/nonexistent, emit()'s deliberate degradation
|
||||
# swallows the write, and the scan below finds nothing.
|
||||
from rune import event_bus as _eb
|
||||
orig_journal = _eb.JOURNAL_DIR
|
||||
orig_event_log = _eb.EVENT_LOG
|
||||
journal_dir = Path(tmp) / "journal"
|
||||
_eb.JOURNAL_DIR = str(journal_dir)
|
||||
_eb.EVENT_LOG = str(journal_dir / "events.jsonl")
|
||||
self.addCleanup(setattr, _eb, "JOURNAL_DIR", orig_journal)
|
||||
self.addCleanup(setattr, _eb, "EVENT_LOG", orig_event_log)
|
||||
|
||||
op = self._make_op("execute", tmp)
|
||||
result = op.send_task("Fix the failing test in tests/test_x.py")
|
||||
task_id = result["task"]["task_id"]
|
||||
@@ -242,8 +258,6 @@ class TestLifecycleExtended(unittest.TestCase):
|
||||
self.assertTrue(events_path.exists())
|
||||
# task.outcome rides the event_bus journal (memory_dir/journal),
|
||||
# not the operator's task-transition events.jsonl.
|
||||
from rune import event_bus as _eb
|
||||
journal_dir = Path(_eb.JOURNAL_DIR)
|
||||
outcomes = []
|
||||
if journal_dir.exists():
|
||||
for j in journal_dir.glob("*.jsonl"):
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
"""test_tool_parity.py — TTY-repair tranche: canonical tool hash parity.
|
||||
The installed MiMo tools MUST match the canonical sources
|
||||
(same contract as test_hook_parity for hooks)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
TOOLS = ("bash.ts", "await-operation.ts")
|
||||
|
||||
|
||||
def _canonical(name: str) -> Path:
|
||||
return REPO / "config" / "mimo-tools" / name
|
||||
|
||||
|
||||
def _installed(name: str) -> Path:
|
||||
home = os.environ.get("RUNE_HOOK_TARGET_HOME", "/home/nick")
|
||||
return Path(home) / ".mimocode" / "tools" / name
|
||||
|
||||
|
||||
def _sha(p: Path) -> str:
|
||||
return hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def test_canonical_sources_exist():
|
||||
for name in TOOLS:
|
||||
assert _canonical(name).is_file(), f"missing canonical {name}"
|
||||
|
||||
|
||||
def test_installed_matches_canonical():
|
||||
for name in TOOLS:
|
||||
inst = _installed(name)
|
||||
assert inst.is_file(), f"tool missing at {inst}"
|
||||
assert _sha(_canonical(name)) == _sha(inst), (
|
||||
f"TOOL DRIFT: {name} canonical={_sha(_canonical(name))[:12]} "
|
||||
f"installed={_sha(inst)[:12]} — run "
|
||||
f"python3 scripts/install_mimo_tools.py to sync"
|
||||
)
|
||||
|
||||
|
||||
def test_installer_exists():
|
||||
assert (REPO / "scripts/install_mimo_tools.py").is_file()
|
||||
Reference in new issue
Block a user