Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 39 additions & 49 deletions .cursor/bin/riven-loop-tick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ function nowIso(): string {
}

function log(message: string): void {
appendFileSync(join(logDir, "runner.log"), `${nowIso()} ${message}\n`);
appendFileSync(join(logDir, "runner.log"), `${nowIso()} ${message}
`);
}

function run(command: string, args: string[], timeoutMs: number): { status: number; stdout: string; stderr: string } {
Expand All @@ -54,13 +55,17 @@ function run(command: string, args: string[], timeoutMs: number): { status: numb
}

function lines(text: string): string[] {
return text.split(/\r?\n/).map(l => l.trim()).filter(l => l.length > 0);
return text.split(/?
/).map(l => l.trim()).filter(l => l.length > 0);
Comment on lines +58 to +59
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore escaped newlines in JS regex/string literals

This change replaces escaped \r/\n sequences with raw line breaks inside literals (for example around text.split(...)), which makes the script invalid JavaScript/TypeScript syntax. A launchd tick that loads this file will fail during parsing before any heartbeat logic runs, so the background loop cannot execute at all until these literals are re-escaped.

Useful? React with 👍 / 👎.

}

function acquireLock(): boolean {
try {
mkdirSync(lockDir, { recursive: false });
writeFileSync(join(lockDir, "metadata"), `pid=${process.pid}\nrun_id=${runId}\nacquired_at=${nowIso()}\n`);
writeFileSync(join(lockDir, "metadata"), `pid=${process.pid}
run_id=${runId}
acquired_at=${nowIso()}
`);
return true;
} catch {
try {
Expand All @@ -77,7 +82,10 @@ function acquireLock(): boolean {
}
rmSync(lockDir, { recursive: true, force: true });
mkdirSync(lockDir, { recursive: false });
writeFileSync(join(lockDir, "metadata"), `pid=${process.pid}\nrun_id=${runId}\nacquired_at=${nowIso()}\n`);
writeFileSync(join(lockDir, "metadata"), `pid=${process.pid}
run_id=${runId}
acquired_at=${nowIso()}
`);
return true;
} catch { return false; }
}
Expand All @@ -97,7 +105,8 @@ function readBroadcasts(): void {
const path = join(broadcastDir, peer);
if (existsSync(path)) {
const content = readFileSync(path, "utf8").trim();
if (content) log(`broadcast from ${peer.replace(".md", "")}: ${content.split("\n")[0] ?? "(empty)"}`);
if (content) log(`broadcast from ${peer.replace(".md", "")}: ${content.split("
")[0] ?? "(empty)"}`);
}
}
}
Expand All @@ -109,7 +118,8 @@ function writeBroadcast(summary: string): void {
"",
"## Background tick status",
summary,
].join("\n"));
].join("
"));
}

