From 4f527a4138ea0fc4af3dc23b77eb7a3d862bbd05 Mon Sep 17 00:00:00 2001 From: Suresh Kasipandy Date: Sat, 16 May 2026 21:33:44 -0400 Subject: [PATCH 1/2] Fix codex exec worker invocation for codex-cli 0.130.0 codex-cli 0.130.0 'codex exec' has no --ask-for-approval flag; approval policy is a config override. Use -c approval_policy=on-request (with -c approvals_reviewer=auto_review) so workers self-unblock without an interactive approver. Sync the canonical command in .codex/DELEGATION.md. Found because the first real worker delegation failed: 'unexpected argument --ask-for-approval'. --- .codex/DELEGATION.md | 2 +- scripts/codex-run.sh | 5 ++++- tsconfig.tsbuildinfo | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 tsconfig.tsbuildinfo diff --git a/.codex/DELEGATION.md b/.codex/DELEGATION.md index 52ff3c8..4f5f049 100644 --- a/.codex/DELEGATION.md +++ b/.codex/DELEGATION.md @@ -42,7 +42,7 @@ codex exec --json --sandbox read-only \ ```bash codex exec --json --sandbox workspace-write \ - --ask-for-approval on-request \ + -c approval_policy="on-request" \ -c approvals_reviewer=auto_review \ -c sandbox_workspace_write.network_access=false \ -c model="$CODEX_MODEL" \ diff --git a/scripts/codex-run.sh b/scripts/codex-run.sh index d580941..5b260aa 100755 --- a/scripts/codex-run.sh +++ b/scripts/codex-run.sh @@ -44,8 +44,11 @@ if [ "$ROLE" = "explorer" ]; then -c model="$CODEX_MODEL" \ --output-schema "$SCHEMA" -o "$RUN/result.json" "$(cat "$RUN/task.md")" else + # codex-cli `exec` has no --ask-for-approval flag; approval policy is a + # config override. on-request + auto_review lets it self-unblock without + # an interactive approver. Sandbox stays workspace-write, network off. set -- codex exec --json --sandbox workspace-write \ - --ask-for-approval on-request \ + -c approval_policy="on-request" \ -c approvals_reviewer=auto_review \ -c sandbox_workspace_write.network_access=false \ -c model="$CODEX_MODEL" \ diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo deleted file mode 100644 index 1353151..0000000 --- a/tsconfig.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"root":["./src/app.tsx","./src/main.tsx","./src/store.ts","./src/narrator/heuristic.ts","./src/narrator/llm.ts","./src/render/worldcanvas.tsx","./src/render/palette.ts","./src/sim/config.ts","./src/sim/events.ts","./src/sim/genome.ts","./src/sim/history.ts","./src/sim/phylogeny.ts","./src/sim/protocol.ts","./src/sim/rng.ts","./src/sim/sim.test.ts","./src/sim/simulation.ts","./src/sim/spatial.ts","./src/sim/speciation.ts","./src/sim/stats.ts","./src/sim/types.ts","./src/sim/worker.ts","./src/sim/world.ts","./src/ui/controls.tsx","./src/ui/creatureinspector.tsx","./src/ui/eventslog.tsx","./src/ui/narratorpanel.tsx","./src/ui/phylogeny.tsx","./src/ui/shockpanel.tsx","./src/ui/statspanel.tsx","./src/ui/timeline.tsx","./scripts/headless.ts","./scripts/inspect.ts","./scripts/narrator-server.ts","./scripts/lib/dashboard.ts","./scripts/lib/font.ts","./scripts/lib/phylo.ts","./scripts/lib/png.ts","./scripts/lib/render.ts","./vite.config.ts"],"version":"5.9.3"} \ No newline at end of file From 81937f2a0525f8d4125190d1540bcf5de1b5f603 Mon Sep 17 00:00:00 2001 From: Suresh Kasipandy Date: Sat, 16 May 2026 21:33:44 -0400 Subject: [PATCH 2/2] Add computePhylogeny unit tests; untrack tsbuildinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First real Codex-exec worker delegation: tests for the previously untested pure module src/sim/phylogeny.ts — empty input, minPeak filtering, relink-through-pruned-ancestor, alive/extinct, maxNodes significance cap, row/t0 invariants. Independently verified: npx tsc -b clean, npx vitest run 15/15 green (incl. determinism). Also gitignore + untrack tsconfig.tsbuildinfo (build cache, was tracked). --- .gitignore | 3 + src/sim/phylogeny.test.ts | 122 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/sim/phylogeny.test.ts diff --git a/.gitignore b/.gitignore index 7a28f25..9906785 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ inspect/ # Codex exec run packets (external-subagent transcripts) .codex-runs/ + +# TypeScript incremental build cache +*.tsbuildinfo diff --git a/src/sim/phylogeny.test.ts b/src/sim/phylogeny.test.ts new file mode 100644 index 0000000..9984c20 --- /dev/null +++ b/src/sim/phylogeny.test.ts @@ -0,0 +1,122 @@ +import { describe, expect, it } from "vitest"; +import { computePhylogeny } from "./phylogeny"; +import type { Species } from "./types"; + +describe("computePhylogeny", () => { + const species = (values: Partial): Species => ({ + id: values.id ?? 1, + parentId: values.parentId ?? null, + color: values.color ?? "#000000", + centroid: values.centroid ?? ({} as any), + bornTick: values.bornTick ?? 0, + population: values.population ?? 10, + peakPopulation: values.peakPopulation ?? 10, + ...values, + }); + + it("returns empty layout for empty input", () => { + const result = computePhylogeny({}, 1234); + + expect(result.nodes).toEqual([]); + expect(result.links).toEqual([]); + expect(result.rows).toBe(1); + expect(result.t0).toBe(0); + }); + + it("filters out species with peakPopulation below minPeak", () => { + const speciesById: Record = { + 1: species({ id: 1, parentId: null, peakPopulation: 5 }), + 2: species({ id: 2, parentId: 1, peakPopulation: 9 }), + 3: species({ id: 3, parentId: 1, peakPopulation: 11 }), + }; + + const result = computePhylogeny(speciesById, 100, { minPeak: 10 }); + + const ids = result.nodes.map((n) => n.id); + expect(ids).toEqual([3]); + }); + + it("relinks through pruned intermediates to nearest kept ancestor", () => { + const speciesById: Record = { + 1: species({ id: 1, parentId: null, peakPopulation: 20 }), + 2: species({ id: 2, parentId: 1, peakPopulation: 4 }), + 3: species({ id: 3, parentId: 2, peakPopulation: 30 }), + }; + + const result = computePhylogeny(speciesById, 100, { minPeak: 10 }); + const keptNode = result.nodes.find((n) => n.id === 3); + + expect(keptNode?.parentId).toBe(1); + + const linksForNode = result.links.filter((l) => l.child.id === 3); + expect(linksForNode).toHaveLength(1); + expect(linksForNode[0]?.parent.id).toBe(1); + }); + + it("sets alive false when extinctTick is present", () => { + const speciesById: Record = { + 1: species({ + id: 1, + parentId: null, + peakPopulation: 20, + extinctTick: 3, + population: 8, + }), + 2: species({ + id: 2, + parentId: 1, + peakPopulation: 20, + extinctTick: undefined, + population: 12, + }), + }; + + const result = computePhylogeny(speciesById, 50); + const extinct = result.nodes.find((n) => n.id === 1); + const alive = result.nodes.find((n) => n.id === 2); + + expect(extinct?.alive).toBe(false); + expect(extinct?.endTick).toBe(3); + expect(alive?.alive).toBe(true); + expect(alive?.endTick).toBe(50); + }); + + it("keeps the most significant lineages when maxNodes is hit", () => { + const speciesById: Record = { + 1: species({ id: 1, peakPopulation: 5 }), + 2: species({ id: 2, peakPopulation: 50 }), + 3: species({ id: 3, peakPopulation: 30 }), + 4: species({ id: 4, peakPopulation: 20 }), + 5: species({ id: 5, peakPopulation: 15 }), + 6: species({ id: 6, peakPopulation: 10 }), + }; + + const result = computePhylogeny(speciesById, 20, { + minPeak: 0, + maxNodes: 3, + }); + + const ids = new Set(result.nodes.map((n) => n.id)); + expect(result.nodes).toHaveLength(3); + expect(ids.has(2)).toBe(true); + expect(ids.has(3)).toBe(true); + expect(ids.has(4)).toBe(true); + }); + + it("assigns unique rows and computes t0 with bornTick bounds", () => { + const speciesById: Record = { + 1: species({ id: 1, parentId: null, bornTick: 10, peakPopulation: 100 }), + 2: species({ id: 2, parentId: 1, bornTick: 0, peakPopulation: 90 }), + 3: species({ id: 3, parentId: 1, bornTick: 5, peakPopulation: 80 }), + 4: species({ id: 4, parentId: 2, bornTick: -5, peakPopulation: 70 }), + }; + + const result = computePhylogeny(speciesById, 20, { minPeak: 0 }); + + const rows = result.nodes.map((n) => n.row); + const uniqueRows = new Set(rows); + expect(uniqueRows.size).toBe(result.nodes.length); + expect(result.rows).toBe(result.nodes.length); + expect(result.t0).toBeLessThanOrEqual(-5); + }); +});