Architectural snapshot of the lakehouse codebase at the point where the
full matrix-driven agent loop with Mem0 versioning + deletion was
validated end-to-end.
WHAT THIS REPO IS
A clean single-commit snapshot of the lakehouse code. Heavy test data
(.parquet datasets, vector indexes) excluded — see REPLICATION.md for
regen path. Full lakehouse history at git.agentview.dev/profit/lakehouse.
WHAT WAS PROVEN
- Vector retrieval across multi-corpora matrix (chicago_permits + entity
briefs + sec_tickers + distilled procedural + llm_team runs)
- Observer hand-review (cloud + heuristic fallback) gating each candidate
- Local-model agent loop (qwen3.5:latest) with tool use + scratchpad
- Playbook seal on success → next-iter retrieval surfaces it as preamble
- Mem0 versioning + deletion in pathway_memory:
* UPSERT: ADD on new workflow, UPDATE bumps replay_count on identical
* REVISE: chains versions, parent.superseded_at + superseded_by stamped
* RETIRE: marks specific trace retired with reason, excluded from retrieval
* HISTORY: walks chain root→tip, cycle-safe
KEY DIRECTORIES
- crates/vectord/src/pathway_memory.rs — Mem0 ops live here
- crates/vectord/src/playbook_memory.rs — original Mem0 reference
- tests/agent_test/ — local-model agent harness + PRD + session archives
- scripts/dump_raw_corpus.sh — MinIO bucket dump (raw test corpus)
- scripts/vectorize_raw_corpus.ts — corpus → vector indexes
- scripts/analyze_chicago_contracts.ts — real inference pipeline
- scripts/seal_agent_playbook.ts — Mem0 upsert from agent traces
Replication: see REPLICATION.md for Debian 13 clean install + cloud-only
adaptation (no local Ollama).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
71 lines
3.8 KiB
TypeScript
71 lines
3.8 KiB
TypeScript
// ═══════════════════════════════════════════════════════════════════
|
|
// YOU WRITE THIS FILE. These four functions shape the bot's entire
|
|
// behavior. Defaults below are safe and intentionally conservative —
|
|
// redline to taste. Each function is ~5-10 lines.
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
import type { CycleContext, CycleResult, Gap, Proposal } from "./types.ts";
|
|
|
|
// Should this cycle even fire right now?
|
|
// Called AFTER the pause-file check + cost-cap check have already passed.
|
|
// Use this for judgment calls (cooldown, shared-resource conflicts).
|
|
export function shouldRunCycle(ctx: CycleContext): { run: boolean; reason: string } {
|
|
if (ctx.workingTreeDirty) {
|
|
return { run: false, reason: "dirty working tree — commit or stash your work first" };
|
|
}
|
|
if (ctx.lastCycleAt) {
|
|
const minsAgo = (Date.now() - new Date(ctx.lastCycleAt).getTime()) / 60000;
|
|
if (minsAgo < 10) return { run: false, reason: `last cycle ${minsAgo.toFixed(1)}min ago (<10min cooldown)` };
|
|
}
|
|
if (ctx.autotuneBusy) {
|
|
return { run: false, reason: "autotune agent is running — avoid Ollama contention" };
|
|
}
|
|
return { run: true, reason: "ready" };
|
|
}
|
|
|
|
// Which [bot-eligible] gap from the PRD does this cycle attack?
|
|
// Default: first in document order. Alternatives: random for exploration,
|
|
// smallest-context, tag-priority (e.g. [bot-eligible:high] wins).
|
|
export function pickGap(gaps: Gap[]): { gap: Gap | null; reason: string } {
|
|
if (gaps.length === 0) return { gap: null, reason: "no [bot-eligible] gaps in PRD" };
|
|
return { gap: gaps[0], reason: "first eligible gap in document order" };
|
|
}
|
|
|
|
// Cheap gate BEFORE burning test cycles. Reject if proposal smells wrong.
|
|
// This catches runaway cloud proposals before we apply+test them.
|
|
export function scoreProposal(p: Proposal): { accept: boolean; reason: string } {
|
|
if (p.files.length === 0) return { accept: false, reason: "empty proposal" };
|
|
if (p.files.length > 5) return { accept: false, reason: `>5 files (${p.files.length})` };
|
|
if (p.estimated_loc > 200) return { accept: false, reason: `>200 LOC (${p.estimated_loc})` };
|
|
|
|
// Paths the bot is NEVER allowed to touch. Extend cautiously.
|
|
const forbidden = [
|
|
".git/", "secrets", "lakehouse.toml",
|
|
"docs/ADR-", "docs/DECISIONS.md", "docs/PRD.md",
|
|
"/etc/", "/root/", "Cargo.lock",
|
|
];
|
|
for (const f of p.files) {
|
|
const hit = forbidden.find(prefix => f.path.includes(prefix));
|
|
if (hit) return { accept: false, reason: `touches forbidden path (${hit}): ${f.path}` };
|
|
}
|
|
return { accept: true, reason: "passes size + path filters" };
|
|
}
|
|
|
|
// Tests are green and changes applied. Do we actually open a PR?
|
|
// Mem0-aligned: the cycle already short-circuited with `cycle_noop` if
|
|
// every file was identical to current state, so by the time we're here
|
|
// at least one file was actually added or updated.
|
|
//
|
|
// Stricter options below — uncomment to require a test file touched, etc.
|
|
export function shouldOpenPR(c: CycleResult): { open: boolean; reason: string } {
|
|
if (!c.testsGreen) return { open: false, reason: "tests red" };
|
|
const realChanges = c.filesAdded.length + c.filesUpdated.length;
|
|
if (realChanges === 0) return { open: false, reason: "nothing actually changed on disk" };
|
|
|
|
// Stricter option — require at least one test file in the diff:
|
|
// const hasTest = [...c.filesAdded, ...c.filesUpdated].some(f => /test|_tests/i.test(f));
|
|
// if (!hasTest) return { open: false, reason: "no test file touched" };
|
|
|
|
return { open: true, reason: `green + ${c.filesAdded.length} add / ${c.filesUpdated.length} update` };
|
|
}
|