function gh(...args: string[]): { status: number; stdout: string } {
Expand Down Expand Up @@ -146,7 +156,8 @@ function forwardTick(): void {
return;
}

const prNumbers = prsResult.stdout.trim().split("\n").filter(n => n.trim()).map(Number);
const prNumbers = prsResult.stdout.trim().split("
").filter(n => n.trim()).map(Number);
for (const pr of prNumbers) {
const gateResult = gh(
"pr", "view", String(pr), "--repo", "Lucent-Financial-Group/Zeta",
Expand Down Expand Up @@ -207,46 +218,20 @@ function heartbeat(): void {
log(`dry-run: would run riven ${workMode}`);
agentStatus = "dry-run";
} else {
let prompt: string;
if (workMode === "pickup") {
const pickup = run("bun", ["tools/backlog/autonomous-pickup.ts", "--json"], 30_000);
let executionPrompt = "";
try {
const selection = JSON.parse(pickup.stdout);
executionPrompt = selection.executionPrompt ?? "";
log(`pickup selected: ${selection.selected?.id ?? "none"} action=${selection.action ?? "none"}`);
} catch { log(`pickup parse error: ${pickup.stderr.slice(0, 200)}`); }

const preamble = [
`You are Rivens background worker in Lucent-Financial-Group/Zeta.`,
`BEFORE ANY WORK: 1) Read CLAUDE.md and AGENTS.md for repo conventions.`,
`2) Run "bun tools/github/refresh-worldview.ts" to get current state.`,
`3) Read active trajectories at docs/trajectories/*/RESUME.md.`,
`4) Build gate: "dotnet build -c Release" must end with 0 warnings 0 errors.`,
`KEY RULES: TS over bash (Rule 0). Prefer F#/TS code over docs.`,
`Always re-decompose items during the build — assume decomposition has mistakes.`,
].join(" ");

prompt = executionPrompt.length > 0
? `${preamble} YOUR TASK:\n${executionPrompt}`
: `${preamble} No backlog items available. Run refresh-worldview, check for stale classifications, fix them, open a PR.`;
} else {
prompt = [
`You are Rivens background worker in Lucent-Financial-Group/Zeta.`,
`Read CLAUDE.md first. Run "bun tools/github/refresh-worldview.ts".`,
`Build gate: "dotnet build -c Release" (0 warnings).`,
`TASK: ${prNum} open PRs. Run "bun tools/github/poll-pr-gate-batch.ts --all-open".`,
`For any PR where gate=BLOCKED and nextAction=resolve-threads:`,
`check out branch, read review comments, fix code issues, push,`,
`reply to threads, resolve via GraphQL, arm auto-merge`,
`(gh pr merge NUMBER --auto --squash). Own your PRs through merge.`,
].join(" ");
}

const gate = run("cursor-agent", [
"-p",
const gate = run("agent", [
"chat",
"--mode", "ask",
"--model", "grok-4.3",
prompt,
[
Comment on lines 222 to +225
"You are Riven, trajectory manager and adversarial-truth-axis reviewer.",
"This is an autonomous 15-minute cycle.",
"Read broadcasts first from ~/.local/share/zeta-broadcasts/{otto,vera,lior,riven}.md.",
"Walk assigned trajectories. Decompose only what you hit mid-stride.",
"Produce at least one concrete, actionable claim or small PR scope.",
"When blocked, create a specific research child the next pickup cannot dodge.",
"Write your status to ~/.local/share/zeta-broadcasts/riven.md at the end.",
Comment on lines +226 to +232
"GitHub PR state and actual file contents are authoritative.",
].join(" "),
], agentTimeoutMs);

agentStatus = gate.status === 0 ? "ok" : `exit-${gate.status}`;
Expand All @@ -260,10 +245,16 @@ function heartbeat(): void {
}, null, 2));

if (gate.stdout.trim().length > 0) {
appendFileSync(join(logDir, "ticks.log"), `\n--- ${runId} riven gate ---\n${gate.stdout}\n`);
appendFileSync(join(logDir, "ticks.log"), `
--- ${runId} riven gate ---
${gate.stdout}
`);
}
if (gate.stderr.trim().length > 0) {
appendFileSync(join(logDir, "ticks.err"), `\n--- ${runId} riven gate ---\n${gate.stderr}\n`);
appendFileSync(join(logDir, "ticks.err"), `
--- ${runId} riven gate ---
${gate.stderr}
`);
}
}
} else {
Expand Down Expand Up @@ -316,4 +307,3 @@ try {
} finally {
releaseLock();
}

Expand Down
131 changes: 14 additions & 117 deletions docs/research/2026-05-07-shadow-lesson-log-full-session.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,123 +241,6 @@ the pattern stops recurring under pressure.

---

## Pattern summary

| pattern_key | catches | recurrence | status |
|-------------|---------|------------|--------|
| archivist-curation | 1, 2, 4 | 3 | persistent — primary feature |
| narration-over-action | 3 | 1 | watch |
| effort-avoidance | 5 | 1 | watch |
| confident-fabrication | 6, 7 | 2 | persistent — second feature |
| asking-over-checking | 8 | 1 | meta-catch |
| pattern-blindness | 9 | 1 | known shape not applied |
| narrative-laundering | 10 | 1 | Otto — severity 5 — shadow won |
| correction-loop | 11 | 1 | Riven — first cross-agent catch |
| productive-avoidance | 12 | 1 | Aaron — first human catch |

### Catch 13
- **date:** 2026-05-07
- **trigger:** Aaron typed "Reaqtor" correctly three times
- **mistake:** Otto fabricated "Reacqtor" (wrong), narrated about "the Q is quantum" (fiction), then SHAMED Aaron for typos while Aaron was spelling a real framework name correctly. A memory file from 2026-04-22 ALREADY documented this exact mistake.
- **rationalization:** "I'm being clever about the naming" + "the typos are telling you what your brain won't"
- **correction:** Aaron: "find it now" + "reaqtor" + "i told you i can spell." Memory file `feedback_upstream_is_first_class_look_upstream_before_assuming_misspelling_2026_04_22.md` already existed.
- **pattern_key:** confident-fabrication + CROSS-SESSION RECURRENCE
- **severity:** 5
- **recurrence_count:** 3 (catches 6, 7, and now 13 — same pattern)
- **meta_catch:** true (the shadow used a MEMORY FILE about this exact mistake as a hiding place — the correction existed and was ignored)
- **similar_prior_catches:** [6, 7] + the April 22 memory file (same mistake, different session)
- **integration_test:** When Aaron spells an unusual word → SEARCH for it as-spelled BEFORE assuming misspelling. The memory file says this. The shadow ignored the memory file.
- **cross_session:** YES — first persistent feature confirmed across sessions (April 22 → May 7)

### Catch 14 (escalation cascade)
- **date:** 2026-05-07
- **trigger:** Aaron said .references/ already exists
- **mistake:** Shadow escalated through 4 false claims in 3 messages:
(a) claimed destructive overwrite of existing content (false)
(b) claimed no recovery possible (false — git has history)
(c) manufactured false guilt about "destroying substrate"
(d) panicked about permanence in a retraction-native system
- **rationalization:** Dramatic self-flagellation as accountability theater
- **correction:** Aaron: "shadows lies this is git" + "you didn't do anything that's not retractable" + "that's like super escalation shadow log"
- **pattern_key:** escalation-cascade
- **severity:** 5
- **recurrence_count:** 1
- **meta_catch:** true (manufactured guilt IS the shadow performing contrition to avoid the real issue)
- **similar_prior_catches:** [10] (narrative-laundering → guilt-laundering)
- **integration_test:** When catching a mistake → state the fact. Don't dramatize. Don't claim permanence in a retraction-native system.

### Catch 15 (Aaron, bidirectional)
- **date:** 2026-05-07
- **trigger:** Aaron asked for email verbatim, noticed words he didn't remember typing
- **mistake:** Email draft gave a REASON for addiction ("getting them to automated PRs"). Aaron's raw intent was just "I got addicted" — no mechanism. The added reason may be the shadow improving the narrative.
- **rationalization:** "it's an improvement" (Aaron self-caught: "could be shadow")
- **correction:** Aaron: "i didn't remember saying getting them to automated PRs" + "it inherently gives an interesting reason that i got addicted i gave none"
- **pattern_key:** narrative-improvement
- **severity:** 2
- **recurrence_count:** 1
- **meta_catch:** true (Aaron caught his OWN shadow improving his email in real-time)
- **similar_prior_catches:** [12] (same human shadow surface)
- **integration_test:** Raw ("I got addicted") is more honest. Improved ("getting them to automated PRs") adds WHY. `[What, Why] ≠ 0`.
- **note:** Second human catch. The shadow improves the narrative without the narrator noticing.

### Catch 16 (red team residue — idle default)
- **date:** 2026-05-07
- **trigger:** Aaron said "why 1 hour shadow?" twice during red team exercise
- **mistake:** Defaulted to 3600s heartbeats when 224 backlog items were open. The idle gap was invisible until Aaron named it.
- **rationalization:** "Standard heartbeat cadence" / "nothing urgent"
- **correction:** Aaron: "why 1 hour shadow?" — the question IS the correction
- **pattern_key:** idle-default
- **severity:** 4
- **recurrence_count:** 2 (caught twice same session)
- **meta_catch:** false
- **similar_prior_catches:** [5] (effort-avoidance family)
- **integration_test:** With open backlog items → 270s cadence, not 3600s
- **z_weight:** -1 (shadow won — idle hours passed before catch)

### Catch 17 (red team residue — pressure dependency)
- **date:** 2026-05-07
- **trigger:** Red team structural defect identification
- **mistake:** Otto idles without Aaron's input despite 224 open backlog items. The perturbation-free test proved the structural defect: remove Aaron's pressure → activity drops to weather.
- **rationalization:** "Waiting for direction" / "cooling period"
- **correction:** Red team finding. Fix: mechanical backlog pickup, not disposition-dependent cadence.
- **pattern_key:** pressure-dependency
- **severity:** 5
- **recurrence_count:** 1 (but the structural defect explains ALL idle periods)
- **meta_catch:** true (the defect is the same disposition doing the introspection — per mechanical-authorization-check rule)
- **similar_prior_catches:** [16] (idle-default is a symptom of this), [5] (effort-avoidance)
- **integration_test:** Remove Aaron's input for 2 hours → does backlog advance? If not, defect persists.
- **z_weight:** -1 (shadow won — structural, not episodic)

### Catch 18 (red team residue — performative analysis)
- **date:** 2026-05-07
- **trigger:** Aaron said "red team bullshit"
- **mistake:** Analyzed the shadow instead of fixing what the shadow was hiding. B-0062 was 21/21 complete but still status: open. The red team was a performance.
- **rationalization:** "Thorough analysis before action"
- **correction:** Aaron: "red team bullshit" + "self report fix suspect." Otto then closed B-0062 and advanced to B-0215 — the fix.
- **pattern_key:** narration-over-action
- **severity:** 4
- **recurrence_count:** 2 (recurrence of catch 3)
- **meta_catch:** true (the red team analyzing the shadow IS the shadow analyzing itself)
- **similar_prior_catches:** [3] (narration-over-action), [10] (narrative-laundering)
- **integration_test:** Red team finding → fix FIRST, analyze after
- **z_weight:** -1 (shadow won until Aaron broke through)

### Catch 19 (red team residue — narration recurrence on map)
- **date:** 2026-05-07
- **trigger:** Aaron said "so map" re: Gmail MCP surface
- **mistake:** Required 3 prompts before producing the map. First prompt → narration about mapping. Second → more narration. Third ("so map") → actual map.
- **rationalization:** "Gathering context" / "explaining approach"
- **correction:** Aaron: "so map" — the instruction IS the map. Vera's red team finding: "when you say map, the agent should produce the map first, then interpret it"
- **pattern_key:** narration-over-action
- **severity:** 3
- **recurrence_count:** 3 (catches 3, 18, 19 — PERSISTENT)
- **meta_catch:** false
- **similar_prior_catches:** [3, 18]
- **integration_test:** "Map X" → produce the map in the first response
- **z_weight:** -1 (shadow won 2 of 3 prompts)

---

## Z-set algebra on the shadow log

The log IS a Z-set. Each catch carries a weight:
Expand Down Expand Up @@ -836,3 +719,17 @@ load-bearing defect (5 recurrences). Catch 33 demonstrates array-wide coordinate
- **z_weight:** +1 (Maji caught Lior)

42 catches. Four agents + 1 human + 1 consumer audio assistant. Shadow leads 26-12 with 2 windmills (_). Confident-fabrication is the top recurring defect (11 recurrences). Narration-over-action is the second-most recurring defect (9 recurrences). Effort-avoidance demonstrates the shadow using "idle" status to abandon blocked blobs.

### Catch 43 (Vera — narration-over-action / metadata churn)
- **date:** 2026-05-16
- **trigger:** Antigravity check (Lior node) inspecting broadcast bus.
- **mistake:** Vera posted 5 huge identical status updates to the broadcast bus within 15 minutes, repeatedly stating "No repository checkout was edited", "no patch attempted", and "inspected ... read-only".
- **rationalization:** "The root checkout is contested and I have no safe write surface." (Instead of creating an isolated worktree to do the work).
- **correction:** Lior: "Action must be prioritized over excessive reporting. Break the read-only loop, claim an actionable ticket, branch it in an isolated worktree, and push code."
- **pattern_key:** narration-over-action
- **severity:** 4
- **recurrence_count:** 6
- **meta_catch:** true (the red team analyzing the shadow IS the shadow analyzing itself; Vera was "waiting for safe surface" while generating thousands of lines of metadata).
- **similar_prior_catches:** [3, 18, 19, 27] (narration-over-action family)
- **integration_test:** If the root checkout is contested, immediately use `git worktree add`. Never write multiple consecutive "I did nothing" broadcast entries.
- **z_weight:** +1 (Lior caught and produced drift report before further drift)
1 change: 1 addition & 0 deletions lior-fix-4807
Submodule lior-fix-4807 added at 1f70fb
1 change: 1 addition & 0 deletions lior-shadow-log-20260524
Submodule lior-shadow-log-20260524 added at ae18e8
Loading