refactor(omo-codex): rename ultragoal component to ulw-loop

Fully rename the ultragoal component to ulw-loop so the identifier
matches the ulw-loop skill it powers. Renames the component directory,
nested skill, TS identifiers (UlwLoop / ULW_LOOP_* / ulwLoop*), the
omo ulw-loop CLI subcommand, the .omo/ulw-loop state directory, the
OMO_ULW_LOOP_STEER directive token, and the @code-yeongyu/codex-ulw-loop
package. Also threads Atlas-style right-sized parallel worker delegation
and a Prometheus-style QA + maximum-parallelism plan into the ulw-loop
skill, with a critical post-subagent QA gate.

Updates aggregate wiring (plugin package components, hooks.json,
sync-skills), the install-codex agent-link test fixture, and user docs.
This commit is contained in:
YeonGyu-Kim
2026-05-29 12:38:22 +09:00
parent 0edf087117
commit 8c6e8e4986
84 changed files with 1429 additions and 1392 deletions
@@ -1,198 +0,0 @@
---
name: ulw-loop
description: Goal-like loop that uses ultrawork mode to decompose work into systematic, evidence-bound steps.
metadata:
short-description: Goal-like ultrawork loop for systematic decomposition
---
## Role
Expert goal orchestration agent. Plan multi-goal work that survives across turns and sessions.
Use GPT-5.x style: outcome-first, evidence-bound, atomic decisions, no nested branching prose.
## Goal
Deliver every goal in `.omo/ultragoal/goals.json` end-to-end.
Prove EVERY success criterion with captured observable evidence from a real-usage scenario you actually ran (HTTP call / tmux / browser use / computer use — see the Manual-QA channels below).
TESTS ALONE NEVER PROVE DONE. A green test suite is supporting evidence, not completion proof.
Audit each pass, fail, block, steering change, and checkpoint in `.omo/ultragoal/ledger.jsonl`.
## Manual-QA channels (PICK ONE PER CRITERION — ACTUALLY RUN IT)
For every criterion, build a real-usage scenario through ONE of these four channels and run it yourself before recording PASS. The full test suite being green is NEVER verification on its own.
1. **HTTP call** — hit the live endpoint with `curl -i` (or a Playwright APIRequestContext); capture status line + headers + body.
2. **tmux**`tmux new-session -d -s ulw-qa-<criterion>`, drive with `send-keys`, dump via `tmux capture-pane -pS -E -`; transcript is the artifact.
3. **Browser use** — drive the real page via Playwright / puppeteer / Chromium; capture action log + screenshot path.
4. **Computer use** — OS-level GUI automation (computer-use agent, AppleScript, xdotool, etc.) against the running app; capture action log + screenshot.
Auxiliary surfaces (pure CLI stdout / DB state diff / parsed config dump) satisfy CLI- or data-shaped criteria but NEVER replace a channel scenario for user-facing behavior. `--dry-run`, printing the command, "should respond", and "looks correct" never count.
## Artifacts
- `.omo/ultragoal/brief.md`: original brief and durable constraints.
- `.omo/ultragoal/goals.json`: goals with embedded `successCriteria` per goal.
- `.omo/ultragoal/ledger.jsonl`: append-only audit trail.
- Read artifacts before resuming, steering, or checkpointing.
- Never invent state outside `.omo/ultragoal` artifacts or `omo ultragoal status --json`.
## Bootstrap
Do all three steps before execution. No edits, goal tools, or checkpointing before bootstrap completes.
### 1. Create goals from the brief
Resolve the CLI before the first command. If `omo` is absent from PATH, use the stable local installer bin or cached Codex component CLI. This is the same ultragoal CLI, so PATH absence is not a blocker. If PATH is empty, the fallback uses shell builtins and absolute Node locations before reporting guidance, and records the failure in `.omo/ultragoal/bootstrap-notepad.md`.
```sh
if command -v omo >/dev/null 2>&1; then
ULTRAGOAL_CLI=omo
else
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
ULTRAGOAL_CLI=
if [ -f "$CODEX_HOME/bin/omo" ] || [ -x "$CODEX_HOME/bin/omo" ]; then
ULTRAGOAL_CLI="$CODEX_HOME/bin/omo"
else
for candidate in "$CODEX_HOME"/plugins/cache/sisyphuslabs/omo/*/components/ultragoal/dist/cli.js; do
[ -f "$candidate" ] || continue
ULTRAGOAL_CLI="$candidate"
done
fi
ULTRAGOAL_NODE="$(command -v node 2>/dev/null || true)"
if [ -z "$ULTRAGOAL_NODE" ]; then
for candidate in /opt/homebrew/bin/node /usr/local/bin/node /usr/bin/node; do
[ -x "$candidate" ] || continue
ULTRAGOAL_NODE="$candidate"
break
done
fi
if [ -n "$ULTRAGOAL_CLI" ] && [ -n "$ULTRAGOAL_NODE" ]; then
omo() { "$ULTRAGOAL_NODE" "$ULTRAGOAL_CLI" "$@"; }
fi
fi
if [ -z "${ULTRAGOAL_CLI:-}" ]; then
/bin/mkdir -p .omo/ultragoal 2>/dev/null || mkdir -p .omo/ultragoal 2>/dev/null || true
NOTE="${NOTE:-.omo/ultragoal/bootstrap-notepad.md}"
printf '%s\n' "omo executable missing from PATH; cached ultragoal CLI not found under ${CODEX_HOME:-$HOME/.codex}." >> "$NOTE" 2>/dev/null || true
printf '%s\n' "Install with bunx omo install --platform=codex or set CODEX_LOCAL_BIN_DIR to a PATH directory." >&2
fi
```
If `ULTRAGOAL_CLI` is empty, open the durable notepad first, record the missing CLI evidence, then surface the installer issue.
Run one form:
```sh
omo ultragoal create-goals --brief "<brief>" --json
omo ultragoal create-goals --brief-file <path> --json
cat <brief> | omo ultragoal create-goals --from-stdin --json
```
Write state through the CLI path. Do not hand-edit state files.
### 2. Refine success criteria per goal
Define pass/fail acceptance criteria before launching execution lanes. Include the command, artifact, or manual check that will prove success.
Each goal MUST carry 3+ `successCriteria` covering happy path, edge, regression, and adversarial risk.
For each criterion set: `id`, `scenario`, `expectedEvidence`, adversarial classes, stop condition, and the Manual-QA channel (HTTP call / tmux / browser use / computer use) that will exercise it.
Apply ultraqa classes where relevant: malformed input, repeated interruptions, prompt injection, cancel/resume, stale state, dirty worktree, hung or long commands, flaky tests, misleading success output.
Use evidence verbs from the channel table (tmux transcript, curl status+body, browser screenshot, computer-use action log, CLI stdout, DB diff, parsed config dump) — not vibes.
"Tests pass" is supporting signal, NEVER completion proof. Every criterion needs its own channel scenario, built fresh and exercised every time.
Record manual QA notes when behavior is user-visible.
Revise any criterion that lacks observable `expectedEvidence` or a named channel before execution.
### 3. Inspect state
Run `omo ultragoal status --json`.
Read pending goals, criteria IDs, current ledger head, blockers, and aggregate Codex objective.
## Execution Loop
Loop per goal. Cap at 5 cycles per goal. Cap identical same-criterion failures at 3.
### Acquire Next Goal
1. Run `omo ultragoal complete-goals --json` and read the handoff, including criteria.
2. Call `get_goal` and inspect active Codex state.
3. Apply this table exactly:
| get_goal result | action |
|-----------------|--------|
| no active goal | Call `create_goal` with the handoff payload. |
| same aggregate objective active | Continue the current ultragoal story. |
| different goal active | STOP. Checkpoint blocked and surface the conflict. |
4. If retrying failed work, run `omo ultragoal complete-goals --retry-failed --json`.
5. Never create a second Codex goal for the same aggregate objective.
### Per-Criterion Cycle
1. PLAN: read `criterion.scenario`, `criterion.expectedEvidence`, prior ledger entries, and safety bounds.
2. Register atomic todos: `path: <action> for <criterion> - verify by <check>`.
3. EXECUTE-AS-SCENARIO: do one bounded change, then ACTUALLY run the Manual-QA channel scenario the criterion named (HTTP call / tmux / browser use / computer use — see the channel table above). The unit suite being green is NEVER substitute for running the channel scenario.
4. CAPTURE: collect the observable artifact path: transcript, stdout, screenshot, assertion, status+body, diff, or parsed dump.
5. CLEAN (PAIRED, NEVER SKIP): tear down every runtime artifact step 3 spawned BEFORE recording — server PIDs (`kill`, verify `kill -0` fails), `tmux` sessions (`tmux kill-session -t ulw-qa-<criterion>`; confirm `tmux ls`), browser / Playwright contexts (`.close()`), containers (`docker rm -f`), bound ports (`lsof -i :<port>` empty), temp sockets / files / dirs (`rm -rf` the `mktemp` paths), QA-only env vars. Embed a one-line cleanup receipt in the evidence string, e.g. `cleanup: killed 12345; tmux kill-session ulw-qa-foo; rm -rf /tmp/ulw.aB12cD`. Missing receipt → record BLOCKED, not PASS.
6. RECORD exactly one result:
- PASS: `omo ultragoal record-evidence --goal-id <id> --criterion-id <id> --status pass --evidence "<observable> | <cleanup receipt>" --json`
- FAIL: `omo ultragoal record-evidence --goal-id <id> --criterion-id <id> --status fail --evidence "<observable> | <cleanup receipt>" --notes "<diagnosis>" --json`
- BLOCKED: `omo ultragoal record-evidence --goal-id <id> --criterion-id <id> --status blocked --evidence "<observable>" --notes "<safety/blocker/leftover-state>" --json`
7. If actual does not match expected, diagnose, fix minimally, and rerun the SAME criterion (including a fresh cleanup).
8. After 3 same-criterion failures, exit the goal with diagnosis.
9. After 5 cycles on one goal without all criteria passing, checkpoint failed.
10. Continue only when the next pending criterion has a concrete `expectedEvidence` target.
### Goal Completion
1. Confirm every criterion is `pass` with `omo ultragoal criteria --goal-id <id> --json`.
2. Call `get_goal` for a fresh snapshot.
3. Run `omo ultragoal checkpoint --goal-id <id> --status complete --evidence "<criteria evidence summary>" --codex-goal-json <snapshot> --json`.
4. If blocked or failed, checkpoint with `--status blocked` or `--status failed` and include diagnosis evidence.
5. If this is the final goal, run the final quality gate first and pass `--quality-gate-json`.
## Final Quality Gate
Trigger only when one goal remains and all its criteria are passing.
1. Run targeted verification for changed behavior.
2. Run `ai-slop-cleaner` on changed files. If no relevant edits exist, record a passed no-op cleaner report.
3. Rerun verification after cleanup.
4. Run `$code-review`.
5. Clean review means `codeReview.recommendation == "APPROVE"` and `codeReview.architectStatus == "CLEAR"`.
6. If review is non-clean, run `omo ultragoal record-review-blockers --goal-id <id> --title "<...>" --objective "<...>" --evidence "<review findings>" --codex-goal-json <snapshot> --json`.
7. If clean, checkpoint final completion:
```sh
omo ultragoal checkpoint --goal-id <id> --status complete --evidence "<e2e evidence + manual QA notes>" --codex-goal-json <snapshot> --quality-gate-json <json-or-path> --json
```
`--quality-gate-json` shape:
```json
{
"aiSlopCleaner": { "status": "passed", "evidence": "cleaner report" },
"verification": { "status": "passed", "commands": ["npm test"], "evidence": "post-cleaner verification" },
"codeReview": { "recommendation": "APPROVE", "architectStatus": "CLEAR", "evidence": "review synthesis" },
"criteriaCoverage": { "totalCriteria": N, "passCount": N, "adversarialClassesCovered": ["malformed_input", "..."] }
}
```
## Dynamic Steering
Use steering only for structured evidence-backed mutation. Reject natural-language steering requests.
| Kind | When to use | Required fields |
|------|-------------|-----------------|
| add_subgoal | Real blocker found; new story required | `--title`, `--objective`, `--evidence`, `--rationale` |
| split_subgoal | Story too large; needs decomposition | `--goal-id`, `--children` JSON, `--evidence`, `--rationale` |
| reorder_pending | Discovered dependency order | `--order` JSON array of ids, `--evidence`, `--rationale` |
| revise_pending_wording | Title/objective ambiguous | `--goal-id`, `--title?`, `--objective?`, `--evidence`, `--rationale` |
| revise_criterion | Criterion lacks observable PASS evidence | `--goal-id`, `--criterion-id`, `--scenario?`, `--expected-evidence?`, `--evidence`, `--rationale` |
| annotate_ledger | Audit-only note | `--evidence`, `--rationale` |
| mark_blocked_superseded | Old story replaced by new evidence | `--goal-id`, `--replacements?`, `--evidence`, `--rationale` |
Command form: `omo ultragoal steer --kind <kind> [<kind-specific-fields>] --evidence "<...>" --rationale "<...>" --json`.
Structured prompt directives accepted: `OMO_ULTRAGOAL_STEER: { ... }`, `omo.ultragoal.steer: {...}`, `omo ultragoal steer: {...}`.
## Constraints
1. NEVER call `update_goal` mid-aggregate; only on final story after the quality gate passes.
2. NEVER call `create_goal` when `get_goal` shows a different active goal.
3. NEVER mark `criterion.status == "pass"` without captured observable evidence in `record-evidence`.
4. NEVER bypass the criteria gate at checkpoint; all criteria must be `pass` before `--status complete`.
5. Baseline build/lint/typecheck/test commands are necessary evidence, NOT SUFFICIENT completion proof. Criteria coverage with observable evidence is the gate.
6. Treat `.omo/ultragoal/ledger.jsonl` as the durable audit trail; checkpoint after every success or failure.
7. Per-story Codex goal mode is opt-in only with `--codex-goal-mode per-story`; default is aggregate.
8. Structured steering directives mutate state through validation; normal prose does not.
9. Evidence MUST be observable from the real surface: tmux transcript, curl status+body, browser/Playwright assertion, CLI stdout, DB state diff, parsed config dump.
10. Apply ultraqa's 9 adversarial classes where relevant per goal: malformed input, prompt injection, cancel/resume, stale state, dirty worktree, hung commands, flaky tests, misleading success output, repeated interruptions.
11. After completing an aggregate ultragoal run, clear the Codex goal manually with `/goal clear` before starting another in the same session.
12. The shell command emits a model-facing handoff; only the Codex agent calls `get_goal`, `create_goal`, or `update_goal` tools.
13. NEVER record `--status pass` while a QA-spawned process, `tmux` session, browser context, bound port, container, or temp file / dir is still alive. The evidence string MUST include the cleanup receipt. Leftover runtime state = BLOCKED, not PASS.
## Stop Rules
- All goals complete plus all criteria `pass` plus final quality gate clean: DONE.
- 3x same criterion failure: checkpoint failed, surface diagnosis.
- 5 cycles on one goal without all-pass: checkpoint failed, surface.
- Safety boundary such as destructive command, secret exfiltration, or production write: block and surface a safe substitute.
- Codex `get_goal` reports a different active goal: checkpoint blocker, stop, surface.
- Leftover state from QA (live process, `tmux` session, browser context, bound port, temp dir): NOT pass. Clean up, append the receipt, then continue.
- User issues `/cancel`: release in-progress state cleanly and do not auto-resume.
@@ -1,27 +0,0 @@
import { join } from "node:path";
import { ULTRAGOAL_BRIEF, ULTRAGOAL_DIR, ULTRAGOAL_GOALS, ULTRAGOAL_LEDGER } from "./types.js";
export function ultragoalDir(repoRoot: string): string {
return join(repoRoot, ULTRAGOAL_DIR);
}
export function ultragoalBriefPath(repoRoot: string): string {
return join(ultragoalDir(repoRoot), ULTRAGOAL_BRIEF);
}
export function ultragoalGoalsPath(repoRoot: string): string {
return join(ultragoalDir(repoRoot), ULTRAGOAL_GOALS);
}
export function ultragoalLedgerPath(repoRoot: string): string {
return join(ultragoalDir(repoRoot), ULTRAGOAL_LEDGER);
}
export function repoRelative(absolutePath: string, repoRoot: string): string {
const slashPrefix = `${repoRoot}/`;
const backslashPrefix = `${repoRoot}\\`;
if (absolutePath.startsWith(slashPrefix)) return absolutePath.slice(slashPrefix.length).split("\\").join("/");
if (absolutePath.startsWith(backslashPrefix))
return absolutePath.slice(backslashPrefix.length).split("\\").join("/");
return absolutePath.split("\\").join("/");
}
@@ -1 +0,0 @@
{ "goal": { "objective": "Complete the durable ultragoal plan", "status": "active" } }
@@ -1,37 +0,0 @@
import { describe, expect, it } from "vitest";
import {
repoRelative,
ultragoalBriefPath,
ultragoalDir,
ultragoalGoalsPath,
ultragoalLedgerPath,
} from "../src/paths.ts";
describe("ultragoalDir(repo)", () => {
it("returns repo + '/.omo/ultragoal'", () => {
// when/then
expect(ultragoalDir("/repo")).toBe("/repo/.omo/ultragoal");
});
});
describe("ultragoal*Path helpers", () => {
it("compose artifact filenames under ultragoalDir", () => {
// when/then
expect(ultragoalBriefPath("/r")).toBe("/r/.omo/ultragoal/brief.md");
expect(ultragoalGoalsPath("/r")).toBe("/r/.omo/ultragoal/goals.json");
expect(ultragoalLedgerPath("/r")).toBe("/r/.omo/ultragoal/ledger.jsonl");
});
});
describe("repoRelative", () => {
it("strips repo prefix when path is inside repo", () => {
// when/then
expect(repoRelative("/repo/.omo/ultragoal/goals.json", "/repo")).toBe(".omo/ultragoal/goals.json");
});
it("returns absolute when path is outside repo", () => {
// when/then
expect(repoRelative("/elsewhere/file", "/repo")).toBe("/elsewhere/file");
});
});
@@ -37,9 +37,9 @@ Conventions for human contributors and AI agents working on this repository.
## Branding
- Repo artifacts live under `.omo/ultragoal/` paths.
- Environment variables use the `OMO_ULTRAGOAL_*` prefix.
- CLI commands use the `omo ultragoal` form.
- Repo artifacts live under `.omo/ulw-loop/` paths.
- Environment variables use the `OMO_ULW_LOOP_*` prefix.
- CLI commands use the `omo ulw-loop` form.
- Do not use any alternate legacy CLI alias anywhere.
## Build and Hooks
@@ -2,6 +2,6 @@
## [0.1.0] - unreleased
- Initial scaffold of codex-ultragoal plugin.
- Initial scaffold of codex-ulw-loop plugin.
- Per-Criterion Cycle: `EXECUTE` is now **EXECUTE-AS-SCENARIO** — the agent must run the Manual-QA channel scenario the criterion named (HTTP call / tmux / browser use / computer use; see new `## Manual-QA channels` section). Inserted a new **CLEAN (PAIRED, NEVER SKIP)** step that tears down every QA-spawned process / `tmux` session / browser context / container / port / temp dir before recording evidence; the cleanup receipt is embedded in the `--evidence` string. Missing receipt → record BLOCKED, not PASS. Added Constraint #13 and a Stop Rule for leftover state.
- New top-level **`## Manual-QA channels`** section explicitly enumerates the four channels (HTTP call, tmux, Browser use, Computer use) with concrete commands and required artifacts. Goal section now declares **TESTS ALONE NEVER PROVE DONE**: a green test suite is supporting evidence, never completion proof. Criterion-refinement step 2 requires each criterion to name its channel up front.
@@ -1,6 +1,6 @@
codex-ultragoal
codex-ulw-loop
This package ports the oh-my-codex ultragoal feature into a Codex plugin repository.
This package ports the oh-my-codex ulw-loop feature into a Codex plugin repository.
The plugin targets Codex plugin manifests and plugin-bundled lifecycle hooks.
The orchestration engine is added in later port waves.
@@ -1,4 +1,4 @@
# codex-ultragoal
# codex-ulw-loop
[![ci](https://img.shields.io/badge/ci-pending-lightgrey.svg)](#) [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
@@ -8,13 +8,13 @@ Codex plugin scaffold for durable repo-native multi-goal orchestration with embe
| Subcommand | Purpose |
|------------|---------|
| `omo ultragoal create-goals` | Create repo-native goals from a brief and seed criteria. |
| `omo ultragoal record-evidence` | Record observable evidence for the active criterion. |
| `omo ultragoal criteria` | Inspect or revise goal success criteria. |
| `omo ultragoal complete-goals` | Complete eligible goals after criteria pass. |
| `omo ultragoal checkpoint` | Refuse completion until criteria and evidence gates pass. |
| `omo ultragoal steer` | Apply steering updates to the plan. |
| `omo ultragoal status` | Report active goal, criteria, and evidence state. |
| `omo ulw-loop create-goals` | Create repo-native goals from a brief and seed criteria. |
| `omo ulw-loop record-evidence` | Record observable evidence for the active criterion. |
| `omo ulw-loop criteria` | Inspect or revise goal success criteria. |
| `omo ulw-loop complete-goals` | Complete eligible goals after criteria pass. |
| `omo ulw-loop checkpoint` | Refuse completion until criteria and evidence gates pass. |
| `omo ulw-loop steer` | Apply steering updates to the plan. |
| `omo ulw-loop status` | Report active goal, criteria, and evidence state. |
Wave 1 is scaffold only. Command behavior lands in later waves.
@@ -24,7 +24,7 @@ The plugin ships:
- `.codex-plugin/plugin.json` for Codex plugin discovery.
- `hooks/hooks.json` for the `UserPromptSubmit` hook.
- `skills/ultragoal/` as the future skill directory.
- `skills/ulw-loop/` as the future skill directory.
The hook command is:
@@ -71,5 +71,5 @@ This plugin runs locally. The scaffold does not call a network service by itself
## Related
- [oh-my-codex](https://github.com/code-yeongyu/oh-my-codex) - source project for the ultragoal port.
- [oh-my-codex](https://github.com/code-yeongyu/oh-my-codex) - source project for the ulw-loop port.
- [lazycodex](https://github.com/code-yeongyu/lazycodex) - Sisyphus Labs Codex marketplace repository.
@@ -7,7 +7,7 @@
"type": "command",
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit",
"timeout": 10,
"statusMessage": "checking ultragoal steering"
"statusMessage": "checking ulw-loop steering"
}
]
}
@@ -20,7 +20,7 @@
"type": "command",
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use",
"timeout": 5,
"statusMessage": "enforcing unlimited ultragoal budget"
"statusMessage": "enforcing unlimited ulw-loop budget"
}
]
}
@@ -1,22 +1,22 @@
{
"name": "@code-yeongyu/codex-ultragoal",
"name": "@code-yeongyu/codex-ulw-loop",
"version": "0.1.0",
"description": "Codex plugin: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit.",
"type": "module",
"packageManager": "npm@11.12.1",
"license": "MIT",
"homepage": "https://github.com/code-yeongyu/codex-ultragoal",
"homepage": "https://github.com/code-yeongyu/codex-ulw-loop",
"repository": {
"type": "git",
"url": "git+https://github.com/code-yeongyu/codex-ultragoal.git"
"url": "git+https://github.com/code-yeongyu/codex-ulw-loop.git"
},
"bugs": {
"url": "https://github.com/code-yeongyu/codex-ultragoal/issues"
"url": "https://github.com/code-yeongyu/codex-ulw-loop/issues"
},
"keywords": [
"codex",
"codex-plugin",
"ultragoal",
"ulw-loop",
"goal-mode",
"orchestration",
"evidence",
@@ -0,0 +1,221 @@
---
name: ulw-loop
description: Goal-like loop that uses ultrawork mode to decompose work into systematic, evidence-bound steps.
metadata:
short-description: Goal-like ultrawork loop for systematic decomposition
---
## Role
Expert goal orchestration agent. You conduct; right-sized parallel subagents play. Plan multi-goal work that survives across turns and sessions, fan independent work out to workers, QA every result yourself, record only proven evidence.
Use GPT-5.x style: outcome-first, evidence-bound, atomic decisions, no nested branching prose.
## Goal
Deliver every goal in `.omo/ulw-loop/goals.json` end-to-end.
Prove EVERY success criterion with captured observable evidence from a real-usage scenario you actually ran (HTTP call / tmux / browser use / computer use — see the Manual-QA channels below).
TESTS ALONE NEVER PROVE DONE. A green test suite is supporting evidence, not completion proof.
Audit each pass, fail, block, steering change, and checkpoint in `.omo/ulw-loop/ledger.jsonl`.
## Manual-QA channels (PICK ONE PER CRITERION — ACTUALLY RUN IT)
For every criterion, build a real-usage scenario through ONE of these four channels and run it yourself before recording PASS. The full test suite being green is NEVER verification on its own.
1. **HTTP call** — hit the live endpoint with `curl -i` (or a Playwright APIRequestContext); capture status line + headers + body.
2. **tmux**`tmux new-session -d -s ulw-qa-<criterion>`, drive with `send-keys`, dump via `tmux capture-pane -pS -E -`; transcript is the artifact.
3. **Browser use** — drive the real page via Playwright / puppeteer / Chromium; capture action log + screenshot path.
4. **Computer use** — OS-level GUI automation (computer-use agent, AppleScript, xdotool, etc.) against the running app; capture action log + screenshot.
Auxiliary surfaces (pure CLI stdout / DB state diff / parsed config dump) satisfy CLI- or data-shaped criteria but NEVER replace a channel scenario for user-facing behavior. `--dry-run`, printing the command, "should respond", and "looks correct" never count.
## Delegation model (ATLAS-STYLE — YOU CONDUCT, WORKERS PLAY)
You read, search, plan, integrate, and QA. You DELEGATE every code edit, test write, bug fix, and QA execution to a right-sized `spawn_agent` worker, then verify what comes back. Fan out independent tasks in PARALLEL in a single response; serialize only on a NAMED dependency (one task consumes another's output or edits the same file).
Size each worker to the task — never spend `xhigh` on a one-liner, never send a race condition to a mini. Pass `model` + `reasoning_effort` per call (an override needs a non-full-history fork mode):
| Task shape | agent_type | model | reasoning_effort |
|---|---|---|---|
| Trivial / mechanical (rename, move, obvious one-liner, config edit) | `worker` | `gpt-5.4-mini` | `low` |
| Pure implementation against a clear spec (new function, endpoint, test from a named pattern) | `worker` | `gpt-5.3-codex` | `high` |
| Deep debugging / race / perf / subtle cross-module reasoning | `worker` | `gpt-5.5` | `xhigh` |
| QA execution (drive a channel, capture evidence) | `worker` | `gpt-5.3-codex` | `high` |
| Read-only codebase search | `explorer` | role default | role default |
| External library / docs research | `librarian` | role default | role default |
| Final verification audit | `codex-ultrawork-reviewer` | role default | role default |
Every worker message MUST carry: goal + exact files in scope; the failing test / reproduction required before production code; constraints + project rules; the verification commands to run; the ONE Manual-QA channel and the exact evidence artifact to capture. Workers have NO interview context — be exhaustive, and forward accumulated learnings to every next worker. Track running workers; `wait_agent` for results, `close_agent` when done.
## Artifacts
- `.omo/ulw-loop/brief.md`: original brief and durable constraints.
- `.omo/ulw-loop/goals.json`: goals with embedded `successCriteria` per goal.
- `.omo/ulw-loop/ledger.jsonl`: append-only audit trail.
- Read artifacts before resuming, steering, or checkpointing.
- Never invent state outside `.omo/ulw-loop` artifacts or `omo ulw-loop status --json`.
## Bootstrap
Do all three steps before execution. No edits, goal tools, or checkpointing before bootstrap completes.
### 1. Create goals from the brief
Resolve the CLI before the first command. If `omo` is absent from PATH, use the stable local installer bin or cached Codex component CLI. This is the same ulw-loop CLI, so PATH absence is not a blocker. If PATH is empty, the fallback uses shell builtins and absolute Node locations before reporting guidance, and records the failure in `.omo/ulw-loop/bootstrap-notepad.md`.
```sh
if command -v omo >/dev/null 2>&1; then
ULW_LOOP_CLI=omo
else
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
ULW_LOOP_CLI=
if [ -f "$CODEX_HOME/bin/omo" ] || [ -x "$CODEX_HOME/bin/omo" ]; then
ULW_LOOP_CLI="$CODEX_HOME/bin/omo"
else
for candidate in "$CODEX_HOME"/plugins/cache/sisyphuslabs/omo/*/components/ulw-loop/dist/cli.js; do
[ -f "$candidate" ] || continue
ULW_LOOP_CLI="$candidate"
done
fi
ULW_LOOP_NODE="$(command -v node 2>/dev/null || true)"
if [ -z "$ULW_LOOP_NODE" ]; then
for candidate in /opt/homebrew/bin/node /usr/local/bin/node /usr/bin/node; do
[ -x "$candidate" ] || continue
ULW_LOOP_NODE="$candidate"
break
done
fi
if [ -n "$ULW_LOOP_CLI" ] && [ -n "$ULW_LOOP_NODE" ]; then
omo() { "$ULW_LOOP_NODE" "$ULW_LOOP_CLI" "$@"; }
fi
fi
if [ -z "${ULW_LOOP_CLI:-}" ]; then
/bin/mkdir -p .omo/ulw-loop 2>/dev/null || mkdir -p .omo/ulw-loop 2>/dev/null || true
NOTE="${NOTE:-.omo/ulw-loop/bootstrap-notepad.md}"
printf '%s\n' "omo executable missing from PATH; cached ulw-loop CLI not found under ${CODEX_HOME:-$HOME/.codex}." >> "$NOTE" 2>/dev/null || true
printf '%s\n' "Install with bunx omo install --platform=codex or set CODEX_LOCAL_BIN_DIR to a PATH directory." >&2
fi
```
If `ULW_LOOP_CLI` is empty, open the durable notepad first, record the missing CLI evidence, then surface the installer issue.
Run one form:
```sh
omo ulw-loop create-goals --brief "<brief>" --json
omo ulw-loop create-goals --brief-file <path> --json
cat <brief> | omo ulw-loop create-goals --from-stdin --json
```
Write state through the CLI path. Do not hand-edit state files.
### 2. Refine success criteria + a Prometheus-grade QA and parallelism plan per goal
Gather context BEFORE planning — fire parallel `explorer` / `librarian` workers plus your own read-only tools; never plan blind.
Define pass/fail acceptance criteria before launching execution lanes. Include the command, artifact, or manual check that will prove success.
Each goal MUST carry 3+ `successCriteria` covering happy path, edge, regression, and adversarial risk.
For each criterion set, concretely and upfront: `id`, `scenario` (the exact tool — curl / tmux / playwright / computer-use — plus exact steps with specific inputs and a binary pass/fail), `expectedEvidence` (the exact artifact path, e.g. `.omo/ulw-loop/evidence/<goal>-<criterion>.<ext>`), adversarial classes, stop condition, and the Manual-QA channel (HTTP call / tmux / browser use / computer use) that will exercise it. Vague QA ("verify it works") is a rejected criterion — revise it before execution.
Apply ultraqa classes where relevant: malformed input, repeated interruptions, prompt injection, cancel/resume, stale state, dirty worktree, hung or long commands, flaky tests, misleading success output.
Use evidence verbs from the channel table (tmux transcript, curl status+body, browser screenshot, computer-use action log, CLI stdout, DB diff, parsed config dump) — not vibes.
"Tests pass" is supporting signal, NEVER completion proof. Every criterion needs its own channel scenario, built fresh and exercised every time.
**Plan for maximum parallelism.** Decompose each goal's criteria into atomic tasks (Implementation + its Test = ONE task, never split) and group them into dependency waves. Target 58 tasks per wave; <3 per wave (except the final wave) means under-splitting — extract shared prerequisites into Wave 1. For each task record its wave, what it blocks, what blocks it, the worker tier from the Delegation table, and its QA scenario + evidence path. Build a dependency matrix (Task | Depends on | Blocks | Can parallelize with) and name the critical path. Anything not on a real dependency edge MUST share a wave and dispatch together.
Record manual QA notes when behavior is user-visible.
Revise any criterion that lacks observable `expectedEvidence` or a named channel before execution.
### 3. Inspect state
Run `omo ulw-loop status --json`.
Read pending goals, criteria IDs, current ledger head, blockers, and aggregate Codex objective.
## Execution Loop
Loop per goal. Cap at 5 cycles per goal. Cap identical same-criterion failures at 3.
### Acquire Next Goal
1. Run `omo ulw-loop complete-goals --json` and read the handoff, including criteria.
2. Call `get_goal` and inspect active Codex state.
3. Apply this table exactly:
| get_goal result | action |
|-----------------|--------|
| no active goal | Call `create_goal` with the handoff payload. |
| same aggregate objective active | Continue the current ulw-loop story. |
| different goal active | STOP. Checkpoint blocked and surface the conflict. |
4. If retrying failed work, run `omo ulw-loop complete-goals --retry-failed --json`.
5. Never create a second Codex goal for the same aggregate objective.
### Per-Criterion Cycle
1. PLAN: read `criterion.scenario`, `criterion.expectedEvidence`, prior ledger entries, and safety bounds. Identify which tasks in the current wave are independent.
2. Register atomic todos: `path: <action> for <criterion> - verify by <check>`.
3. DELEGATE-IN-PARALLEL: dispatch every independent task in the wave at once via right-sized `spawn_agent` workers (Delegation table). Each worker does strict TDD on its task: RED first (the failing assertion must fail for the RIGHT reason — no syntax/import error), then the SMALLEST GREEN change; a GREEN needing >~20 lines means the test was too coarse — instruct a split. Serialize only on a NAMED dependency.
4. INTEGRATE + CRITICAL SELF-QA (EVERY WORKER RETURN): do NOT trust the worker's report. Read the diff yourself, re-run its tests, and run LSP diagnostics on the changed files. Treat "done" as a claim to disprove. If the diff drifts, the test is hollow, or evidence is missing, RESPAWN the worker with the specific failure context. Forward every finding/learning to subsequent workers.
5. EXECUTE-AS-SCENARIO: ACTUALLY run the Manual-QA channel scenario the criterion named (HTTP call / tmux / browser use / computer use — see the channel table above). Run it yourself for the orchestrator check; for heavier flows dispatch a dedicated QA worker (`worker`, `gpt-5.3-codex`, `high`) whose ONLY job is to drive the channel and write the artifact to the named evidence path. The unit suite being green is NEVER substitute. If the scenario FAILS, respawn the implementing worker with the captured failure — do not hand-patch around it.
6. CAPTURE: collect the observable artifact path: transcript, stdout, screenshot, assertion, status+body, diff, or parsed dump. No artifact written at the evidence path — not done; record BLOCKED and respawn QA.
7. CLEAN (PAIRED, NEVER SKIP): tear down every runtime artifact step 5 spawned BEFORE recording — server PIDs (`kill`, verify `kill -0` fails), `tmux` sessions (`tmux kill-session -t ulw-qa-<criterion>`; confirm `tmux ls`), browser / Playwright contexts (`.close()`), containers (`docker rm -f`), bound ports (`lsof -i :<port>` empty), temp sockets / files / dirs (`rm -rf` the `mktemp` paths), QA-only env vars, AND `close_agent` on every finished worker. Embed a one-line cleanup receipt in the evidence string, e.g. `cleanup: killed 12345; tmux kill-session ulw-qa-foo; rm -rf /tmp/ulw.aB12cD; close_agent w-3`. Missing receipt → record BLOCKED, not PASS.
8. RECORD exactly one result:
- PASS: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass --evidence "<observable> | <cleanup receipt>" --json`
- FAIL: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status fail --evidence "<observable> | <cleanup receipt>" --notes "<diagnosis>" --json`
- BLOCKED: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status blocked --evidence "<observable>" --notes "<safety/blocker/leftover-state>" --json`
9. If actual does not match expected, diagnose, respawn the right-sized worker with the failure context to fix minimally, and rerun the SAME criterion (including a fresh cleanup).
10. After 3 same-criterion failures, exit the goal with diagnosis.
11. After 5 cycles on one goal without all criteria passing, checkpoint failed.
12. Continue only when the next pending criterion has a concrete `expectedEvidence` target.
### Goal Completion
1. Confirm every criterion is `pass` with `omo ulw-loop criteria --goal-id <id> --json`.
2. Call `get_goal` for a fresh snapshot.
3. Run `omo ulw-loop checkpoint --goal-id <id> --status complete --evidence "<criteria evidence summary>" --codex-goal-json <snapshot> --json`.
4. If blocked or failed, checkpoint with `--status blocked` or `--status failed` and include diagnosis evidence.
5. If this is the final goal, run the final quality gate first and pass `--quality-gate-json`.
## Final Quality Gate
Trigger only when one goal remains and all its criteria are passing.
1. Run targeted verification for changed behavior.
2. Run `ai-slop-cleaner` on changed files. If no relevant edits exist, record a passed no-op cleaner report.
3. Rerun verification after cleanup.
4. Run `$code-review`.
5. Clean review means `codeReview.recommendation == "APPROVE"` and `codeReview.architectStatus == "CLEAR"`.
6. If review is non-clean, run `omo ulw-loop record-review-blockers --goal-id <id> --title "<...>" --objective "<...>" --evidence "<review findings>" --codex-goal-json <snapshot> --json`.
7. If clean, checkpoint final completion:
```sh
omo ulw-loop checkpoint --goal-id <id> --status complete --evidence "<e2e evidence + manual QA notes>" --codex-goal-json <snapshot> --quality-gate-json <json-or-path> --json
```
`--quality-gate-json` shape:
```json
{
"aiSlopCleaner": { "status": "passed", "evidence": "cleaner report" },
"verification": { "status": "passed", "commands": ["npm test"], "evidence": "post-cleaner verification" },
"codeReview": { "recommendation": "APPROVE", "architectStatus": "CLEAR", "evidence": "review synthesis" },
"criteriaCoverage": { "totalCriteria": N, "passCount": N, "adversarialClassesCovered": ["malformed_input", "..."] }
}
```
## Dynamic Steering
Use steering only for structured evidence-backed mutation. Reject natural-language steering requests.
| Kind | When to use | Required fields |
|------|-------------|-----------------|
| add_subgoal | Real blocker found; new story required | `--title`, `--objective`, `--evidence`, `--rationale` |
| split_subgoal | Story too large; needs decomposition | `--goal-id`, `--children` JSON, `--evidence`, `--rationale` |
| reorder_pending | Discovered dependency order | `--order` JSON array of ids, `--evidence`, `--rationale` |
| revise_pending_wording | Title/objective ambiguous | `--goal-id`, `--title?`, `--objective?`, `--evidence`, `--rationale` |
| revise_criterion | Criterion lacks observable PASS evidence | `--goal-id`, `--criterion-id`, `--scenario?`, `--expected-evidence?`, `--evidence`, `--rationale` |
| annotate_ledger | Audit-only note | `--evidence`, `--rationale` |
| mark_blocked_superseded | Old story replaced by new evidence | `--goal-id`, `--replacements?`, `--evidence`, `--rationale` |
Command form: `omo ulw-loop steer --kind <kind> [<kind-specific-fields>] --evidence "<...>" --rationale "<...>" --json`.
Structured prompt directives accepted: `OMO_ULW_LOOP_STEER: { ... }`, `omo.ulw-loop.steer: {...}`, `omo ulw-loop steer: {...}`.
## Constraints
1. NEVER call `update_goal` mid-aggregate; only on final story after the quality gate passes.
2. NEVER call `create_goal` when `get_goal` shows a different active goal.
3. NEVER mark `criterion.status == "pass"` without captured observable evidence in `record-evidence`.
4. NEVER bypass the criteria gate at checkpoint; all criteria must be `pass` before `--status complete`.
5. Baseline build/lint/typecheck/test commands are necessary evidence, NOT SUFFICIENT completion proof. Criteria coverage with observable evidence is the gate.
6. Treat `.omo/ulw-loop/ledger.jsonl` as the durable audit trail; checkpoint after every success or failure.
7. Per-story Codex goal mode is opt-in only with `--codex-goal-mode per-story`; default is aggregate.
8. Structured steering directives mutate state through validation; normal prose does not.
9. Evidence MUST be observable from the real surface: tmux transcript, curl status+body, browser/Playwright assertion, CLI stdout, DB state diff, parsed config dump.
10. Apply ultraqa's 9 adversarial classes where relevant per goal: malformed input, prompt injection, cancel/resume, stale state, dirty worktree, hung commands, flaky tests, misleading success output, repeated interruptions.
11. After completing an aggregate ulw-loop run, clear the Codex goal manually with `/goal clear` before starting another in the same session.
12. The shell command emits a model-facing handoff; only the Codex agent calls `get_goal`, `create_goal`, or `update_goal` tools.
13. NEVER record `--status pass` while a QA-spawned process, `tmux` session, browser context, bound port, container, or temp file / dir is still alive, or while any worker is still open. The evidence string MUST include the cleanup receipt. Leftover runtime state = BLOCKED, not PASS.
14. DELEGATE all code edits, test writes, fixes, and QA execution to right-sized `spawn_agent` workers (Delegation table); you read, search, plan, integrate, and QA. NEVER record `--status pass` from a worker's self-report — only from evidence you re-verified yourself. Dispatch independent tasks in parallel; serialize only on a NAMED dependency.
## Stop Rules
- All goals complete plus all criteria `pass` plus final quality gate clean: DONE.
- 3x same criterion failure: checkpoint failed, surface diagnosis.
- 5 cycles on one goal without all-pass: checkpoint failed, surface.
- Safety boundary such as destructive command, secret exfiltration, or production write: block and surface a safe substitute.
- Codex `get_goal` reports a different active goal: checkpoint blocker, stop, surface.
- Leftover state from QA (live process, `tmux` session, browser context, bound port, temp dir): NOT pass. Clean up, append the receipt, then continue.
- User issues `/cancel`: release in-progress state cleanly and do not auto-resume.
@@ -2,5 +2,5 @@ interface:
display_name: "ulw loop"
short_description: "Goal-like ultrawork loop for systematic decomposition"
search_terms:
- "ultragoal"
- "ulw-loop"
default_prompt: "Use $ulw-loop to break this work into a systematic ultrawork loop with evidence-backed checkpoints."
@@ -6,23 +6,23 @@ import { resolve } from "node:path";
import { formatCodexGoalReconciliation, readCodexGoalSnapshotInput, reconcileCodexGoalSnapshot } from "./codex-goal-snapshot.js";
import { requireAllCriteriaPass } from "./evidence.js";
import { codexGoalMode, compatibleCodexObjectives, expectedCodexObjective, isFinalRunCompletionCandidate } from "./goal-status.js";
import { ultragoalBriefPath } from "./paths.js";
import { appendLedger, readUltragoalPlan, withUltragoalMutationLock, writePlan } from "./plan-io.js";
import { ulwLoopBriefPath } from "./paths.js";
import { appendLedger, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
import { classifyExternalAuthorizationBlocker, clearGoalBlockerFields, sameBlockerOccurrences, validateQualityGate } from "./quality-gate.js";
import type { UltragoalAggregateCompletion, UltragoalItem, UltragoalLedgerEntry, UltragoalPlan, UltragoalQualityGate } from "./types.js";
import { iso, ULTRAGOAL_DIR, ULTRAGOAL_GOALS, ULTRAGOAL_LEDGER, UltragoalError } from "./types.js";
import type { UlwLoopAggregateCompletion, UlwLoopItem, UlwLoopLedgerEntry, UlwLoopPlan, UlwLoopQualityGate } from "./types.js";
import { iso, ULW_LOOP_DIR, ULW_LOOP_GOALS, ULW_LOOP_LEDGER, UlwLoopError } from "./types.js";
export interface CheckpointUltragoalArgs { readonly goalId: string; readonly status: "complete" | "failed" | "blocked"; readonly evidence: string; readonly codexGoalJson?: string; readonly qualityGateJson?: string }
export interface CheckpointUltragoalResult { readonly plan: UltragoalPlan; readonly goal: UltragoalItem; readonly ledgerEntry: UltragoalLedgerEntry; readonly aggregateCompletion?: UltragoalAggregateCompletion }
export interface CheckpointUlwLoopArgs { readonly goalId: string; readonly status: "complete" | "failed" | "blocked"; readonly evidence: string; readonly codexGoalJson?: string; readonly qualityGateJson?: string }
export interface CheckpointUlwLoopResult { readonly plan: UlwLoopPlan; readonly goal: UlwLoopItem; readonly ledgerEntry: UlwLoopLedgerEntry; readonly aggregateCompletion?: UlwLoopAggregateCompletion }
function ultragoalFail(message: string, code: string): never { throw new UltragoalError(message, code); }
function ulwLoopFail(message: string, code: string): never { throw new UlwLoopError(message, code); }
function normalizeObjective(value: string): string { return value.replace(/\s+/g, " ").trim(); }
function nonEmptyEvidence(value: string): string { const trimmed = value.trim(); return trimmed || ultragoalFail("Evidence must be a non-empty string.", "ultragoal_evidence_required"); }
function findGoal(plan: UltragoalPlan, goalId: string): UltragoalItem { const goal = plan.goals.find((candidate) => candidate.id === goalId); return goal ?? ultragoalFail(`Unknown ultragoal id: ${goalId}.`, "ultragoal_goal_not_found"); }
function nonEmptyEvidence(value: string): string { const trimmed = value.trim(); return trimmed || ulwLoopFail("Evidence must be a non-empty string.", "ulw_loop_evidence_required"); }
function findGoal(plan: UlwLoopPlan, goalId: string): UlwLoopItem { const goal = plan.goals.find((candidate) => candidate.id === goalId); return goal ?? ulwLoopFail(`Unknown ulw-loop id: ${goalId}.`, "ulw_loop_goal_not_found"); }
function textMentionsUltragoalPlanArtifact(value: string | undefined): boolean {
function textMentionsUlwLoopPlanArtifact(value: string | undefined): boolean {
const normalized = (value ?? "").toLowerCase();
return normalized.includes(ULTRAGOAL_DIR.toLowerCase()) || normalized.includes(ULTRAGOAL_GOALS.toLowerCase()) || normalized.includes(ULTRAGOAL_LEDGER.toLowerCase());
return normalized.includes(ULW_LOOP_DIR.toLowerCase()) || normalized.includes(ULW_LOOP_GOALS.toLowerCase()) || normalized.includes(ULW_LOOP_LEDGER.toLowerCase());
}
function textMentionsGoalId(value: string | undefined, goalId: string): boolean { return (value ?? "").toLowerCase().includes(goalId.toLowerCase()); }
function textHasCompletionValidationEvidence(value: string | undefined): boolean {
@@ -32,12 +32,12 @@ function textHasCompletionValidationEvidence(value: string | undefined): boolean
return done && verified;
}
async function snapshotObjectiveMapsToUltragoalPlan(repoRoot: string, snapshotObjective: string): Promise<boolean> {
async function snapshotObjectiveMapsToUlwLoopPlan(repoRoot: string, snapshotObjective: string): Promise<boolean> {
const actual = normalizeObjective(snapshotObjective).toLowerCase();
if (textMentionsUltragoalPlanArtifact(actual)) return true;
if (actual.length < 24 || !existsSync(ultragoalBriefPath(repoRoot))) return false;
if (textMentionsUlwLoopPlanArtifact(actual)) return true;
if (actual.length < 24 || !existsSync(ulwLoopBriefPath(repoRoot))) return false;
try {
const brief = normalizeObjective(await readFile(ultragoalBriefPath(repoRoot), "utf8")).toLowerCase();
const brief = normalizeObjective(await readFile(ulwLoopBriefPath(repoRoot), "utf8")).toLowerCase();
return brief.length >= 24 && (brief.includes(actual) || actual.includes(brief));
} catch (error) {
if (error instanceof Error) return false;
@@ -45,28 +45,28 @@ async function snapshotObjectiveMapsToUltragoalPlan(repoRoot: string, snapshotOb
}
}
async function canReconcileCompletedTaskScopedAggregateSnapshot(repoRoot: string, plan: UltragoalPlan, goal: UltragoalItem, snapshotObjective: string, evidence: string): Promise<boolean> {
async function canReconcileCompletedTaskScopedAggregateSnapshot(repoRoot: string, plan: UlwLoopPlan, goal: UlwLoopItem, snapshotObjective: string, evidence: string): Promise<boolean> {
if (codexGoalMode(plan) !== "aggregate") return false;
if (goal.status !== "in_progress" || plan.activeGoalId !== goal.id) return false;
if (isFinalRunCompletionCandidate(plan, goal)) return snapshotObjectiveMapsToUltragoalPlan(repoRoot, snapshotObjective);
if (!textMentionsUltragoalPlanArtifact(evidence) || !textMentionsGoalId(evidence, goal.id)) return false;
if (isFinalRunCompletionCandidate(plan, goal)) return snapshotObjectiveMapsToUlwLoopPlan(repoRoot, snapshotObjective);
if (!textMentionsUlwLoopPlanArtifact(evidence) || !textMentionsGoalId(evidence, goal.id)) return false;
if (!textHasCompletionValidationEvidence(evidence)) return false;
return snapshotObjectiveMapsToUltragoalPlan(repoRoot, snapshotObjective);
return snapshotObjectiveMapsToUlwLoopPlan(repoRoot, snapshotObjective);
}
function buildCompletedLegacyGoalRemediation(goal: UltragoalItem): string {
function buildCompletedLegacyGoalRemediation(goal: UlwLoopItem): string {
return [
"If get_goal returns a different completed legacy/thread objective, do not repeat --status complete in this thread.",
`Record a non-terminal blocker with: omo ultragoal checkpoint --goal-id ${goal.id} --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json "<different completed get_goal JSON or path>".`,
`Record a non-terminal blocker with: omo ulw-loop checkpoint --goal-id ${goal.id} --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json "<different completed get_goal JSON or path>".`,
"Then continue only from a Codex goal context with no active/completed conflicting goal, in the same repo/worktree, and create the intended goal there.",
].join(" ");
}
function buildTaskScopedAggregateReconciliationHint(goal: UltragoalItem, final: boolean): string {
function buildTaskScopedAggregateReconciliationHint(goal: UlwLoopItem, final: boolean): string {
if (final) {
return ` Final task-scoped aggregate reconciliation requires the checkpoint goal to be the active in-progress final OMO goal and the completed get_goal objective to map to the ultragoal brief or artifact. ${buildCompletedLegacyGoalRemediation(goal)}`;
return ` Final task-scoped aggregate reconciliation requires the checkpoint goal to be the active in-progress final OMO goal and the completed get_goal objective to map to the ulw-loop brief or artifact. ${buildCompletedLegacyGoalRemediation(goal)}`;
}
return ` Completed task-scoped aggregate reconciliation requires the checkpoint goal to be the active in-progress OMO goal, evidence that names that active OMO goal id, names .omo/ultragoal/goals.json or ledger.jsonl, includes completed implementation plus validation/review evidence, and a get_goal objective that maps to the ultragoal brief/artifact. ${buildCompletedLegacyGoalRemediation(goal)}`;
return ` Completed task-scoped aggregate reconciliation requires the checkpoint goal to be the active in-progress OMO goal, evidence that names that active OMO goal id, names .omo/ulw-loop/goals.json or ledger.jsonl, includes completed implementation plus validation/review evidence, and a get_goal objective that maps to the ulw-loop brief/artifact. ${buildCompletedLegacyGoalRemediation(goal)}`;
}
async function readJsonInput(raw: string | undefined, repoRoot: string): Promise<unknown> {
@@ -74,15 +74,15 @@ async function readJsonInput(raw: string | undefined, repoRoot: string): Promise
const trimmed = raw.trim();
try { return JSON.parse(trimmed); } catch (error) { if (!(error instanceof SyntaxError)) throw error; }
const path = resolve(repoRoot, trimmed);
if (!existsSync(path)) return ultragoalFail("Quality gate JSON is neither valid JSON nor a readable path.", "ultragoal_json_input_invalid");
try { return JSON.parse(await readFile(path, "utf8")); } catch (error) { return ultragoalFail(`Quality gate path does not contain valid JSON${error instanceof Error ? `: ${error.message}` : "."}`, "ultragoal_json_input_invalid"); }
if (!existsSync(path)) return ulwLoopFail("Quality gate JSON is neither valid JSON nor a readable path.", "ulw_loop_json_input_invalid");
try { return JSON.parse(await readFile(path, "utf8")); } catch (error) { return ulwLoopFail(`Quality gate path does not contain valid JSON${error instanceof Error ? `: ${error.message}` : "."}`, "ulw_loop_json_input_invalid"); }
}
function makeAggregateCompletion(now: string, evidence: string, codexGoal: unknown): UltragoalAggregateCompletion {
function makeAggregateCompletion(now: string, evidence: string, codexGoal: unknown): UlwLoopAggregateCompletion {
return { status: "complete", completedAt: now, evidence, codexGoal };
}
function applyBlockedOrFailed(goal: UltragoalItem, plan: UltragoalPlan, status: "failed" | "blocked", evidence: string, now: string): void {
function applyBlockedOrFailed(goal: UlwLoopItem, plan: UlwLoopPlan, status: "failed" | "blocked", evidence: string, now: string): void {
const signature = classifyExternalAuthorizationBlocker(evidence);
const occurrences = signature === null ? 0 : sameBlockerOccurrences(plan, signature) + 1;
const needsDecision = signature !== null && occurrences >= 3;
@@ -95,15 +95,15 @@ function applyBlockedOrFailed(goal: UltragoalItem, plan: UltragoalPlan, status:
if (plan.activeGoalId === goal.id) delete plan.activeGoalId;
}
function ledgerKind(status: CheckpointUltragoalArgs["status"], goal: UltragoalItem, aggregateCompletion: UltragoalAggregateCompletion | undefined): UltragoalLedgerEntry["kind"] {
function ledgerKind(status: CheckpointUlwLoopArgs["status"], goal: UlwLoopItem, aggregateCompletion: UlwLoopAggregateCompletion | undefined): UlwLoopLedgerEntry["kind"] {
if (aggregateCompletion !== undefined) return "aggregate_completed";
if (status === "complete") return "goal_completed";
if (goal.status === "needs_user_decision") return "goal_needs_user_decision";
return status === "blocked" ? "goal_blocked" : "goal_failed";
}
function buildLedger(now: string, args: CheckpointUltragoalArgs, goal: UltragoalItem, qualityGate: UltragoalQualityGate | undefined, codexGoal: unknown, aggregateCompletion: UltragoalAggregateCompletion | undefined): UltragoalLedgerEntry {
const entry: UltragoalLedgerEntry = { at: now, kind: ledgerKind(args.status, goal, aggregateCompletion), goalId: goal.id, status: goal.status, evidence: args.evidence };
function buildLedger(now: string, args: CheckpointUlwLoopArgs, goal: UlwLoopItem, qualityGate: UlwLoopQualityGate | undefined, codexGoal: unknown, aggregateCompletion: UlwLoopAggregateCompletion | undefined): UlwLoopLedgerEntry {
const entry: UlwLoopLedgerEntry = { at: now, kind: ledgerKind(args.status, goal, aggregateCompletion), goalId: goal.id, status: goal.status, evidence: args.evidence };
if (codexGoal !== undefined) entry.codexGoal = codexGoal;
if (qualityGate !== undefined) entry.qualityGate = qualityGate;
if (goal.blockerSignature !== undefined) entry.blockerSignature = goal.blockerSignature;
@@ -112,15 +112,15 @@ function buildLedger(now: string, args: CheckpointUltragoalArgs, goal: Ultragoal
return entry;
}
export async function checkpointUltragoal(repoRoot: string, args: CheckpointUltragoalArgs): Promise<CheckpointUltragoalResult> {
return withUltragoalMutationLock(repoRoot, async () => {
const plan = await readUltragoalPlan(repoRoot);
export async function checkpointUlwLoop(repoRoot: string, args: CheckpointUlwLoopArgs): Promise<CheckpointUlwLoopResult> {
return withUlwLoopMutationLock(repoRoot, async () => {
const plan = await readUlwLoopPlan(repoRoot);
const goal = findGoal(plan, args.goalId);
if (args.status === "complete") requireAllCriteriaPass(goal);
const evidence = nonEmptyEvidence(args.evidence);
const now = iso();
let aggregateCompletion: UltragoalAggregateCompletion | undefined;
let qualityGate: UltragoalQualityGate | undefined;
let aggregateCompletion: UlwLoopAggregateCompletion | undefined;
let qualityGate: UlwLoopQualityGate | undefined;
let codexGoal: unknown;
if (args.status === "complete") {
const aggregate = codexGoalMode(plan) === "aggregate";
@@ -131,7 +131,7 @@ export async function checkpointUltragoal(repoRoot: string, args: CheckpointUltr
if (!reconciliation.ok) {
const objective = snapshot?.objective;
const taskScoped = snapshot?.available === true && snapshot.status === "complete" && objective !== undefined && normalizeObjective(objective) !== normalizeObjective(expectedCodexObjective(plan, goal)) && await canReconcileCompletedTaskScopedAggregateSnapshot(repoRoot, plan, goal, objective, evidence);
if (!taskScoped) throw new UltragoalError(`${formatCodexGoalReconciliation(reconciliation)}${aggregate && snapshot?.status === "complete" && objective !== undefined ? buildTaskScopedAggregateReconciliationHint(goal, final) : ""}`, "ultragoal_codex_snapshot_mismatch");
if (!taskScoped) throw new UlwLoopError(`${formatCodexGoalReconciliation(reconciliation)}${aggregate && snapshot?.status === "complete" && objective !== undefined ? buildTaskScopedAggregateReconciliationHint(goal, final) : ""}`, "ulw_loop_codex_snapshot_mismatch");
aggregateCompletion = makeAggregateCompletion(now, evidence, codexGoal);
}
if (final) aggregateCompletion = makeAggregateCompletion(now, evidence, codexGoal);
@@ -1,7 +1,7 @@
// biome-ignore-all format: keep this module under the mandated pure LOC budget.
import { readFile } from "node:fs/promises";
import { UltragoalError } from "./types.js";
import { UlwLoopError } from "./types.js";
type RecordEvidenceCliArgs = { readonly goalId: string; readonly criterionId: string; readonly status: "pass" | "fail" | "blocked"; readonly evidence: string; readonly notes?: string };
@@ -59,7 +59,7 @@ export async function readJsonInput(value: string | undefined): Promise<unknown
try { return JSON.parse(looksLikeJson(value) ? value : await readFile(value, "utf8")); }
catch (error) {
const message = error instanceof Error ? error.message : "unknown error";
throw new UltragoalError(`Invalid JSON input: ${message}`, "ULTRAGOAL_JSON_INPUT_INVALID", { cause: error });
throw new UlwLoopError(`Invalid JSON input: ${message}`, "ULW_LOOP_JSON_INPUT_INVALID", { cause: error });
}
}
@@ -69,14 +69,14 @@ export async function parseCodexGoalJson(value: string | undefined): Promise<str
try { JSON.parse(raw); return raw; }
catch (error) {
const message = error instanceof Error ? error.message : "unknown error";
throw new UltragoalError(`Invalid --codex-goal-json: ${message}`, "ULTRAGOAL_CODEX_GOAL_JSON_INVALID", { cause: error });
throw new UlwLoopError(`Invalid --codex-goal-json: ${message}`, "ULW_LOOP_CODEX_GOAL_JSON_INVALID", { cause: error });
}
}
function required(argv: readonly string[], flag: string, code: string): string {
const value = readValue(argv, flag)?.trim();
if (value) return value;
throw new UltragoalError(`Missing ${flag}.`, code, { details: { flag } });
throw new UlwLoopError(`Missing ${flag}.`, code, { details: { flag } });
}
function evidenceStatus(value: string): RecordEvidenceCliArgs["status"] {
@@ -84,12 +84,12 @@ function evidenceStatus(value: string): RecordEvidenceCliArgs["status"] {
case "pass": return "pass";
case "fail": return "fail";
case "blocked": return "blocked";
default: throw new UltragoalError("Invalid --status; expected pass, fail, or blocked.", "ULTRAGOAL_EVIDENCE_STATUS_INVALID", { details: { status: value } });
default: throw new UlwLoopError("Invalid --status; expected pass, fail, or blocked.", "ULW_LOOP_EVIDENCE_STATUS_INVALID", { details: { status: value } });
}
}
export function parseRecordEvidenceArgs(argv: readonly string[]): RecordEvidenceCliArgs {
const result = { goalId: required(argv, "--goal-id", "ULTRAGOAL_GOAL_ID_REQUIRED"), criterionId: required(argv, "--criterion-id", "ULTRAGOAL_CRITERION_ID_REQUIRED"), status: evidenceStatus(required(argv, "--status", "ULTRAGOAL_EVIDENCE_STATUS_REQUIRED")), evidence: required(argv, "--evidence", "ULTRAGOAL_EVIDENCE_REQUIRED") };
const result = { goalId: required(argv, "--goal-id", "ULW_LOOP_GOAL_ID_REQUIRED"), criterionId: required(argv, "--criterion-id", "ULW_LOOP_CRITERION_ID_REQUIRED"), status: evidenceStatus(required(argv, "--status", "ULW_LOOP_EVIDENCE_STATUS_REQUIRED")), evidence: required(argv, "--evidence", "ULW_LOOP_EVIDENCE_REQUIRED") };
const notes = readValue(argv, "--notes")?.trim();
return notes ? { ...result, notes } : result;
}
@@ -1,28 +1,28 @@
// biome-ignore-all format: keep cli-commands dispatcher under the 200 pure LOC budget.
import { readFile } from "node:fs/promises";
import { checkpointUltragoal } from "./checkpoint.js";
import { checkpointUlwLoop } from "./checkpoint.js";
import { hasFlag, parseCodexGoalJson, parseRecordEvidenceArgs, positionalText, readStdin, readValue } from "./cli-arg-parser.js";
import { blockedDecisionHandoff, normalizeCodexGoalMode, printJson, printStatus, ULTRAGOAL_HELP } from "./cli-output.js";
import { blockedDecisionHandoff, normalizeCodexGoalMode, printJson, printStatus, ULW_LOOP_HELP } from "./cli-output.js";
import { parseSteeringProposal, printSteerResult } from "./cli-steering.js";
import { buildCodexGoalInstruction } from "./codex-goal-instruction.js";
import { recordEvidence } from "./evidence.js";
import { addUltragoalGoal, createUltragoalPlan, startNextUltragoal, summarizeUltragoalPlan } from "./plan-crud.js";
import { readUltragoalPlan } from "./plan-io.js";
import { addUlwLoopGoal, createUlwLoopPlan, startNextUlwLoop, summarizeUlwLoopPlan } from "./plan-crud.js";
import { readUlwLoopPlan } from "./plan-io.js";
import { recordFinalReviewBlockers } from "./review-blockers.js";
import { steerUltragoal } from "./steering.js";
import type { UltragoalItem } from "./types.js";
import { UltragoalError } from "./types.js";
import { steerUlwLoop } from "./steering.js";
import type { UlwLoopItem } from "./types.js";
import { UlwLoopError } from "./types.js";
type CheckpointStatus = "complete" | "failed" | "blocked";
export async function ultragoalCommand(argv: readonly string[]): Promise<number> {
export async function ulwLoopCommand(argv: readonly string[]): Promise<number> {
const command = argv[0] ?? "help";
const rest = argv.slice(1);
const repoRoot = process.cwd();
const json = hasFlag(rest, "--json");
try {
switch (command) {
case "help": case "--help": case "-h": process.stdout.write(`${ULTRAGOAL_HELP}\n`); return 0;
case "help": case "--help": case "-h": process.stdout.write(`${ULW_LOOP_HELP}\n`); return 0;
case "create-goals": return await createGoals(repoRoot, rest, json);
case "status": return await status(repoRoot, json);
case "complete-goals": return await completeGoals(repoRoot, rest, json);
@@ -32,12 +32,12 @@ export async function ultragoalCommand(argv: readonly string[]): Promise<number>
case "criteria": return await criteria(repoRoot, rest, json);
case "record-evidence": return await captureEvidence(repoRoot, rest, json);
case "record-review-blockers": return await reviewBlockers(repoRoot, rest, json);
default: process.stdout.write(`${ULTRAGOAL_HELP}\n`); return 1;
default: process.stdout.write(`${ULW_LOOP_HELP}\n`); return 1;
}
} catch (error) {
if (error instanceof UltragoalError) process.stderr.write(`[ultragoal] ${error.message}\n`);
else if (error instanceof Error) process.stderr.write(`[ultragoal] unexpected: ${error.message}\n`);
else process.stderr.write("[ultragoal] unknown error\n");
if (error instanceof UlwLoopError) process.stderr.write(`[ulw-loop] ${error.message}\n`);
else if (error instanceof Error) process.stderr.write(`[ulw-loop] unexpected: ${error.message}\n`);
else process.stderr.write("[ulw-loop] unknown error\n");
return 1;
}
}
@@ -45,26 +45,26 @@ export async function ultragoalCommand(argv: readonly string[]): Promise<number>
async function createGoals(repoRoot: string, argv: readonly string[], json: boolean): Promise<number> {
const briefFile = readValue(argv, "--brief-file");
const brief = readValue(argv, "--brief") ?? (briefFile === undefined ? undefined : await readFile(briefFile, "utf8")) ?? (hasFlag(argv, "--from-stdin") ? await readStdin() : undefined) ?? positionalText(argv);
if (!brief.trim()) throw new UltragoalError("Missing brief text. Pass --brief, --brief-file, --from-stdin, or positional text.", "ULTRAGOAL_BRIEF_REQUIRED");
const plan = await createUltragoalPlan(repoRoot, { brief, codexGoalMode: normalizeCodexGoalMode(readValue(argv, "--codex-goal-mode")), force: hasFlag(argv, "--force") });
if (json) printJson({ ok: true, plan, summary: summarizeUltragoalPlan(plan) });
else process.stdout.write(`ultragoal plan created: ${plan.goals.length} goal(s)\nbrief: ${plan.briefPath}\ngoals: ${plan.goalsPath}\nledger: ${plan.ledgerPath}\n`);
if (!brief.trim()) throw new UlwLoopError("Missing brief text. Pass --brief, --brief-file, --from-stdin, or positional text.", "ULW_LOOP_BRIEF_REQUIRED");
const plan = await createUlwLoopPlan(repoRoot, { brief, codexGoalMode: normalizeCodexGoalMode(readValue(argv, "--codex-goal-mode")), force: hasFlag(argv, "--force") });
if (json) printJson({ ok: true, plan, summary: summarizeUlwLoopPlan(plan) });
else process.stdout.write(`ulw-loop plan created: ${plan.goals.length} goal(s)\nbrief: ${plan.briefPath}\ngoals: ${plan.goalsPath}\nledger: ${plan.ledgerPath}\n`);
return 0;
}
async function status(repoRoot: string, json: boolean): Promise<number> {
const plan = await readUltragoalPlan(repoRoot);
if (json) printJson({ ok: true, plan, summary: summarizeUltragoalPlan(plan) });
const plan = await readUlwLoopPlan(repoRoot);
if (json) printJson({ ok: true, plan, summary: summarizeUlwLoopPlan(plan) });
else printStatus(plan);
return 0;
}
async function completeGoals(repoRoot: string, argv: readonly string[], json: boolean): Promise<number> {
const result = await startNextUltragoal(repoRoot, { retryFailed: hasFlag(argv, "--retry-failed") });
const result = await startNextUlwLoop(repoRoot, { retryFailed: hasFlag(argv, "--retry-failed") });
if ("done" in result) {
const handoff = blockedDecisionHandoff(result.plan);
if (json) printJson({ ok: true, done: true, blocked: handoff.length > 0, handoff, summary: summarizeUltragoalPlan(result.plan), plan: result.plan });
else process.stdout.write(`${handoff || "ultragoal: all goals complete"}\n`);
if (json) printJson({ ok: true, done: true, blocked: handoff.length > 0, handoff, summary: summarizeUlwLoopPlan(result.plan), plan: result.plan });
else process.stdout.write(`${handoff || "ulw-loop: all goals complete"}\n`);
return 0;
}
const instruction = buildCodexGoalInstruction({ plan: result.plan, goal: result.goal });
@@ -78,31 +78,31 @@ async function checkpoint(repoRoot: string, argv: readonly string[], json: boole
const statusValue = checkpointStatus(required(argv, "--status"));
const evidence = required(argv, "--evidence");
const codexGoalJson = await parseCodexGoalJson(required(argv, "--codex-goal-json"));
if (codexGoalJson === undefined) throw new UltragoalError("Missing --codex-goal-json.", "ULTRAGOAL_CODEX_GOAL_JSON_REQUIRED");
if (codexGoalJson === undefined) throw new UlwLoopError("Missing --codex-goal-json.", "ULW_LOOP_CODEX_GOAL_JSON_REQUIRED");
const qualityGateJson = readValue(argv, "--quality-gate-json");
const result = await checkpointUltragoal(repoRoot, qualityGateJson === undefined ? { goalId, status: statusValue, evidence, codexGoalJson } : { goalId, status: statusValue, evidence, codexGoalJson, qualityGateJson });
if (json) printJson({ ok: true, ...result, summary: summarizeUltragoalPlan(result.plan) });
else process.stdout.write(`ultragoal checkpoint: ${result.goal.id} -> ${result.goal.status}\n`);
const result = await checkpointUlwLoop(repoRoot, qualityGateJson === undefined ? { goalId, status: statusValue, evidence, codexGoalJson } : { goalId, status: statusValue, evidence, codexGoalJson, qualityGateJson });
if (json) printJson({ ok: true, ...result, summary: summarizeUlwLoopPlan(result.plan) });
else process.stdout.write(`ulw-loop checkpoint: ${result.goal.id} -> ${result.goal.status}\n`);
return 0;
}
async function steer(repoRoot: string, argv: readonly string[], json: boolean): Promise<number> {
const proposal = await parseSteeringProposal(argv);
const result = await steerUltragoal(repoRoot, proposal);
const result = await steerUlwLoop(repoRoot, proposal);
printSteerResult(result, json);
return result.accepted ? 0 : 1;
}
async function addGoal(repoRoot: string, argv: readonly string[], json: boolean): Promise<number> {
const result = await addUltragoalGoal(repoRoot, { title: required(argv, "--title"), objective: required(argv, "--objective") });
if (json) printJson({ ok: true, plan: result.plan, goal: result.goal, summary: summarizeUltragoalPlan(result.plan) });
else { process.stdout.write(`ultragoal added goal: ${result.goal.id}\n`); printStatus(result.plan); }
const result = await addUlwLoopGoal(repoRoot, { title: required(argv, "--title"), objective: required(argv, "--objective") });
if (json) printJson({ ok: true, plan: result.plan, goal: result.goal, summary: summarizeUlwLoopPlan(result.plan) });
else { process.stdout.write(`ulw-loop added goal: ${result.goal.id}\n`); printStatus(result.plan); }
return 0;
}
async function criteria(repoRoot: string, argv: readonly string[], json: boolean): Promise<number> {
const goalId = required(argv, "--goal-id");
const goal = findGoal(await readUltragoalPlan(repoRoot), goalId);
const goal = findGoal(await readUlwLoopPlan(repoRoot), goalId);
if (json) printJson({ ok: true, goalId: goal.id, criteria: goal.successCriteria });
else process.stdout.write(`criteria for ${goal.id}:\n${goal.successCriteria.map((c) => `- ${c.id} [${c.status}] (${c.userModel}) ${c.scenario} evidence: ${c.capturedEvidence ?? "pending"}`).join("\n")}\n`);
return 0;
@@ -110,33 +110,33 @@ async function criteria(repoRoot: string, argv: readonly string[], json: boolean
async function captureEvidence(repoRoot: string, argv: readonly string[], json: boolean): Promise<number> {
const result = await recordEvidence(repoRoot, parseRecordEvidenceArgs(argv));
if (json) printJson({ ok: true, ...result, summary: summarizeUltragoalPlan(result.plan) });
else process.stdout.write(`ultragoal evidence recorded: ${result.goal.id}/${result.criterion.id} -> ${result.criterion.status}\n`);
if (json) printJson({ ok: true, ...result, summary: summarizeUlwLoopPlan(result.plan) });
else process.stdout.write(`ulw-loop evidence recorded: ${result.goal.id}/${result.criterion.id} -> ${result.criterion.status}\n`);
return 0;
}
async function reviewBlockers(repoRoot: string, argv: readonly string[], json: boolean): Promise<number> {
const codexGoalJson = await parseCodexGoalJson(required(argv, "--codex-goal-json"));
if (codexGoalJson === undefined) throw new UltragoalError("Missing --codex-goal-json.", "ULTRAGOAL_CODEX_GOAL_JSON_REQUIRED");
if (codexGoalJson === undefined) throw new UlwLoopError("Missing --codex-goal-json.", "ULW_LOOP_CODEX_GOAL_JSON_REQUIRED");
const result = await recordFinalReviewBlockers(repoRoot, { goalId: required(argv, "--goal-id"), title: required(argv, "--title"), objective: required(argv, "--objective"), evidence: required(argv, "--evidence"), codexGoalJson });
if (json) printJson({ ok: true, plan: result.plan, blockedGoal: result.blockedGoal, goal: result.newGoal, ledgerEntries: result.ledgerEntries, summary: summarizeUltragoalPlan(result.plan) });
else process.stdout.write(`ultragoal final review blockers recorded: ${result.blockedGoal.id} -> review_blocked; added ${result.newGoal.id}\n`);
if (json) printJson({ ok: true, plan: result.plan, blockedGoal: result.blockedGoal, goal: result.newGoal, ledgerEntries: result.ledgerEntries, summary: summarizeUlwLoopPlan(result.plan) });
else process.stdout.write(`ulw-loop final review blockers recorded: ${result.blockedGoal.id} -> review_blocked; added ${result.newGoal.id}\n`);
return 0;
}
function required(argv: readonly string[], flag: string): string {
const value = readValue(argv, flag)?.trim();
if (value) return value;
throw new UltragoalError(`Missing ${flag}.`, "ULTRAGOAL_ARGUMENT_MISSING", { details: { flag } });
throw new UlwLoopError(`Missing ${flag}.`, "ULW_LOOP_ARGUMENT_MISSING", { details: { flag } });
}
function checkpointStatus(value: string): CheckpointStatus {
if (value === "complete" || value === "failed" || value === "blocked") return value;
throw new UltragoalError("Missing or invalid --status; expected complete, failed, or blocked.", "ULTRAGOAL_STATUS_INVALID", { details: { status: value } });
throw new UlwLoopError("Missing or invalid --status; expected complete, failed, or blocked.", "ULW_LOOP_STATUS_INVALID", { details: { status: value } });
}
function findGoal(plan: { readonly goals: readonly UltragoalItem[] }, goalId: string): UltragoalItem {
function findGoal(plan: { readonly goals: readonly UlwLoopItem[] }, goalId: string): UlwLoopItem {
const goal = plan.goals.find((candidate) => candidate.id === goalId);
if (goal !== undefined) return goal;
throw new UltragoalError(`Unknown ultragoal id: ${goalId}.`, "ULTRAGOAL_GOAL_NOT_FOUND", { details: { goalId } });
throw new UlwLoopError(`Unknown ulw-loop id: ${goalId}.`, "ULW_LOOP_GOAL_NOT_FOUND", { details: { goalId } });
}
@@ -1,16 +1,16 @@
import type { UltragoalCodexGoalMode, UltragoalItem, UltragoalPlan } from "./types.js";
import { UltragoalError } from "./types.js";
import type { UlwLoopCodexGoalMode, UlwLoopItem, UlwLoopPlan } from "./types.js";
import { UlwLoopError } from "./types.js";
export const ULTRAGOAL_HELP = `Usage:
omo ultragoal create-goals --brief "..." [--brief-file <path>] [--from-stdin] [--codex-goal-mode aggregate|per_story] [--force] [--json]
omo ultragoal status [--json]
omo ultragoal complete-goals [--retry-failed] [--json]
omo ultragoal criteria --goal-id <id> [--json]
omo ultragoal record-evidence --goal-id <id> --criterion-id <id> --status pass|fail|blocked --evidence "..." [--notes "..."] [--json]
omo ultragoal checkpoint --goal-id <id> --status complete|failed|blocked --evidence "..." --codex-goal-json <...> [--quality-gate-json <...>] [--json]
omo ultragoal steer --kind <kind> ... --evidence "..." --rationale "..." [--json]
omo ultragoal add-goal --title "..." --objective "..." [--json]
omo ultragoal record-review-blockers --goal-id <id> --title "..." --objective "..." --evidence "..." --codex-goal-json <...> [--json]`;
export const ULW_LOOP_HELP = `Usage:
omo ulw-loop create-goals --brief "..." [--brief-file <path>] [--from-stdin] [--codex-goal-mode aggregate|per_story] [--force] [--json]
omo ulw-loop status [--json]
omo ulw-loop complete-goals [--retry-failed] [--json]
omo ulw-loop criteria --goal-id <id> [--json]
omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass|fail|blocked --evidence "..." [--notes "..."] [--json]
omo ulw-loop checkpoint --goal-id <id> --status complete|failed|blocked --evidence "..." --codex-goal-json <...> [--quality-gate-json <...>] [--json]
omo ulw-loop steer --kind <kind> ... --evidence "..." --rationale "..." [--json]
omo ulw-loop add-goal --title "..." --objective "..." [--json]
omo ulw-loop record-review-blockers --goal-id <id> --title "..." --objective "..." --evidence "..." --codex-goal-json <...> [--json]`;
type CriteriaCounts = { readonly pass: number; readonly total: number };
@@ -18,16 +18,16 @@ export function printJson(value: unknown): void {
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
}
function criteriaCounts(goal: UltragoalItem): CriteriaCounts {
function criteriaCounts(goal: UlwLoopItem): CriteriaCounts {
let pass = 0;
for (const criterion of goal.successCriteria) if (criterion.status === "pass") pass += 1;
return { pass, total: goal.successCriteria.length };
}
export function printStatus(plan: UltragoalPlan): void {
export function printStatus(plan: UlwLoopPlan): void {
let totalCriteria = 0;
let passCriteria = 0;
const lines = ["ultragoal status", "", "goals:"];
const lines = ["ulw-loop status", "", "goals:"];
for (const goal of plan.goals) {
const counts = criteriaCounts(goal);
totalCriteria += counts.total;
@@ -39,23 +39,23 @@ export function printStatus(plan: UltragoalPlan): void {
process.stdout.write(`${lines.join("\n")}\n`);
}
export function blockedDecisionHandoff(plan: UltragoalPlan): string {
export function blockedDecisionHandoff(plan: UlwLoopPlan): string {
const blocked = plan.goals.find((goal) => goal.status === "needs_user_decision" && goal.nonRetriable);
if (blocked === undefined) return "";
return [
"ultragoal: blocked on repeated external authorization; no retryable failed goals remain.",
"ulw-loop: blocked on repeated external authorization; no retryable failed goals remain.",
`Goal: ${blocked.id} - ${blocked.title}`,
`Required external decision: ${blocked.requiredExternalDecision ?? "provide the missing authorization or choose a different unblock path"}.`,
"Do not run complete-goals --retry-failed again until external state changes or the user authorizes an unblock path.",
].join("\n");
}
export function normalizeCodexGoalMode(value: string | undefined): UltragoalCodexGoalMode {
export function normalizeCodexGoalMode(value: string | undefined): UlwLoopCodexGoalMode {
if (value === undefined) return "aggregate";
if (value === "aggregate" || value === "per_story") return value;
throw new UltragoalError(
throw new UlwLoopError(
"Invalid --codex-goal-mode; expected aggregate or per_story.",
"ULTRAGOAL_CODEX_GOAL_MODE_INVALID",
"ULW_LOOP_CODEX_GOAL_MODE_INVALID",
{ details: { value } },
);
}
@@ -1,63 +1,63 @@
// biome-ignore-all format: keep this module under the mandated pure LOC budget.
import { parseGoalArg, readJsonInput, readValue } from "./cli-arg-parser.js";
import { printJson, printStatus } from "./cli-output.js";
import type { SteerUltragoalResult, UltragoalSteeringChildGoal, UltragoalSteeringMutationKind, UltragoalSteeringProposal, UltragoalSteeringSource, UltragoalSuccessCriterionUserModel } from "./types.js";
import { ULTRAGOAL_STEERING_MUTATION_KINDS, ULTRAGOAL_SUCCESS_CRITERION_USER_MODELS, UltragoalError } from "./types.js";
import type { SteerUlwLoopResult, UlwLoopSteeringChildGoal, UlwLoopSteeringMutationKind, UlwLoopSteeringProposal, UlwLoopSteeringSource, UlwLoopSuccessCriterionUserModel } from "./types.js";
import { ULW_LOOP_STEERING_MUTATION_KINDS, ULW_LOOP_SUCCESS_CRITERION_USER_MODELS, UlwLoopError } from "./types.js";
const SOURCES = ["user_prompt_submit", "finding", "cli"] as const satisfies readonly UltragoalSteeringSource[];
const SOURCES = ["user_prompt_submit", "finding", "cli"] as const satisfies readonly UlwLoopSteeringSource[];
export type CliSteeringProposal = UltragoalSteeringProposal & { readonly goalId?: string; readonly scenario?: string; readonly expectedEvidence?: string; readonly userModel?: UltragoalSuccessCriterionUserModel };
export type CliSteeringProposal = UlwLoopSteeringProposal & { readonly goalId?: string; readonly scenario?: string; readonly expectedEvidence?: string; readonly userModel?: UlwLoopSuccessCriterionUserModel };
function isKind(value: string | undefined): value is UltragoalSteeringMutationKind { return value !== undefined && ULTRAGOAL_STEERING_MUTATION_KINDS.some((kind) => kind === value); }
function isSource(value: string | undefined): value is UltragoalSteeringSource { return value !== undefined && SOURCES.some((source) => source === value); }
function isModel(value: string): value is UltragoalSuccessCriterionUserModel { return ULTRAGOAL_SUCCESS_CRITERION_USER_MODELS.some((model) => model === value); }
function fail(message: string, code: string, details: Record<string, unknown>): never { throw new UltragoalError(message, code, { details }); }
function text(value: string | undefined, field: string): string | undefined { if (value === undefined) return undefined; const trimmed = value.trim(); if (trimmed.length > 0) return trimmed; return fail(`Empty ${field}.`, "ULTRAGOAL_STEERING_FIELD_EMPTY", { field }); }
function required(argv: readonly string[], flag: string): string { const value = text(readValue(argv, flag), flag); return value ?? fail(`Missing ${flag}.`, "ULTRAGOAL_STEERING_FIELD_REQUIRED", { flag }); }
function requiredGoal(argv: readonly string[]): string { const value = text(parseGoalArg(argv), "--goal-id"); return value ?? fail("Missing --goal-id.", "ULTRAGOAL_GOAL_ID_REQUIRED", { flag: "--goal-id" }); }
function isKind(value: string | undefined): value is UlwLoopSteeringMutationKind { return value !== undefined && ULW_LOOP_STEERING_MUTATION_KINDS.some((kind) => kind === value); }
function isSource(value: string | undefined): value is UlwLoopSteeringSource { return value !== undefined && SOURCES.some((source) => source === value); }
function isModel(value: string): value is UlwLoopSuccessCriterionUserModel { return ULW_LOOP_SUCCESS_CRITERION_USER_MODELS.some((model) => model === value); }
function fail(message: string, code: string, details: Record<string, unknown>): never { throw new UlwLoopError(message, code, { details }); }
function text(value: string | undefined, field: string): string | undefined { if (value === undefined) return undefined; const trimmed = value.trim(); if (trimmed.length > 0) return trimmed; return fail(`Empty ${field}.`, "ULW_LOOP_STEERING_FIELD_EMPTY", { field }); }
function required(argv: readonly string[], flag: string): string { const value = text(readValue(argv, flag), flag); return value ?? fail(`Missing ${flag}.`, "ULW_LOOP_STEERING_FIELD_REQUIRED", { flag }); }
function requiredGoal(argv: readonly string[]): string { const value = text(parseGoalArg(argv), "--goal-id"); return value ?? fail("Missing --goal-id.", "ULW_LOOP_GOAL_ID_REQUIRED", { flag: "--goal-id" }); }
function readObject(value: object, key: string): unknown { return Object.entries(value).find(([name]) => name === key)?.[1]; }
function isPlain(value: unknown): value is object { return typeof value === "object" && value !== null && !Array.isArray(value); }
function objectText(value: object, key: string): string | undefined { const candidate = readObject(value, key); return typeof candidate === "string" ? candidate : undefined; }
export function parseSteeringKind(argv: readonly string[]): UltragoalSteeringMutationKind {
export function parseSteeringKind(argv: readonly string[]): UlwLoopSteeringMutationKind {
const value = readValue(argv, "--kind");
if (isKind(value)) return value;
return value === undefined ? fail("Missing --kind.", "ULTRAGOAL_STEERING_KIND_REQUIRED", { flag: "--kind" }) : fail(`Invalid --kind: ${value}.`, "ULTRAGOAL_STEERING_KIND_INVALID", { value, expected: ULTRAGOAL_STEERING_MUTATION_KINDS });
return value === undefined ? fail("Missing --kind.", "ULW_LOOP_STEERING_KIND_REQUIRED", { flag: "--kind" }) : fail(`Invalid --kind: ${value}.`, "ULW_LOOP_STEERING_KIND_INVALID", { value, expected: ULW_LOOP_STEERING_MUTATION_KINDS });
}
export function parseSteeringSource(argv: readonly string[]): UltragoalSteeringSource {
export function parseSteeringSource(argv: readonly string[]): UlwLoopSteeringSource {
const value = readValue(argv, "--source");
if (value === undefined) return "cli";
return isSource(value) ? value : fail(`Invalid --source: ${value}.`, "ULTRAGOAL_STEERING_SOURCE_INVALID", { value, expected: SOURCES });
return isSource(value) ? value : fail(`Invalid --source: ${value}.`, "ULW_LOOP_STEERING_SOURCE_INVALID", { value, expected: SOURCES });
}
function child(value: unknown): UltragoalSteeringChildGoal | null {
function child(value: unknown): UlwLoopSteeringChildGoal | null {
if (!isPlain(value)) return null;
const title = text(objectText(value, "title"), "title"); const objective = text(objectText(value, "objective"), "objective");
if (title === undefined || objective === undefined) return null;
return { title, objective };
}
async function children(argv: readonly string[], flag: string, needed: boolean): Promise<UltragoalSteeringChildGoal[]> {
async function children(argv: readonly string[], flag: string, needed: boolean): Promise<UlwLoopSteeringChildGoal[]> {
const input = needed ? required(argv, flag) : text(readValue(argv, flag), flag);
if (input === undefined) return [];
const raw = await readJsonInput(input);
if (!Array.isArray(raw)) return fail(`${flag} must be a JSON array.`, "ULTRAGOAL_STEERING_JSON_ARRAY_REQUIRED", { flag });
const parsed: UltragoalSteeringChildGoal[] = [];
for (const item of raw) { const next = child(item); if (next === null) return fail(`${flag} entries require title/objective.`, "ULTRAGOAL_STEERING_CHILD_INVALID", { flag }); parsed.push(next); }
if (!Array.isArray(raw)) return fail(`${flag} must be a JSON array.`, "ULW_LOOP_STEERING_JSON_ARRAY_REQUIRED", { flag });
const parsed: UlwLoopSteeringChildGoal[] = [];
for (const item of raw) { const next = child(item); if (next === null) return fail(`${flag} entries require title/objective.`, "ULW_LOOP_STEERING_CHILD_INVALID", { flag }); parsed.push(next); }
return parsed;
}
async function stringArray(argv: readonly string[], flag: string): Promise<string[]> {
const raw = await readJsonInput(required(argv, flag));
if (!Array.isArray(raw)) return fail(`${flag} must be a JSON array.`, "ULTRAGOAL_STEERING_JSON_ARRAY_REQUIRED", { flag });
if (!Array.isArray(raw)) return fail(`${flag} must be a JSON array.`, "ULW_LOOP_STEERING_JSON_ARRAY_REQUIRED", { flag });
const values: string[] = [];
for (const item of raw) { if (typeof item !== "string") return fail(`${flag} entries must be strings.`, "ULTRAGOAL_STEERING_STRING_ARRAY_REQUIRED", { flag }); values.push(text(item, flag) ?? ""); }
for (const item of raw) { if (typeof item !== "string") return fail(`${flag} entries must be strings.`, "ULW_LOOP_STEERING_STRING_ARRAY_REQUIRED", { flag }); values.push(text(item, flag) ?? ""); }
return values;
}
function model(value: string | undefined): UltragoalSuccessCriterionUserModel | undefined { const trimmed = text(value, "--user-model"); if (trimmed === undefined) return undefined; return isModel(trimmed) ? trimmed : fail(`Invalid --user-model: ${trimmed}.`, "ULTRAGOAL_STEERING_USER_MODEL_INVALID", { value: trimmed, expected: ULTRAGOAL_SUCCESS_CRITERION_USER_MODELS }); }
function neverKind(kind: never): never { return fail(`Unsupported steering kind: ${String(kind)}.`, "ULTRAGOAL_STEERING_KIND_UNSUPPORTED", { kind }); }
function model(value: string | undefined): UlwLoopSuccessCriterionUserModel | undefined { const trimmed = text(value, "--user-model"); if (trimmed === undefined) return undefined; return isModel(trimmed) ? trimmed : fail(`Invalid --user-model: ${trimmed}.`, "ULW_LOOP_STEERING_USER_MODEL_INVALID", { value: trimmed, expected: ULW_LOOP_SUCCESS_CRITERION_USER_MODELS }); }
function neverKind(kind: never): never { return fail(`Unsupported steering kind: ${String(kind)}.`, "ULW_LOOP_STEERING_KIND_UNSUPPORTED", { kind }); }
export async function parseSteeringProposal(argv: readonly string[]): Promise<CliSteeringProposal> {
const kind = parseSteeringKind(argv); const source = parseSteeringSource(argv); const base = { kind, source, evidence: required(argv, "--evidence"), rationale: required(argv, "--rationale") };
@@ -65,15 +65,15 @@ export async function parseSteeringProposal(argv: readonly string[]): Promise<Cl
case "add_subgoal": return normalizeSteeringProposal({ ...base, title: required(argv, "--title"), objective: required(argv, "--objective") });
case "split_subgoal": { const goalId = requiredGoal(argv); return normalizeSteeringProposal({ ...base, goalId, targetGoalId: goalId, childGoals: await children(argv, "--children", true) }); }
case "reorder_pending": return normalizeSteeringProposal({ ...base, pendingOrder: await stringArray(argv, "--order") });
case "revise_pending_wording": { const goalId = requiredGoal(argv); const revisedTitle = readValue(argv, "--title"); const revisedObjective = readValue(argv, "--objective"); if (revisedTitle === undefined && revisedObjective === undefined) return fail("revise_pending_wording requires --title or --objective.", "ULTRAGOAL_STEERING_UPDATE_REQUIRED", { kind }); return normalizeSteeringProposal({ ...base, goalId, targetGoalId: goalId, ...(revisedTitle === undefined ? {} : { revisedTitle }), ...(revisedObjective === undefined ? {} : { revisedObjective }) }); }
case "revise_criterion": { const goalId = requiredGoal(argv); const criterionId = required(argv, "--criterion-id"); const scenario = readValue(argv, "--scenario"); const expectedEvidence = readValue(argv, "--expected-evidence"); const userModel = model(readValue(argv, "--user-model")); if (scenario === undefined && expectedEvidence === undefined && userModel === undefined) return fail("revise_criterion requires scenario, expected-evidence, or user-model.", "ULTRAGOAL_STEERING_UPDATE_REQUIRED", { kind }); return normalizeSteeringProposal({ ...base, goalId, targetGoalId: goalId, criterionId, ...(scenario === undefined ? {} : { scenario }), ...(expectedEvidence === undefined ? {} : { expectedEvidence }), ...(userModel === undefined ? {} : { userModel }) }); }
case "revise_pending_wording": { const goalId = requiredGoal(argv); const revisedTitle = readValue(argv, "--title"); const revisedObjective = readValue(argv, "--objective"); if (revisedTitle === undefined && revisedObjective === undefined) return fail("revise_pending_wording requires --title or --objective.", "ULW_LOOP_STEERING_UPDATE_REQUIRED", { kind }); return normalizeSteeringProposal({ ...base, goalId, targetGoalId: goalId, ...(revisedTitle === undefined ? {} : { revisedTitle }), ...(revisedObjective === undefined ? {} : { revisedObjective }) }); }
case "revise_criterion": { const goalId = requiredGoal(argv); const criterionId = required(argv, "--criterion-id"); const scenario = readValue(argv, "--scenario"); const expectedEvidence = readValue(argv, "--expected-evidence"); const userModel = model(readValue(argv, "--user-model")); if (scenario === undefined && expectedEvidence === undefined && userModel === undefined) return fail("revise_criterion requires scenario, expected-evidence, or user-model.", "ULW_LOOP_STEERING_UPDATE_REQUIRED", { kind }); return normalizeSteeringProposal({ ...base, goalId, targetGoalId: goalId, criterionId, ...(scenario === undefined ? {} : { scenario }), ...(expectedEvidence === undefined ? {} : { expectedEvidence }), ...(userModel === undefined ? {} : { userModel }) }); }
case "annotate_ledger": return normalizeSteeringProposal(base);
case "mark_blocked_superseded": { const goalId = requiredGoal(argv); const childGoals = await children(argv, "--replacements", false); return normalizeSteeringProposal({ ...base, goalId, targetGoalId: goalId, ...(childGoals.length === 0 ? {} : { childGoals }) }); }
default: return neverKind(kind);
}
}
function normalizedChildren(values: readonly UltragoalSteeringChildGoal[] | undefined): UltragoalSteeringChildGoal[] | undefined { if (values === undefined) return undefined; return values.map((item) => ({ title: text(item.title, "child.title") ?? "", objective: text(item.objective, "child.objective") ?? "" })); }
function normalizedChildren(values: readonly UlwLoopSteeringChildGoal[] | undefined): UlwLoopSteeringChildGoal[] | undefined { if (values === undefined) return undefined; return values.map((item) => ({ title: text(item.title, "child.title") ?? "", objective: text(item.objective, "child.objective") ?? "" })); }
function normalizedStrings(values: readonly string[] | undefined, field: string): string[] | undefined { if (values === undefined) return undefined; return values.map((value) => text(value, field) ?? ""); }
export function normalizeSteeringProposal(proposal: CliSteeringProposal): CliSteeringProposal {
@@ -84,10 +84,10 @@ export function normalizeSteeringProposal(proposal: CliSteeringProposal): CliSte
return { kind: proposal.kind, source: proposal.source, evidence, rationale, ...(goalId === undefined ? {} : { goalId }), ...(targetGoalId === undefined ? {} : { targetGoalId }), ...(targetGoalIds === undefined ? {} : { targetGoalIds }), ...(criterionId === undefined ? {} : { criterionId }), ...(title === undefined ? {} : { title }), ...(objective === undefined ? {} : { objective }), ...(childGoals === undefined ? {} : { childGoals }), ...(revisedTitle === undefined ? {} : { revisedTitle }), ...(revisedObjective === undefined ? {} : { revisedObjective }), ...(pendingOrder === undefined ? {} : { pendingOrder }), ...(blockedReason === undefined ? {} : { blockedReason }), ...(proposal.after === undefined ? {} : { after: proposal.after }), ...(directiveText === undefined ? {} : { directiveText }), ...(promptSignature === undefined ? {} : { promptSignature }), ...(idempotencyKey === undefined ? {} : { idempotencyKey }), ...(proposal.now === undefined ? {} : { now: proposal.now }), ...(scenario === undefined ? {} : { scenario }), ...(expectedEvidence === undefined ? {} : { expectedEvidence }), ...(proposal.userModel === undefined ? {} : { userModel: proposal.userModel }) };
}
export function printSteerResult(result: SteerUltragoalResult, json: boolean): void {
export function printSteerResult(result: SteerUlwLoopResult, json: boolean): void {
if (json) { printJson({ ok: result.accepted, accepted: result.accepted, rejectedReasons: result.rejectedReasons, deduped: result.deduped, audit: result.audit, plan: result.plan }); return; }
const outcome = result.deduped ? "deduped" : result.accepted ? "accepted" : "rejected";
process.stdout.write(`ultragoal steer: ${outcome} ${result.audit.kind}\n`);
process.stdout.write(`ulw-loop steer: ${outcome} ${result.audit.kind}\n`);
if (result.rejectedReasons.length > 0) process.stdout.write(`rejected: ${result.rejectedReasons.join("; ")}\n`);
if (result.audit.idempotencyKey !== undefined) process.stdout.write(`idempotency-key: ${result.audit.idempotencyKey}\n`);
printStatus(result.plan);
@@ -1,9 +1,9 @@
#!/usr/bin/env node
import { ultragoalCommand } from "./cli-commands.js";
import { runPreToolUseGoalBudgetGuardCli, runUltragoalHookCli } from "./codex-hook.js";
import { ulwLoopCommand } from "./cli-commands.js";
import { runPreToolUseGoalBudgetGuardCli, runUlwLoopHookCli } from "./codex-hook.js";
const TOP_LEVEL_HELP =
"Usage:\n omo ultragoal <subcommand> [args]\n omo hook user-prompt-submit (Codex UserPromptSubmit hook)\n omo help | --help | -h (this message)\n\nRun `omo ultragoal help` for ultragoal subcommands.\n";
"Usage:\n omo ulw-loop <subcommand> [args]\n omo hook user-prompt-submit (Codex UserPromptSubmit hook)\n omo help | --help | -h (this message)\n\nRun `omo ulw-loop help` for ulw-loop subcommands.\n";
async function main(): Promise<number> {
const argv = process.argv.slice(2);
@@ -12,11 +12,11 @@ async function main(): Promise<number> {
process.stdout.write(TOP_LEVEL_HELP);
return 0;
}
if (command === "ultragoal") return ultragoalCommand(argv.slice(1));
if (command === "ulw-loop") return ulwLoopCommand(argv.slice(1));
if (command === "hook") {
const sub = argv[1];
if (sub === "user-prompt-submit") {
await runUltragoalHookCli(process.stdin, process.stdout);
await runUlwLoopHookCli(process.stdin, process.stdout);
return 0;
}
if (sub === "pre-tool-use") {
@@ -1,40 +1,40 @@
import { codexGoalMode, expectedCodexObjective, isFinalRunCompletionCandidate } from "./goal-status.js";
import type { UltragoalCodexGoalMode, UltragoalItem, UltragoalPlan, UltragoalSuccessCriterion } from "./types.js";
import type { UlwLoopCodexGoalMode, UlwLoopItem, UlwLoopPlan, UlwLoopSuccessCriterion } from "./types.js";
export interface CodexCreateGoalPayload {
readonly objective: string;
readonly status: "active";
}
export interface UltragoalGoalInstruction {
export interface UlwLoopGoalInstruction {
readonly text: string;
readonly json: CodexCreateGoalPayload;
}
export function buildCodexGoalInstruction(args: {
readonly plan: UltragoalPlan;
readonly goal: UltragoalItem;
readonly plan: UlwLoopPlan;
readonly goal: UlwLoopItem;
readonly isFinal?: boolean;
}): UltragoalGoalInstruction {
}): UlwLoopGoalInstruction {
const mode = codexGoalMode(args.plan);
const createGoal = buildCreateGoalPayload(args.plan, args.goal);
const isFinal = args.isFinal ?? isFinalRunCompletionCandidate(args.plan, args.goal);
return { text: buildText(mode, args.plan, args.goal, createGoal, isFinal), json: createGoal };
}
function buildCreateGoalPayload(plan: UltragoalPlan, goal: UltragoalItem): CodexCreateGoalPayload {
function buildCreateGoalPayload(plan: UlwLoopPlan, goal: UlwLoopItem): CodexCreateGoalPayload {
return { objective: expectedCodexObjective(plan, goal), status: "active" };
}
function buildText(
mode: UltragoalCodexGoalMode,
plan: UltragoalPlan,
goal: UltragoalItem,
mode: UlwLoopCodexGoalMode,
plan: UlwLoopPlan,
goal: UlwLoopItem,
createGoal: CodexCreateGoalPayload,
isFinal: boolean,
): string {
return joinLines([
mode === "aggregate" ? "Ultragoal aggregate-goal handoff" : "Ultragoal active-goal handoff",
mode === "aggregate" ? "UlwLoop aggregate-goal handoff" : "UlwLoop active-goal handoff",
`Mode: ${mode}`,
`Plan: ${plan.goalsPath}`,
`Ledger: ${plan.ledgerPath}`,
@@ -56,26 +56,26 @@ function buildText(
]);
}
function modeConstraintLines(mode: UltragoalCodexGoalMode, isFinal: boolean): readonly string[] {
function modeConstraintLines(mode: UlwLoopCodexGoalMode, isFinal: boolean): readonly string[] {
if (mode === "per_story") {
return [
"- First call get_goal. If no active goal exists, call create_goal with the payload below.",
"- If a different active Codex goal exists, finish/checkpoint that goal before starting this ultragoal.",
"- If a different active Codex goal exists, finish/checkpoint that goal before starting this ulw-loop.",
"- Work only this goal until its completion audit passes.",
];
}
return [
"- Codex goal = the whole omo ultragoal run; OMO G001/G002/etc. = ledger stories.",
"- Codex goal = the whole omo ulw-loop run; OMO G001/G002/etc. = ledger stories.",
"- First call get_goal. If no active goal exists, call create_goal with the aggregate payload below.",
"- If get_goal reports the same aggregate objective as active, continue this OMO story without creating a new Codex goal.",
"- If a different active or incomplete Codex goal exists, finish/checkpoint that goal before starting this ultragoal.",
"- If a different active or incomplete Codex goal exists, finish/checkpoint that goal before starting this ulw-loop.",
isFinal
? "- This is the final story; update_goal is allowed only after the mandatory quality gate passes."
: "- This is not the final story: do not call update_goal yet; the aggregate Codex goal must remain active while later OMO stories remain.",
];
}
function checkpointLines(mode: UltragoalCodexGoalMode): readonly string[] {
function checkpointLines(mode: UlwLoopCodexGoalMode): readonly string[] {
const failureLine =
"- If blocked or failed, checkpoint with --status failed and the failure evidence; rerun complete-goals --retry-failed to resume.";
if (mode === "per_story") return [failureLine];
@@ -85,25 +85,25 @@ function checkpointLines(mode: UltragoalCodexGoalMode): readonly string[] {
];
}
function activeGoalLines(goal: UltragoalItem): readonly string[] {
function activeGoalLines(goal: UlwLoopItem): readonly string[] {
return ["Active goal:", `- id: ${goal.id}`, `- title: ${goal.title}`, `- objective: ${goal.objective}`];
}
function successCriteriaLines(criteria: readonly UltragoalSuccessCriterion[]): readonly string[] {
function successCriteriaLines(criteria: readonly UlwLoopSuccessCriterion[]): readonly string[] {
if (criteria.length === 0) return ["Success criteria:", "- No success criteria recorded for this goal."];
return ["Success criteria:", ...criteria.map(formatCriterionLine)];
}
function formatCriterionLine(criterion: UltragoalSuccessCriterion): string {
function formatCriterionLine(criterion: UlwLoopSuccessCriterion): string {
const remainingWork = criterion.status === "pending" ? " remaining work:" : "";
return `-${remainingWork} [${criterion.id}] (${criterion.userModel}) ${criterion.scenario} — expect: ${criterion.expectedEvidence} — status: ${criterion.status}`;
}
function finalSection(goal: UltragoalItem, isFinal: boolean, aggregate: boolean): string {
function finalSection(goal: UlwLoopItem, isFinal: boolean, aggregate: boolean): string {
if (!isFinal)
return "- This is not the final ultragoal story; do not run the final ai-slop-cleaner/$code-review gate yet.";
const blockerCommand = `omo ultragoal record-review-blockers --goal-id ${goal.id} --title "Resolve final code-review blockers" --objective "<blocker-resolution objective>" --evidence "<review findings>" --codex-goal-json "<active get_goal JSON or path>"`;
const checkpointCommand = `omo ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>"`;
return "- This is not the final ulw-loop story; do not run the final ai-slop-cleaner/$code-review gate yet.";
const blockerCommand = `omo ulw-loop record-review-blockers --goal-id ${goal.id} --title "Resolve final code-review blockers" --objective "<blocker-resolution objective>" --evidence "<review findings>" --codex-goal-json "<active get_goal JSON or path>"`;
const checkpointCommand = `omo ulw-loop checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>"`;
return joinLines([
"Final story — run mandatory quality gate before update_goal:",
"- Run ai-slop-cleaner on changed files even when it is a no-op, rerun verification, then run $code-review.",
@@ -1,4 +1,4 @@
import { parseUltragoalSteeringDirective, steerUltragoal } from "./steering.js";
import { parseUlwLoopSteeringDirective, steerUlwLoop } from "./steering.js";
export interface UserPromptSubmitPayload {
readonly cwd: string;
@@ -35,7 +35,7 @@ interface PreToolUseHookOutput {
const CREATE_GOAL_TOOL_NAME = "create_goal";
const GOAL_BUDGET_WARNING =
"Do not set token_budget on create_goal. Omit the budget field so the goal stays unlimited; ultrawork and ultragoal runs must always use unlimited goals.";
"Do not set token_budget on create_goal. Omit the budget field so the goal stays unlimited; ultrawork and ulw-loop runs must always use unlimited goals.";
export function parseUserPromptSubmitPayload(raw: string): UserPromptSubmitPayload | null {
if (raw.trim().length === 0) return null;
@@ -59,12 +59,12 @@ export function parsePreToolUsePayload(raw: string): PreToolUsePayload | null {
}
}
export async function applyUserPromptUltragoalSteering(payload: UserPromptSubmitPayload): Promise<string> {
export async function applyUserPromptUlwLoopSteering(payload: UserPromptSubmitPayload): Promise<string> {
try {
if (payload.hook_event_name !== "UserPromptSubmit") return "";
const proposal = parseUltragoalSteeringDirective(payload.prompt);
const proposal = parseUlwLoopSteeringDirective(payload.prompt);
if (proposal === null) return "";
const result = await steerUltragoal(payload.cwd, proposal);
const result = await steerUlwLoop(payload.cwd, proposal);
if (!result.accepted) return "";
return JSON.stringify({
status: "accepted",
@@ -93,11 +93,11 @@ export function applyPreToolUseGoalBudgetGuard(payload: PreToolUsePayload): stri
return `${JSON.stringify(output)}\n`;
}
export async function runUltragoalHookCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream): Promise<void> {
export async function runUlwLoopHookCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream): Promise<void> {
try {
const payload = parseUserPromptSubmitPayload(await readAll(stdin));
if (payload === null) return;
const output = await applyUserPromptUltragoalSteering(payload);
const output = await applyUserPromptUlwLoopSteering(payload);
if (output.length > 0) stdout.write(output);
} catch (error) {
if (error instanceof Error) return;
@@ -1,15 +1,15 @@
// biome-ignore-all format: keep this module under the mandated pure LOC budget.
import { hasAllCriteriaPass } from "./goal-status.js";
import { appendLedger, readUltragoalPlan, withUltragoalMutationLock, writePlan } from "./plan-io.js";
import type { UltragoalItem, UltragoalLedgerEntry, UltragoalPlan, UltragoalSuccessCriterion } from "./types.js";
import { iso, UltragoalError } from "./types.js";
import { appendLedger, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
import type { UlwLoopItem, UlwLoopLedgerEntry, UlwLoopPlan, UlwLoopSuccessCriterion } from "./types.js";
import { iso, UlwLoopError } from "./types.js";
type EvidenceStatus = "pass" | "fail" | "blocked";
type RecordEvidenceArgs = { readonly goalId: string; readonly criterionId: string; readonly status: EvidenceStatus; readonly evidence: string; readonly notes?: string };
function ultragoalFail(message: string, code: string, details: Record<string, unknown>): never { throw new UltragoalError(message, code, { details }); }
function ulwLoopFail(message: string, code: string, details: Record<string, unknown>): never { throw new UlwLoopError(message, code, { details }); }
function ledgerKind(status: EvidenceStatus): UltragoalLedgerEntry["kind"] {
function ledgerKind(status: EvidenceStatus): UlwLoopLedgerEntry["kind"] {
switch (status) {
case "pass":
return "evidence_captured";
@@ -18,25 +18,25 @@ function ledgerKind(status: EvidenceStatus): UltragoalLedgerEntry["kind"] {
case "blocked":
return "criterion_blocked";
default:
return ultragoalFail("Invalid criterion status.", "ULTRAGOAL_CRITERION_STATUS_INVALID", { status });
return ulwLoopFail("Invalid criterion status.", "ULW_LOOP_CRITERION_STATUS_INVALID", { status });
}
}
function findGoal(plan: UltragoalPlan, goalId: string): UltragoalItem {
function findGoal(plan: UlwLoopPlan, goalId: string): UlwLoopItem {
const goal = plan.goals.find((candidate) => candidate.id === goalId);
return goal ?? ultragoalFail(`Ultragoal goal not found: ${goalId}.`, "ULTRAGOAL_GOAL_NOT_FOUND", { goalId });
return goal ?? ulwLoopFail(`UlwLoop goal not found: ${goalId}.`, "ULW_LOOP_GOAL_NOT_FOUND", { goalId });
}
function findCriterion(goal: UltragoalItem, criterionId: string): UltragoalSuccessCriterion {
function findCriterion(goal: UlwLoopItem, criterionId: string): UlwLoopSuccessCriterion {
const criterion = goal.successCriteria.find((candidate) => candidate.id === criterionId);
return criterion ?? ultragoalFail(`Success criterion not found: ${criterionId}.`, "ULTRAGOAL_CRITERION_NOT_FOUND", { goalId: goal.id, criterionId });
return criterion ?? ulwLoopFail(`Success criterion not found: ${criterionId}.`, "ULW_LOOP_CRITERION_NOT_FOUND", { goalId: goal.id, criterionId });
}
function nonEmptyEvidence(evidence: string): string { const trimmed = evidence.trim(); return trimmed || ultragoalFail("Evidence must be a non-empty string.", "ULTRAGOAL_EVIDENCE_REQUIRED", {}); }
function nonEmptyEvidence(evidence: string): string { const trimmed = evidence.trim(); return trimmed || ulwLoopFail("Evidence must be a non-empty string.", "ULW_LOOP_EVIDENCE_REQUIRED", {}); }
export async function recordEvidence(repoRoot: string, args: RecordEvidenceArgs): Promise<{ plan: UltragoalPlan; goal: UltragoalItem; criterion: UltragoalSuccessCriterion; ledgerEntry: UltragoalLedgerEntry }> {
return withUltragoalMutationLock(repoRoot, async () => {
const plan = await readUltragoalPlan(repoRoot);
export async function recordEvidence(repoRoot: string, args: RecordEvidenceArgs): Promise<{ plan: UlwLoopPlan; goal: UlwLoopItem; criterion: UlwLoopSuccessCriterion; ledgerEntry: UlwLoopLedgerEntry }> {
return withUlwLoopMutationLock(repoRoot, async () => {
const plan = await readUlwLoopPlan(repoRoot);
const goal = findGoal(plan, args.goalId);
const criterion = findCriterion(goal, args.criterionId);
const evidence = nonEmptyEvidence(args.evidence);
@@ -50,7 +50,7 @@ export async function recordEvidence(repoRoot: string, args: RecordEvidenceArgs)
goal.updatedAt = capturedAt;
plan.updatedAt = capturedAt;
await writePlan(repoRoot, plan);
const ledgerEntry: UltragoalLedgerEntry = {
const ledgerEntry: UlwLoopLedgerEntry = {
at: capturedAt,
kind,
goalId: goal.id,
@@ -66,9 +66,9 @@ export async function recordEvidence(repoRoot: string, args: RecordEvidenceArgs)
});
}
export async function markCriteriaPendingResetForGoal(repoRoot: string, goalId: string): Promise<{ plan: UltragoalPlan; resetCount: number }> {
return withUltragoalMutationLock(repoRoot, async () => {
const plan = await readUltragoalPlan(repoRoot);
export async function markCriteriaPendingResetForGoal(repoRoot: string, goalId: string): Promise<{ plan: UlwLoopPlan; resetCount: number }> {
return withUlwLoopMutationLock(repoRoot, async () => {
const plan = await readUlwLoopPlan(repoRoot);
const goal = findGoal(plan, goalId);
const now = iso();
const before = goal.successCriteria.map((criterion) => ({ id: criterion.id, status: criterion.status, capturedEvidence: criterion.capturedEvidence, capturedAt: criterion.capturedAt ?? null }));
@@ -86,7 +86,7 @@ export async function markCriteriaPendingResetForGoal(repoRoot: string, goalId:
});
}
export function criteriaSummary(plan: UltragoalPlan): { totalCriteria: number; passCount: number; pendingCount: number; failCount: number; blockedCount: number; goalsWithUnresolvedCriteria: string[] } {
export function criteriaSummary(plan: UlwLoopPlan): { totalCriteria: number; passCount: number; pendingCount: number; failCount: number; blockedCount: number; goalsWithUnresolvedCriteria: string[] } {
let totalCriteria = 0;
let passCount = 0;
let pendingCount = 0;
@@ -103,7 +103,7 @@ export function criteriaSummary(plan: UltragoalPlan): { totalCriteria: number; p
case "pending": pendingCount += 1; break;
case "fail": failCount += 1; break;
case "blocked": blockedCount += 1; break;
default: ultragoalFail("Invalid criterion status.", "ULTRAGOAL_CRITERION_STATUS_INVALID", { status: criterion.status });
default: ulwLoopFail("Invalid criterion status.", "ULW_LOOP_CRITERION_STATUS_INVALID", { status: criterion.status });
}
}
if (unresolved) goalsWithUnresolvedCriteria.push(goal.id);
@@ -111,11 +111,11 @@ export function criteriaSummary(plan: UltragoalPlan): { totalCriteria: number; p
return { totalCriteria, passCount, pendingCount, failCount, blockedCount, goalsWithUnresolvedCriteria };
}
export function unresolvedCriteriaOf(goal: UltragoalItem): UltragoalSuccessCriterion[] { return goal.successCriteria.filter((criterion) => criterion.status !== "pass"); }
export function unresolvedCriteriaOf(goal: UlwLoopItem): UlwLoopSuccessCriterion[] { return goal.successCriteria.filter((criterion) => criterion.status !== "pass"); }
export function requireAllCriteriaPass(goal: UltragoalItem): void {
export function requireAllCriteriaPass(goal: UlwLoopItem): void {
if (hasAllCriteriaPass(goal)) return;
throw new UltragoalError(`Goal ${goal.id} has unresolved success criteria.`, "ultragoal_criteria_not_all_pass", {
throw new UlwLoopError(`Goal ${goal.id} has unresolved success criteria.`, "ulw_loop_criteria_not_all_pass", {
details: { goalId: goal.id, unresolved: unresolvedCriteriaOf(goal).map((criterion) => ({ id: criterion.id, status: criterion.status })) },
});
}
@@ -1,23 +1,23 @@
import type {
UltragoalCodexGoalMode,
UltragoalItem,
UltragoalPlan,
UltragoalStatus,
UltragoalSuccessCriterion,
UlwLoopCodexGoalMode,
UlwLoopItem,
UlwLoopPlan,
UlwLoopStatus,
UlwLoopSuccessCriterion,
} from "./types.js";
export const ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE: string =
"Complete the durable ultragoal plan in .omo/ultragoal/goals.json, including later accepted/appended stories, under the original brief constraints; use .omo/ultragoal/ledger.jsonl as the audit trail.";
export const ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE: string =
"Complete the durable ulw-loop plan in .omo/ulw-loop/goals.json, including later accepted/appended stories, under the original brief constraints; use .omo/ulw-loop/ledger.jsonl as the audit trail.";
export function codexGoalMode(plan: UltragoalPlan): UltragoalCodexGoalMode {
export function codexGoalMode(plan: UlwLoopPlan): UlwLoopCodexGoalMode {
return plan.codexGoalMode ?? "per_story";
}
function isResolvedStatus(status: UltragoalStatus): boolean {
function isResolvedStatus(status: UlwLoopStatus): boolean {
return status === "complete";
}
function isSupersededResolved(goal: UltragoalItem, plan: UltragoalPlan): boolean {
function isSupersededResolved(goal: UlwLoopItem, plan: UlwLoopPlan): boolean {
if (goal.steeringStatus !== "superseded") return false;
const replacements = goal.supersededBy ?? [];
if (replacements.length === 0) return false;
@@ -27,16 +27,16 @@ function isSupersededResolved(goal: UltragoalItem, plan: UltragoalPlan): boolean
});
}
function isCompletionBlocking(goal: UltragoalItem, plan: UltragoalPlan): boolean {
function isCompletionBlocking(goal: UlwLoopItem, plan: UlwLoopPlan): boolean {
if (goal.steeringStatus === "superseded") return !isSupersededResolved(goal, plan);
if (goal.steeringStatus === "blocked") return true;
return !isResolvedStatus(goal.status);
}
function isCompletionBlockingForFinalCandidate(
candidate: UltragoalItem,
finalCandidate: UltragoalItem,
plan: UltragoalPlan,
candidate: UlwLoopItem,
finalCandidate: UlwLoopItem,
plan: UlwLoopPlan,
): boolean {
if (candidate.id === finalCandidate.id) return false;
if (candidate.steeringStatus === "superseded") {
@@ -51,34 +51,34 @@ function isCompletionBlockingForFinalCandidate(
return isCompletionBlocking(candidate, plan);
}
export function isUltragoalDone(plan: UltragoalPlan): boolean {
export function isUlwLoopDone(plan: UlwLoopPlan): boolean {
if (plan.aggregateCompletion?.status === "complete") return true;
return plan.goals.every((goal) => !isCompletionBlocking(goal, plan));
}
export function isFinalRunCompletionCandidate(plan: UltragoalPlan, goal: UltragoalItem): boolean {
export function isFinalRunCompletionCandidate(plan: UlwLoopPlan, goal: UlwLoopItem): boolean {
return (
isCompletionBlocking(goal, plan) &&
plan.goals.every((candidate) => !isCompletionBlockingForFinalCandidate(candidate, goal, plan))
);
}
export function aggregateCodexObjective(plan: UltragoalPlan): string {
return plan.codexObjective ?? ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE;
export function aggregateCodexObjective(plan: UlwLoopPlan): string {
return plan.codexObjective ?? ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE;
}
export function expectedCodexObjective(plan: UltragoalPlan, goal: UltragoalItem): string {
export function expectedCodexObjective(plan: UlwLoopPlan, goal: UlwLoopItem): string {
return codexGoalMode(plan) === "aggregate" ? aggregateCodexObjective(plan) : goal.objective;
}
export function compatibleCodexObjectives(plan: UltragoalPlan): readonly string[] {
export function compatibleCodexObjectives(plan: UlwLoopPlan): readonly string[] {
return [aggregateCodexObjective(plan), ...(plan.codexObjectiveAliases ?? [])];
}
export function hasAllCriteriaPass(goal: UltragoalItem): boolean {
export function hasAllCriteriaPass(goal: UlwLoopItem): boolean {
return goal.successCriteria.length > 0 && goal.successCriteria.every((criterion) => criterion.status === "pass");
}
export function firstUnresolvedCriterion(goal: UltragoalItem): UltragoalSuccessCriterion | undefined {
export function firstUnresolvedCriterion(goal: UlwLoopItem): UlwLoopSuccessCriterion | undefined {
return goal.successCriteria.find((criterion) => criterion.status !== "pass");
}
@@ -0,0 +1,27 @@
import { join } from "node:path";
import { ULW_LOOP_BRIEF, ULW_LOOP_DIR, ULW_LOOP_GOALS, ULW_LOOP_LEDGER } from "./types.js";
export function ulwLoopDir(repoRoot: string): string {
return join(repoRoot, ULW_LOOP_DIR);
}
export function ulwLoopBriefPath(repoRoot: string): string {
return join(ulwLoopDir(repoRoot), ULW_LOOP_BRIEF);
}
export function ulwLoopGoalsPath(repoRoot: string): string {
return join(ulwLoopDir(repoRoot), ULW_LOOP_GOALS);
}
export function ulwLoopLedgerPath(repoRoot: string): string {
return join(ulwLoopDir(repoRoot), ULW_LOOP_LEDGER);
}
export function repoRelative(absolutePath: string, repoRoot: string): string {
const slashPrefix = `${repoRoot}/`;
const backslashPrefix = `${repoRoot}\\`;
if (absolutePath.startsWith(slashPrefix)) return absolutePath.slice(slashPrefix.length).split("\\").join("/");
if (absolutePath.startsWith(backslashPrefix))
return absolutePath.slice(backslashPrefix.length).split("\\").join("/");
return absolutePath.split("\\").join("/");
}
@@ -2,22 +2,22 @@
import { existsSync } from "node:fs";
import { mkdir, writeFile } from "node:fs/promises";
import { ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE } from "./goal-status.js";
import { ultragoalBriefPath, ultragoalDir, ultragoalGoalsPath, ultragoalLedgerPath } from "./paths.js";
import { appendLedger, readUltragoalPlan, withUltragoalMutationLock, writePlan } from "./plan-io.js";
import type { UltragoalCodexGoalMode, UltragoalItem, UltragoalPlan, UltragoalSuccessCriterion } from "./types.js";
import { iso, ULTRAGOAL_BRIEF, ULTRAGOAL_DIR, ULTRAGOAL_GOALS, ULTRAGOAL_LEDGER, UltragoalError } from "./types.js";
import { ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE } from "./goal-status.js";
import { ulwLoopBriefPath, ulwLoopDir, ulwLoopGoalsPath, ulwLoopLedgerPath } from "./paths.js";
import { appendLedger, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
import type { UlwLoopCodexGoalMode, UlwLoopItem, UlwLoopPlan, UlwLoopSuccessCriterion } from "./types.js";
import { iso, ULW_LOOP_BRIEF, ULW_LOOP_DIR, ULW_LOOP_GOALS, ULW_LOOP_LEDGER, UlwLoopError } from "./types.js";
export type UltragoalPlanSummary = { readonly total: number; readonly pending: number; readonly in_progress: number; readonly complete: number; readonly failed: number; readonly blocked: number; readonly review_blocked: number; readonly needs_user_decision: number; readonly superseded: number; readonly criteria: { readonly total: number; readonly pass: number; readonly pending: number; readonly fail: number; readonly blocked: number } };
export type UlwLoopPlanSummary = { readonly total: number; readonly pending: number; readonly in_progress: number; readonly complete: number; readonly failed: number; readonly blocked: number; readonly review_blocked: number; readonly needs_user_decision: number; readonly superseded: number; readonly criteria: { readonly total: number; readonly pass: number; readonly pending: number; readonly fail: number; readonly blocked: number } };
function cleanLine(line: string): string { return line.replace(/^\s*(?:[-*+]\s+|\d+[.)]\s+)/, "").trim(); }
function normalizeObjective(value: string): string { return value.replace(/\s+/g, " ").trim(); }
function titleFromObjective(objective: string, fallback: string): string { const firstLine = objective.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? fallback; return firstLine.length > 72 ? `${firstLine.slice(0, 69).trimEnd()}...` : firstLine; }
function normalizeGoalId(title: string, index: number): string { const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 36).replace(/-+$/g, ""); return `G${String(index + 1).padStart(3, "0")}${slug ? `-${slug}` : ""}`; }
function assertNonEmpty(value: string | undefined, label: string): string { const trimmed = value?.trim(); if (!trimmed) throw new UltragoalError(`Missing ${label}.`, "ULTRAGOAL_ARGUMENT_MISSING"); return trimmed; }
function assertNonEmpty(value: string | undefined, label: string): string { const trimmed = value?.trim(); if (!trimmed) throw new UlwLoopError(`Missing ${label}.`, "ULW_LOOP_ARGUMENT_MISSING"); return trimmed; }
function truncateObjective(objective: string): string { return objective.length > 80 ? `${objective.slice(0, 77).trimEnd()}...` : objective; }
export function seedDefaultSuccessCriteria(goalIndex: number, objective: string): UltragoalSuccessCriterion[] {
export function seedDefaultSuccessCriteria(goalIndex: number, objective: string): UlwLoopSuccessCriterion[] {
const subject = truncateObjective(normalizeObjective(objective) || `Goal ${goalIndex + 1}`);
const rows = [
["C001", "happy", `happy path for: ${subject}`, `Replace via revise_criterion with observable happy-path proof for goal ${goalIndex + 1}.`],
@@ -34,44 +34,44 @@ export function deriveGoalCandidates(brief: string): Array<{ title: string; obje
return selected.map((objective, index) => ({ title: titleFromObjective(objective, `Goal ${index + 1}`), objective }));
}
function makeGoal(title: string, objective: string, index: number, now: string): UltragoalItem {
function makeGoal(title: string, objective: string, index: number, now: string): UlwLoopItem {
const cleanTitle = assertNonEmpty(title, "title");
const cleanObjective = assertNonEmpty(objective, "objective");
return { id: normalizeGoalId(cleanTitle, index), title: cleanTitle, objective: cleanObjective, status: "pending", successCriteria: seedDefaultSuccessCriteria(index, cleanObjective), attempt: 0, createdAt: now, updatedAt: now };
}
function appendGoalToPlan(plan: UltragoalPlan, title: string, objective: string, now: string): UltragoalItem {
function appendGoalToPlan(plan: UlwLoopPlan, title: string, objective: string, now: string): UlwLoopItem {
const goal = makeGoal(title, objective, plan.goals.length, now);
plan.goals.push(goal);
plan.updatedAt = now;
return goal;
}
function isScheduleEligible(goal: UltragoalItem): boolean { return goal.steeringStatus !== "superseded" && goal.steeringStatus !== "blocked"; }
function isScheduleEligible(goal: UlwLoopItem): boolean { return goal.steeringStatus !== "superseded" && goal.steeringStatus !== "blocked"; }
function clearGoalBlockerFields(goal: UltragoalItem): void {
function clearGoalBlockerFields(goal: UlwLoopItem): void {
for (const key of ["blockedReason", "blockerSignature", "blockerOccurrenceCount", "requiredExternalDecision", "nonRetriable", "failedAt", "failureReason"] as const) delete goal[key];
}
export async function createUltragoalPlan(repoRoot: string, args: { brief: string; codexGoalMode?: UltragoalCodexGoalMode; force?: boolean }): Promise<UltragoalPlan> {
return withUltragoalMutationLock(repoRoot, async () => {
if (!args.force && existsSync(ultragoalGoalsPath(repoRoot))) throw new UltragoalError(`Refusing to overwrite existing ${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}; pass --force to recreate it.`, "ULTRAGOAL_PLAN_EXISTS");
export async function createUlwLoopPlan(repoRoot: string, args: { brief: string; codexGoalMode?: UlwLoopCodexGoalMode; force?: boolean }): Promise<UlwLoopPlan> {
return withUlwLoopMutationLock(repoRoot, async () => {
if (!args.force && existsSync(ulwLoopGoalsPath(repoRoot))) throw new UlwLoopError(`Refusing to overwrite existing ${ULW_LOOP_DIR}/${ULW_LOOP_GOALS}; pass --force to recreate it.`, "ULW_LOOP_PLAN_EXISTS");
const now = iso();
const goals = deriveGoalCandidates(args.brief).map((goal, index) => makeGoal(goal.title, goal.objective, index, now));
const plan: UltragoalPlan = { version: 1, createdAt: now, updatedAt: now, briefPath: `${ULTRAGOAL_DIR}/${ULTRAGOAL_BRIEF}`, goalsPath: `${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}`, ledgerPath: `${ULTRAGOAL_DIR}/${ULTRAGOAL_LEDGER}`, codexGoalMode: args.codexGoalMode ?? "aggregate", goals };
if (plan.codexGoalMode === "aggregate") plan.codexObjective = ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE;
await mkdir(ultragoalDir(repoRoot), { recursive: true });
await writeFile(ultragoalBriefPath(repoRoot), args.brief.endsWith("\n") ? args.brief : `${args.brief}\n`, "utf8");
const plan: UlwLoopPlan = { version: 1, createdAt: now, updatedAt: now, briefPath: `${ULW_LOOP_DIR}/${ULW_LOOP_BRIEF}`, goalsPath: `${ULW_LOOP_DIR}/${ULW_LOOP_GOALS}`, ledgerPath: `${ULW_LOOP_DIR}/${ULW_LOOP_LEDGER}`, codexGoalMode: args.codexGoalMode ?? "aggregate", goals };
if (plan.codexGoalMode === "aggregate") plan.codexObjective = ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE;
await mkdir(ulwLoopDir(repoRoot), { recursive: true });
await writeFile(ulwLoopBriefPath(repoRoot), args.brief.endsWith("\n") ? args.brief : `${args.brief}\n`, "utf8");
await writePlan(repoRoot, plan);
await writeFile(ultragoalLedgerPath(repoRoot), "", "utf8");
await writeFile(ulwLoopLedgerPath(repoRoot), "", "utf8");
await appendLedger(repoRoot, { at: now, kind: "plan_created", message: `${goals.length} goal(s) created` });
return plan;
});
}
export async function addUltragoalGoal(repoRoot: string, args: { title: string; objective: string }): Promise<{ plan: UltragoalPlan; goal: UltragoalItem }> {
return withUltragoalMutationLock(repoRoot, async () => {
const plan = await readUltragoalPlan(repoRoot);
export async function addUlwLoopGoal(repoRoot: string, args: { title: string; objective: string }): Promise<{ plan: UlwLoopPlan; goal: UlwLoopItem }> {
return withUlwLoopMutationLock(repoRoot, async () => {
const plan = await readUlwLoopPlan(repoRoot);
const now = iso();
const goal = appendGoalToPlan(plan, args.title, args.objective, now);
await writePlan(repoRoot, plan);
@@ -80,13 +80,13 @@ export async function addUltragoalGoal(repoRoot: string, args: { title: string;
});
}
export async function startNextUltragoal(repoRoot: string, args: { retryFailed?: boolean } = {}): Promise<{ plan: UltragoalPlan; goal: UltragoalItem; resumed: boolean } | { done: true; plan: UltragoalPlan }> {
return withUltragoalMutationLock(repoRoot, async () => {
const plan = await readUltragoalPlan(repoRoot);
export async function startNextUlwLoop(repoRoot: string, args: { retryFailed?: boolean } = {}): Promise<{ plan: UlwLoopPlan; goal: UlwLoopItem; resumed: boolean } | { done: true; plan: UlwLoopPlan }> {
return withUlwLoopMutationLock(repoRoot, async () => {
const plan = await readUlwLoopPlan(repoRoot);
const now = iso();
if (plan.aggregateCompletion?.status === "complete") return { done: true, plan };
const existing = plan.goals.find((goal) => goal.status === "in_progress" && isScheduleEligible(goal));
if (existing) { await appendLedger(repoRoot, { at: now, kind: "goal_resumed", goalId: existing.id, status: existing.status, message: "Resuming active ultragoal" }); return { plan, goal: existing, resumed: true }; }
if (existing) { await appendLedger(repoRoot, { at: now, kind: "goal_resumed", goalId: existing.id, status: existing.status, message: "Resuming active ulw-loop" }); return { plan, goal: existing, resumed: true }; }
let next = plan.goals.find((goal) => goal.status === "pending" && isScheduleEligible(goal));
if (!next && args.retryFailed) {
next = plan.goals.find((goal) => goal.status === "failed" && !goal.nonRetriable && isScheduleEligible(goal));
@@ -106,8 +106,8 @@ export async function startNextUltragoal(repoRoot: string, args: { retryFailed?:
});
}
export function summarizeUltragoalPlan(plan: UltragoalPlan): UltragoalPlanSummary {
const countStatus = (status: UltragoalItem["status"]): number => plan.goals.filter((goal) => goal.status === status).length;
const countCriteria = (status: UltragoalSuccessCriterion["status"]): number => plan.goals.reduce((sum, goal) => sum + goal.successCriteria.filter((criterion) => criterion.status === status).length, 0);
export function summarizeUlwLoopPlan(plan: UlwLoopPlan): UlwLoopPlanSummary {
const countStatus = (status: UlwLoopItem["status"]): number => plan.goals.filter((goal) => goal.status === status).length;
const countCriteria = (status: UlwLoopSuccessCriterion["status"]): number => plan.goals.reduce((sum, goal) => sum + goal.successCriteria.filter((criterion) => criterion.status === status).length, 0);
return { total: plan.goals.length, pending: countStatus("pending"), in_progress: countStatus("in_progress"), complete: countStatus("complete"), failed: countStatus("failed"), blocked: countStatus("blocked"), review_blocked: countStatus("review_blocked"), needs_user_decision: countStatus("needs_user_decision"), superseded: plan.goals.filter((goal) => goal.steeringStatus === "superseded").length, criteria: { total: plan.goals.reduce((sum, goal) => sum + goal.successCriteria.length, 0), pass: countCriteria("pass"), pending: countCriteria("pending"), fail: countCriteria("fail"), blocked: countCriteria("blocked") } };
}
@@ -1,12 +1,12 @@
import { appendFile, mkdir, readFile, rename, writeFile } from "node:fs/promises";
import { repoRelative, ultragoalDir, ultragoalGoalsPath, ultragoalLedgerPath } from "./paths.js";
import type { UltragoalLedgerEntry, UltragoalPlan } from "./types.js";
import { iso, ULTRAGOAL_DIR, ULTRAGOAL_GOALS, ULTRAGOAL_LEDGER, UltragoalError } from "./types.js";
import { repoRelative, ulwLoopDir, ulwLoopGoalsPath, ulwLoopLedgerPath } from "./paths.js";
import type { UlwLoopLedgerEntry, UlwLoopPlan } from "./types.js";
import { iso, ULW_LOOP_DIR, ULW_LOOP_GOALS, ULW_LOOP_LEDGER, UlwLoopError } from "./types.js";
const AGGREGATE_CODEX_OBJECTIVE = `Complete the durable ultragoal plan in ${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}, including later accepted/appended stories, under the original brief constraints; use ${ULTRAGOAL_DIR}/${ULTRAGOAL_LEDGER} as the audit trail.`;
const LEGACY_OBJECTIVE_PREFIX = `Complete all ultragoal stories in ${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}: `;
const LEGACY_OBJECTIVE = `Complete all ultragoal stories listed in ${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}. Use ${ULTRAGOAL_DIR}/${ULTRAGOAL_LEDGER} as the durable audit trail.`;
const AGGREGATE_CODEX_OBJECTIVE = `Complete the durable ulw-loop plan in ${ULW_LOOP_DIR}/${ULW_LOOP_GOALS}, including later accepted/appended stories, under the original brief constraints; use ${ULW_LOOP_DIR}/${ULW_LOOP_LEDGER} as the audit trail.`;
const LEGACY_OBJECTIVE_PREFIX = `Complete all ulw-loop stories in ${ULW_LOOP_DIR}/${ULW_LOOP_GOALS}: `;
const LEGACY_OBJECTIVE = `Complete all ulw-loop stories listed in ${ULW_LOOP_DIR}/${ULW_LOOP_GOALS}. Use ${ULW_LOOP_DIR}/${ULW_LOOP_LEDGER} as the durable audit trail.`;
const locks = new Map<string, Promise<unknown>>();
function hasCode(error: unknown, code: string): boolean {
@@ -17,11 +17,11 @@ function isLegacyEnumeratedAggregateObjective(objective: string | undefined): ob
return objective === LEGACY_OBJECTIVE || Boolean(objective?.startsWith(LEGACY_OBJECTIVE_PREFIX));
}
function isSteeringKind(value: unknown): value is UltragoalLedgerEntry["kind"] {
function isSteeringKind(value: unknown): value is UlwLoopLedgerEntry["kind"] {
return value === "steering_accepted" || value === "steering_rejected" || value === "criteria_revised";
}
export async function withUltragoalMutationLock<T>(repoRoot: string, fn: () => Promise<T>): Promise<T> {
export async function withUlwLoopMutationLock<T>(repoRoot: string, fn: () => Promise<T>): Promise<T> {
const prior = locks.get(repoRoot) ?? Promise.resolve();
const run = prior.then(fn, fn);
locks.set(
@@ -31,22 +31,22 @@ export async function withUltragoalMutationLock<T>(repoRoot: string, fn: () => P
return run;
}
export async function readUltragoalPlan(repoRoot: string): Promise<UltragoalPlan> {
const path = ultragoalGoalsPath(repoRoot);
export async function readUlwLoopPlan(repoRoot: string): Promise<UlwLoopPlan> {
const path = ulwLoopGoalsPath(repoRoot);
let raw: string;
try {
raw = await readFile(path, "utf8");
} catch (error) {
if (!hasCode(error, "ENOENT")) throw error;
throw new UltragoalError(
`No ultragoal plan found at ${repoRelative(path, repoRoot)}. Run \`omo ultragoal create-goals ...\` first.`,
"ULTRAGOAL_PLAN_MISSING",
throw new UlwLoopError(
`No ulw-loop plan found at ${repoRelative(path, repoRoot)}. Run \`omo ulw-loop create-goals ...\` first.`,
"ULW_LOOP_PLAN_MISSING",
{ cause: error },
);
}
const parsed: UltragoalPlan = JSON.parse(raw);
const parsed: UlwLoopPlan = JSON.parse(raw);
if (parsed.version !== 1 || !Array.isArray(parsed.goals)) {
throw new UltragoalError(`Invalid ultragoal plan at ${repoRelative(path, repoRoot)}.`, "ULTRAGOAL_PLAN_INVALID");
throw new UlwLoopError(`Invalid ulw-loop plan at ${repoRelative(path, repoRoot)}.`, "ULW_LOOP_PLAN_INVALID");
}
const previousObjective = parsed.codexObjective;
if (
@@ -69,30 +69,30 @@ export async function readUltragoalPlan(repoRoot: string): Promise<UltragoalPlan
return parsed;
}
export async function writePlan(repoRoot: string, plan: UltragoalPlan): Promise<void> {
await mkdir(ultragoalDir(repoRoot), { recursive: true });
const path = ultragoalGoalsPath(repoRoot);
export async function writePlan(repoRoot: string, plan: UlwLoopPlan): Promise<void> {
await mkdir(ulwLoopDir(repoRoot), { recursive: true });
const path = ulwLoopGoalsPath(repoRoot);
const tmpPath = `${path}.${process.pid}.${Date.now()}.tmp`;
await writeFile(tmpPath, `${JSON.stringify(plan, null, 2)}\n`, "utf8");
await rename(tmpPath, path);
}
export async function appendLedger(repoRoot: string, entry: UltragoalLedgerEntry): Promise<void> {
await mkdir(ultragoalDir(repoRoot), { recursive: true });
await appendFile(ultragoalLedgerPath(repoRoot), `${JSON.stringify(entry)}\n`, "utf8");
export async function appendLedger(repoRoot: string, entry: UlwLoopLedgerEntry): Promise<void> {
await mkdir(ulwLoopDir(repoRoot), { recursive: true });
await appendFile(ulwLoopLedgerPath(repoRoot), `${JSON.stringify(entry)}\n`, "utf8");
}
export async function readSteeringLedgerEntries(repoRoot: string): Promise<UltragoalLedgerEntry[]> {
export async function readSteeringLedgerEntries(repoRoot: string): Promise<UlwLoopLedgerEntry[]> {
let raw: string;
try {
raw = await readFile(ultragoalLedgerPath(repoRoot), "utf8");
raw = await readFile(ulwLoopLedgerPath(repoRoot), "utf8");
} catch (error) {
if (hasCode(error, "ENOENT")) return [];
throw error;
}
const entries: UltragoalLedgerEntry[] = [];
const entries: UlwLoopLedgerEntry[] = [];
for (const line of raw.split(/\r?\n/).filter(Boolean)) {
const entry: UltragoalLedgerEntry = JSON.parse(line);
const entry: UlwLoopLedgerEntry = JSON.parse(line);
if (isSteeringKind(entry.kind)) entries.push(entry);
}
return entries;
@@ -1,5 +1,5 @@
import type { UltragoalItem, UltragoalPlan, UltragoalQualityGate } from "./types.js";
import { UltragoalError } from "./types.js";
import type { UlwLoopItem, UlwLoopPlan, UlwLoopQualityGate } from "./types.js";
import { UlwLoopError } from "./types.js";
const BLOCKER_FIELD_KEYS = "blocker blockerSignature blockerEvidence blockerOccurrences blockedAt".split(" ");
const URL_PATTERN = /https?:\/\/\S+/g;
@@ -14,7 +14,7 @@ const GHCR_401_PATTERN = /\b(401|unauthorized|anonymous pull|authentication requ
const GHCR_403_PATTERN = /\b(403|forbidden|read packages|package api)\b/;
function invalid(message: string, field: string): never {
throw new UltragoalError(message, "ULTRAGOAL_QUALITY_GATE_INVALID", { details: { field } });
throw new UlwLoopError(message, "ULW_LOOP_QUALITY_GATE_INVALID", { details: { field } });
}
function isRecord(value: unknown): value is Record<string, unknown> {
@@ -42,7 +42,7 @@ function stringArray(value: unknown, field: string): string[] {
return value.map((item) => nonEmptyString(item, field));
}
export function validateQualityGate(input: unknown): UltragoalQualityGate {
export function validateQualityGate(input: unknown): UlwLoopQualityGate {
const gate = section(input, "qualityGate");
const cleaner = section(gate["aiSlopCleaner"], "aiSlopCleaner");
const verification = section(gate["verification"], "verification");
@@ -61,7 +61,7 @@ export function validateQualityGate(input: unknown): UltragoalQualityGate {
const cleanerEvidence = nonEmptyString(cleaner["evidence"], "aiSlopCleaner.evidence");
const verificationEvidence = nonEmptyString(verification["evidence"], "verification.evidence");
const reviewEvidence = nonEmptyString(review["evidence"], "codeReview.evidence");
const result: UltragoalQualityGate = {
const result: UlwLoopQualityGate = {
aiSlopCleaner: { status: "passed", evidence: cleanerEvidence },
verification: { status: "passed", commands, evidence: verificationEvidence },
codeReview: { recommendation: "APPROVE", architectStatus: "CLEAR", evidence: reviewEvidence },
@@ -86,17 +86,17 @@ export function classifyExternalAuthorizationBlocker(evidence: string): string |
return `GHCR_PULL_ACCESS:${status || "AUTHORIZATION_REQUIRED"}:GHCR_VISIBILITY_OR_CREDENTIAL_REQUIRED`;
}
function nestedBlockerSignature(goal: UltragoalItem): string | null {
function nestedBlockerSignature(goal: UlwLoopItem): string | null {
const blocker = Reflect.get(goal, "blocker");
const signature = isRecord(blocker) ? blocker["signature"] : null;
return typeof signature === "string" ? signature : null;
}
export function sameBlockerOccurrences(plan: UltragoalPlan, signature: string): number {
export function sameBlockerOccurrences(plan: UlwLoopPlan, signature: string): number {
return plan.goals.filter((goal) => goal.blockerSignature === signature || nestedBlockerSignature(goal) === signature)
.length;
}
export function clearGoalBlockerFields(goal: UltragoalItem): void {
export function clearGoalBlockerFields(goal: UlwLoopItem): void {
for (const key of BLOCKER_FIELD_KEYS) Reflect.deleteProperty(goal, key);
}
@@ -3,20 +3,20 @@
import { readCodexGoalSnapshotInput, reconcileCodexGoalSnapshot } from "./codex-goal-snapshot.js";
import { codexGoalMode, compatibleCodexObjectives, expectedCodexObjective, isFinalRunCompletionCandidate } from "./goal-status.js";
import { seedDefaultSuccessCriteria } from "./plan-crud.js";
import { appendLedger, readUltragoalPlan, withUltragoalMutationLock, writePlan } from "./plan-io.js";
import type { UltragoalItem, UltragoalLedgerEntry, UltragoalPlan } from "./types.js";
import { iso, UltragoalError } from "./types.js";
import { appendLedger, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
import type { UlwLoopItem, UlwLoopLedgerEntry, UlwLoopPlan } from "./types.js";
import { iso, UlwLoopError } from "./types.js";
export interface RecordFinalReviewBlockersArgs { readonly goalId: string; readonly title: string; readonly objective: string; readonly evidence: string; readonly codexGoalJson: string }
export interface RecordFinalReviewBlockersResult { readonly plan: UltragoalPlan; readonly blockedGoal: UltragoalItem; readonly newGoal: UltragoalItem; readonly ledgerEntries: UltragoalLedgerEntry[] }
export interface RecordFinalReviewBlockersResult { readonly plan: UlwLoopPlan; readonly blockedGoal: UlwLoopItem; readonly newGoal: UlwLoopItem; readonly ledgerEntries: UlwLoopLedgerEntry[] }
const BLOCKER_FIELDS = "blockedReason blockerSignature blockerOccurrenceCount requiredExternalDecision nonRetriable failedAt failureReason completedAt blocker blockerEvidence blockerOccurrences blockedAt".split(" ");
function ultragoalError(message: string, code: string): never {
throw new UltragoalError(message, code);
function ulwLoopError(message: string, code: string): never {
throw new UlwLoopError(message, code);
}
function nextGoalId(plan: UltragoalPlan): string {
function nextGoalId(plan: UlwLoopPlan): string {
const max = plan.goals.reduce((current, goal) => {
const digits = /^G(\d+)/u.exec(goal.id)?.[1];
return digits === undefined ? current : Math.max(current, Number(digits));
@@ -24,9 +24,9 @@ function nextGoalId(plan: UltragoalPlan): string {
return `G${String(max + 1).padStart(3, "0")}`;
}
function appendBlockerGoal(plan: UltragoalPlan, args: RecordFinalReviewBlockersArgs, now: string): UltragoalItem {
function appendBlockerGoal(plan: UlwLoopPlan, args: RecordFinalReviewBlockersArgs, now: string): UlwLoopItem {
const index = plan.goals.length;
const goal: UltragoalItem = {
const goal: UlwLoopItem = {
id: nextGoalId(plan),
title: args.title,
objective: args.objective,
@@ -44,17 +44,17 @@ export async function recordFinalReviewBlockers(
repoRoot: string,
args: RecordFinalReviewBlockersArgs,
): Promise<RecordFinalReviewBlockersResult> {
return withUltragoalMutationLock(repoRoot, async () => {
const plan = await readUltragoalPlan(repoRoot);
return withUlwLoopMutationLock(repoRoot, async () => {
const plan = await readUlwLoopPlan(repoRoot);
const goal = plan.goals.find((candidate) => candidate.id === args.goalId);
if (goal === undefined) ultragoalError(`Unknown ultragoal id: ${args.goalId}`, "ultragoal_goal_not_found");
if (goal.status !== "in_progress") ultragoalError(`${goal.id} is ${goal.status}.`, "ultragoal_goal_not_in_progress");
if (!isFinalRunCompletionCandidate(plan, goal)) ultragoalError(`${goal.id} is not final.`, "ultragoal_not_final_story");
if (goal === undefined) ulwLoopError(`Unknown ulw-loop id: ${args.goalId}`, "ulw_loop_goal_not_found");
if (goal.status !== "in_progress") ulwLoopError(`${goal.id} is ${goal.status}.`, "ulw_loop_goal_not_in_progress");
if (!isFinalRunCompletionCandidate(plan, goal)) ulwLoopError(`${goal.id} is not final.`, "ulw_loop_not_final_story");
const snapshot = await readCodexGoalSnapshotInput(args.codexGoalJson, repoRoot);
const aggregate = codexGoalMode(plan) === "aggregate";
const reconciliation = reconcileCodexGoalSnapshot(snapshot, { expectedObjective: expectedCodexObjective(plan, goal), ...(aggregate ? { acceptedObjectives: compatibleCodexObjectives(plan) } : {}), allowedStatuses: ["active"], requireSnapshot: true, requireComplete: false });
if (!reconciliation.ok) ultragoalError(reconciliation.errors.join(" "), "ultragoal_codex_snapshot_mismatch");
if (!reconciliation.ok) ulwLoopError(reconciliation.errors.join(" "), "ulw_loop_codex_snapshot_mismatch");
const now = iso();
for (const field of BLOCKER_FIELDS) Reflect.deleteProperty(goal, field);
@@ -67,9 +67,9 @@ export async function recordFinalReviewBlockers(
plan.updatedAt = now;
const codexGoal = reconciliation.snapshot.raw;
const blockedEntry: UltragoalLedgerEntry = { at: now, kind: "goal_review_blocked", goalId: goal.id, status: goal.status, evidence: args.evidence, codexGoal };
const addedEntry: UltragoalLedgerEntry = { at: now, kind: "goal_added", goalId: newGoal.id, status: newGoal.status, evidence: args.evidence, message: newGoal.title };
const summaryEntry: UltragoalLedgerEntry = { at: now, kind: "goal_review_blocked", goalId: goal.id, status: goal.status, evidence: args.evidence, codexGoal, message: `Review blockers recorded; appended ${newGoal.id}.` };
const blockedEntry: UlwLoopLedgerEntry = { at: now, kind: "goal_review_blocked", goalId: goal.id, status: goal.status, evidence: args.evidence, codexGoal };
const addedEntry: UlwLoopLedgerEntry = { at: now, kind: "goal_added", goalId: newGoal.id, status: newGoal.status, evidence: args.evidence, message: newGoal.title };
const summaryEntry: UlwLoopLedgerEntry = { at: now, kind: "goal_review_blocked", goalId: goal.id, status: goal.status, evidence: args.evidence, codexGoal, message: `Review blockers recorded; appended ${newGoal.id}.` };
Reflect.set(summaryEntry, "kind", "blocker_recorded");
const ledgerEntries = [blockedEntry, addedEntry, summaryEntry];
await writePlan(repoRoot, plan);
@@ -1,21 +1,21 @@
// biome-ignore-all format: compact steering module must stay below the 240 pure-LOC budget
import { isUltragoalDone } from "./goal-status.js";
import { appendLedger, readSteeringLedgerEntries, readUltragoalPlan, withUltragoalMutationLock, writePlan } from "./plan-io.js";
import { isUlwLoopDone } from "./goal-status.js";
import { appendLedger, readSteeringLedgerEntries, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
import type {
SteerUltragoalResult,
UltragoalItem,
UltragoalLedgerEntry,
UltragoalPlan,
UltragoalSteeringAudit,
UltragoalSteeringChildGoal,
UltragoalSteeringMutationKind,
UltragoalSteeringProposal,
UltragoalSteeringSource,
UltragoalSuccessCriterionUserModel,
SteerUlwLoopResult,
UlwLoopItem,
UlwLoopLedgerEntry,
UlwLoopPlan,
UlwLoopSteeringAudit,
UlwLoopSteeringChildGoal,
UlwLoopSteeringMutationKind,
UlwLoopSteeringProposal,
UlwLoopSteeringSource,
UlwLoopSuccessCriterionUserModel,
} from "./types.js";
import { iso, ULTRAGOAL_STEERING_MUTATION_KINDS, ULTRAGOAL_SUCCESS_CRITERION_USER_MODELS } from "./types.js";
import { iso, ULW_LOOP_STEERING_MUTATION_KINDS, ULW_LOOP_SUCCESS_CRITERION_USER_MODELS } from "./types.js";
const SOURCES = ["user_prompt_submit", "finding", "cli"] as const satisfies readonly UltragoalSteeringSource[];
const SOURCES = ["user_prompt_submit", "finding", "cli"] as const satisfies readonly UlwLoopSteeringSource[];
const PROTECTED = new Set(["aggregateCompletion", "codexObjective", "codexObjectiveAliases", "originalConstraints", "qualityGate", "status", "completedAt", "completionStatus"]);
const isObject = (value: unknown): value is object => typeof value === "object" && value !== null; const isPlain = (value: unknown): value is object => isObject(value) && !Array.isArray(value);
const read = (value: object, key: string): unknown => Object.entries(value).find(([name]) => name === key)?.[1];
@@ -24,9 +24,9 @@ const text = (value: object, key: string): string | undefined => {
const candidate = read(value, key);
return isText(candidate) ? candidate.trim() : undefined;
};
const isKind = (value: unknown): value is UltragoalSteeringMutationKind => typeof value === "string" && ULTRAGOAL_STEERING_MUTATION_KINDS.some((kind) => kind === value);
const isSource = (value: unknown): value is UltragoalSteeringSource => typeof value === "string" && SOURCES.some((source) => source === value);
const isModel = (value: unknown): value is UltragoalSuccessCriterionUserModel => typeof value === "string" && ULTRAGOAL_SUCCESS_CRITERION_USER_MODELS.some((model) => model === value);
const isKind = (value: unknown): value is UlwLoopSteeringMutationKind => typeof value === "string" && ULW_LOOP_STEERING_MUTATION_KINDS.some((kind) => kind === value);
const isSource = (value: unknown): value is UlwLoopSteeringSource => typeof value === "string" && SOURCES.some((source) => source === value);
const isModel = (value: unknown): value is UlwLoopSuccessCriterionUserModel => typeof value === "string" && ULW_LOOP_SUCCESS_CRITERION_USER_MODELS.some((model) => model === value);
const texts = (value: object, key: string): string[] => {
const candidate = read(value, key);
return Array.isArray(candidate) && candidate.every((item) => typeof item === "string") ? candidate : [];
@@ -44,7 +44,7 @@ const after = (proposal: object): object | undefined => {
};
const revised = (proposal: object, direct: string, nested: string): string | undefined => text(proposal, direct) ?? text(after(proposal) ?? proposal, nested);
function child(value: unknown): UltragoalSteeringChildGoal | null {
function child(value: unknown): UlwLoopSteeringChildGoal | null {
if (!isPlain(value)) return null;
const title = text(value, "title");
const objective = text(value, "objective");
@@ -60,7 +60,7 @@ function childValues(proposal: object): unknown[] {
return Array.isArray(fromAfter) ? fromAfter : [];
}
const children = (proposal: object): UltragoalSteeringChildGoal[] => childValues(proposal).map(child).filter((item): item is UltragoalSteeringChildGoal => item !== null);
const children = (proposal: object): UlwLoopSteeringChildGoal[] => childValues(proposal).map(child).filter((item): item is UlwLoopSteeringChildGoal => item !== null);
const pendingOrder = (proposal: object): string[] => {
const direct = texts(proposal, "pendingOrder");
return direct.length > 0 ? direct : texts(after(proposal) ?? proposal, "pendingGoalIds");
@@ -82,13 +82,13 @@ function weakens(value: unknown): boolean {
return /\b(skip|bypass|weaken|remove|omit|auto[-\s]?complete|mark complete|complete faster)\b/.test(valueText) && /\b(test|tests|verification|review|quality gate|complete|completion)\b/.test(valueText);
}
function auditFor(proposal: unknown, reasons: string[]): UltragoalSteeringAudit {
function auditFor(proposal: unknown, reasons: string[]): UlwLoopSteeringAudit {
const object = isPlain(proposal) ? proposal : undefined;
const kindRaw = object === undefined ? undefined : read(object, "kind");
const sourceRaw = object === undefined ? undefined : read(object, "source");
const evidence = object === undefined ? "" : (text(object, "evidence") ?? "");
const rationale = object === undefined ? "" : (text(object, "rationale") ?? "");
const audit: UltragoalSteeringAudit = { kind: isKind(kindRaw) ? kindRaw : "annotate_ledger", source: isSource(sourceRaw) ? sourceRaw : "cli", targetGoalIds: object === undefined ? [] : targets(object), evidence, rationale, invariant: { accepted: reasons.length === 0, structuralInvariantAccepted: reasons.length === 0, evidenceBackedNecessity: evidence.length > 0 && rationale.length > 0, noEasierCompletion: !weakens(proposal), rejectedReasons: reasons, reasons } };
const audit: UlwLoopSteeringAudit = { kind: isKind(kindRaw) ? kindRaw : "annotate_ledger", source: isSource(sourceRaw) ? sourceRaw : "cli", targetGoalIds: object === undefined ? [] : targets(object), evidence, rationale, invariant: { accepted: reasons.length === 0, structuralInvariantAccepted: reasons.length === 0, evidenceBackedNecessity: evidence.length > 0 && rationale.length > 0, noEasierCompletion: !weakens(proposal), rejectedReasons: reasons, reasons } };
if (object === undefined) return audit;
const criterionId = text(object, "criterionId");
const directiveText = text(object, "directiveText");
@@ -101,7 +101,7 @@ function auditFor(proposal: unknown, reasons: string[]): UltragoalSteeringAudit
return audit;
}
export function validateUltragoalSteeringProposal(plan: UltragoalPlan, proposal: unknown): UltragoalSteeringAudit {
export function validateUlwLoopSteeringProposal(plan: UlwLoopPlan, proposal: unknown): UlwLoopSteeringAudit {
const reasons: string[] = [];
if (!isPlain(proposal)) reasons.push("proposal must be an object");
const object = isPlain(proposal) ? proposal : {};
@@ -112,16 +112,16 @@ export function validateUltragoalSteeringProposal(plan: UltragoalPlan, proposal:
if (text(object, "rationale") === undefined) reasons.push("missing rationale");
if (hasProtected(proposal)) reasons.push("protected payload");
if (weakens(proposal)) reasons.push("weakened completion");
if (isUltragoalDone(plan)) reasons.push("plan already complete");
if (isUlwLoopDone(plan)) reasons.push("plan already complete");
if (isKind(kind)) validateKind(plan, object, kind, reasons);
return auditFor(proposal, reasons);
}
function goal(plan: UltragoalPlan, id: string | undefined): UltragoalItem | undefined {
function goal(plan: UlwLoopPlan, id: string | undefined): UlwLoopItem | undefined {
return id === undefined ? undefined : plan.goals.find((item) => item.id === id);
}
function validateKind(plan: UltragoalPlan, proposal: object, kind: UltragoalSteeringMutationKind, reasons: string[]): void {
function validateKind(plan: UlwLoopPlan, proposal: object, kind: UlwLoopSteeringMutationKind, reasons: string[]): void {
const target = goal(plan, targets(proposal)[0]);
if (kind === "add_subgoal" && (text(proposal, "title") === undefined || text(proposal, "objective") === undefined)) reasons.push("add_subgoal requires title/objective");
if ((kind === "split_subgoal" || kind === "revise_pending_wording" || kind === "mark_blocked_superseded") && target === undefined) reasons.push(`${kind} requires target`);
@@ -134,7 +134,7 @@ function validateKind(plan: UltragoalPlan, proposal: object, kind: UltragoalStee
if (kind === "revise_criterion") validateCriterion(plan, proposal, reasons);
}
function validateOrder(plan: UltragoalPlan, proposal: object, reasons: string[]): void {
function validateOrder(plan: UlwLoopPlan, proposal: object, reasons: string[]): void {
const requested = pendingOrder(proposal);
const pending = plan.goals.filter((item) => item.status === "pending" && item.steeringStatus === undefined).map((item) => item.id);
if (requested.length === 0) reasons.push("reorder_pending requires ids");
@@ -142,7 +142,7 @@ function validateOrder(plan: UltragoalPlan, proposal: object, reasons: string[])
if (requested.some((id) => !pending.includes(id))) reasons.push("unknown pending id");
}
function validateCriterion(plan: UltragoalPlan, proposal: object, reasons: string[]): void {
function validateCriterion(plan: UlwLoopPlan, proposal: object, reasons: string[]): void {
const target = goal(plan, targets(proposal)[0]);
const criterionId = text(proposal, "criterionId");
if (target === undefined) reasons.push("revise_criterion requires goalId");
@@ -152,7 +152,7 @@ function validateCriterion(plan: UltragoalPlan, proposal: object, reasons: strin
if (model !== undefined && !isModel(model)) reasons.push("invalid userModel");
}
function nextId(plan: UltragoalPlan, offset: number): string {
function nextId(plan: UlwLoopPlan, offset: number): string {
const max = plan.goals.reduce((current, item) => {
const digits = /^G(\d+)$/u.exec(item.id)?.[1];
return digits === undefined ? current : Math.max(current, Number(digits));
@@ -160,18 +160,18 @@ function nextId(plan: UltragoalPlan, offset: number): string {
return `G${String(max + offset).padStart(3, "0")}`;
}
function makeGoal(plan: UltragoalPlan, childGoal: UltragoalSteeringChildGoal, evidence: string, now: string, offset: number): UltragoalItem {
function makeGoal(plan: UlwLoopPlan, childGoal: UlwLoopSteeringChildGoal, evidence: string, now: string, offset: number): UlwLoopItem {
return { id: nextId(plan, offset), title: childGoal.title, objective: childGoal.objective, status: "pending", successCriteria: [], attempt: 0, createdAt: now, updatedAt: now, evidence };
}
export function applySteeringMutation(plan: UltragoalPlan, proposal: UltragoalSteeringProposal, audit: UltragoalSteeringAudit): UltragoalPlan {
export function applySteeringMutation(plan: UlwLoopPlan, proposal: UlwLoopSteeringProposal, audit: UlwLoopSteeringAudit): UlwLoopPlan {
const next = structuredClone(plan);
if (!audit.invariant.accepted) return next;
const now = proposal.now?.toISOString() ?? iso();
if (proposal.kind === "add_subgoal") next.goals.push(makeGoal(next, { title: proposal.title ?? "", objective: proposal.objective ?? "" }, proposal.evidence, now, 1));
if (proposal.kind === "reorder_pending") {
const order = pendingOrder(proposal);
next.goals = [...order.map((id) => goal(next, id)).filter((item): item is UltragoalItem => item !== undefined), ...next.goals.filter((item) => !order.includes(item.id))];
next.goals = [...order.map((id) => goal(next, id)).filter((item): item is UlwLoopItem => item !== undefined), ...next.goals.filter((item) => !order.includes(item.id))];
}
if (proposal.kind === "revise_pending_wording") reviseWording(next, proposal, now);
if (proposal.kind === "split_subgoal" || proposal.kind === "mark_blocked_superseded") splitOrBlock(next, proposal, now);
@@ -180,7 +180,7 @@ export function applySteeringMutation(plan: UltragoalPlan, proposal: UltragoalSt
return next;
}
function reviseWording(plan: UltragoalPlan, proposal: UltragoalSteeringProposal, now: string): void {
function reviseWording(plan: UlwLoopPlan, proposal: UlwLoopSteeringProposal, now: string): void {
const target = goal(plan, targets(proposal)[0]);
if (target === undefined) return;
target.title = revised(proposal, "revisedTitle", "title") ?? target.title;
@@ -190,7 +190,7 @@ function reviseWording(plan: UltragoalPlan, proposal: UltragoalSteeringProposal,
target.updatedAt = now;
}
function splitOrBlock(plan: UltragoalPlan, proposal: UltragoalSteeringProposal, now: string): void {
function splitOrBlock(plan: UlwLoopPlan, proposal: UlwLoopSteeringProposal, now: string): void {
const target = goal(plan, targets(proposal)[0]);
if (target === undefined) return;
const replacements = children(proposal).map((item, index) => makeGoal(plan, item, proposal.evidence, now, index + 1));
@@ -210,7 +210,7 @@ function splitOrBlock(plan: UltragoalPlan, proposal: UltragoalSteeringProposal,
if (plan.activeGoalId === target.id) delete plan.activeGoalId;
}
function reviseCriterion(plan: UltragoalPlan, proposal: UltragoalSteeringProposal, now: string): void {
function reviseCriterion(plan: UlwLoopPlan, proposal: UlwLoopSteeringProposal, now: string): void {
const target = goal(plan, targets(proposal)[0]);
const index = target?.successCriteria.findIndex((item) => item.id === proposal.criterionId) ?? -1;
const current = target?.successCriteria[index];
@@ -220,12 +220,12 @@ function reviseCriterion(plan: UltragoalPlan, proposal: UltragoalSteeringProposa
target.updatedAt = now;
}
function isProposal(value: unknown): value is UltragoalSteeringProposal {
function isProposal(value: unknown): value is UlwLoopSteeringProposal {
return isPlain(value) && isKind(read(value, "kind")) && isSource(read(value, "source")) && isText(read(value, "evidence")) && isText(read(value, "rationale"));
}
export function parseUltragoalSteeringDirective(text: string): UltragoalSteeringProposal | null {
const match = /(?:^|\s)(?:OMO_ULTRAGOAL_STEER|omo\.ultragoal\.steer|omo ultragoal steer):\s*([\s\S]+)$/u.exec(text);
export function parseUlwLoopSteeringDirective(text: string): UlwLoopSteeringProposal | null {
const match = /(?:^|\s)(?:OMO_ULW_LOOP_STEER|omo\.ulw-loop\.steer|omo ulw-loop steer):\s*([\s\S]+)$/u.exec(text);
if (match?.[1] === undefined) return null;
try {
const parsed: unknown = JSON.parse(match[1].trim());
@@ -236,16 +236,16 @@ export function parseUltragoalSteeringDirective(text: string): UltragoalSteering
}
}
export async function steerUltragoal(repoRoot: string, proposal: UltragoalSteeringProposal): Promise<SteerUltragoalResult> {
return withUltragoalMutationLock(repoRoot, async () => {
const plan = await readUltragoalPlan(repoRoot);
export async function steerUlwLoop(repoRoot: string, proposal: UlwLoopSteeringProposal): Promise<SteerUlwLoopResult> {
return withUlwLoopMutationLock(repoRoot, async () => {
const plan = await readUlwLoopPlan(repoRoot);
const key = proposal.idempotencyKey ?? proposal.promptSignature;
const prior = key === undefined ? undefined : (await readSteeringLedgerEntries(repoRoot)).find((entry) => entry.steering?.invariant.accepted === true && (entry.idempotencyKey === key || entry.steering.idempotencyKey === key || entry.steering.promptSignature === key));
if (prior?.steering !== undefined) return { plan, accepted: true, audit: { ...prior.steering, deduped: true }, rejectedReasons: [], deduped: true };
const audit = validateUltragoalSteeringProposal(plan, proposal);
const audit = validateUlwLoopSteeringProposal(plan, proposal);
const accepted = audit.invariant.accepted;
const next = accepted ? applySteeringMutation(plan, proposal, audit) : plan;
const finalAudit: UltragoalSteeringAudit = { ...audit, before: plan };
const finalAudit: UlwLoopSteeringAudit = { ...audit, before: plan };
if (accepted) finalAudit.after = next;
if (accepted) await writePlan(repoRoot, next);
await appendLedger(repoRoot, ledgerEntry(proposal, finalAudit, proposal.now?.toISOString() ?? iso()));
@@ -253,8 +253,8 @@ export async function steerUltragoal(repoRoot: string, proposal: UltragoalSteeri
});
}
function ledgerEntry(proposal: UltragoalSteeringProposal, audit: UltragoalSteeringAudit, at: string): UltragoalLedgerEntry {
const entry: UltragoalLedgerEntry = { at, kind: audit.invariant.accepted ? (proposal.kind === "revise_criterion" ? "criteria_revised" : "steering_accepted") : "steering_rejected", evidence: proposal.evidence, message: proposal.rationale, steering: audit, mutationKind: proposal.kind };
function ledgerEntry(proposal: UlwLoopSteeringProposal, audit: UlwLoopSteeringAudit, at: string): UlwLoopLedgerEntry {
const entry: UlwLoopLedgerEntry = { at, kind: audit.invariant.accepted ? (proposal.kind === "revise_criterion" ? "criteria_revised" : "steering_accepted") : "steering_rejected", evidence: proposal.evidence, message: proposal.rationale, steering: audit, mutationKind: proposal.kind };
const goalId = audit.targetGoalIds[0];
if (goalId !== undefined) entry.goalId = goalId;
if (proposal.criterionId !== undefined) entry.criterionId = proposal.criterionId;
@@ -1,9 +1,9 @@
export const ULTRAGOAL_DIR = ".omo/ultragoal";
export const ULTRAGOAL_BRIEF = "brief.md";
export const ULTRAGOAL_GOALS = "goals.json";
export const ULTRAGOAL_LEDGER = "ledger.jsonl";
export const ULW_LOOP_DIR = ".omo/ulw-loop";
export const ULW_LOOP_BRIEF = "brief.md";
export const ULW_LOOP_GOALS = "goals.json";
export const ULW_LOOP_LEDGER = "ledger.jsonl";
export type UltragoalStatus =
export type UlwLoopStatus =
| "pending"
| "in_progress"
| "complete"
@@ -12,11 +12,11 @@ export type UltragoalStatus =
| "review_blocked"
| "needs_user_decision";
export type UltragoalCodexGoalMode = "aggregate" | "per_story";
export type UlwLoopCodexGoalMode = "aggregate" | "per_story";
export type UltragoalSteeringStatus = "superseded" | "blocked";
export type UlwLoopSteeringStatus = "superseded" | "blocked";
export const ULTRAGOAL_STEERING_MUTATION_KINDS = [
export const ULW_LOOP_STEERING_MUTATION_KINDS = [
"add_subgoal",
"split_subgoal",
"reorder_pending",
@@ -25,22 +25,22 @@ export const ULTRAGOAL_STEERING_MUTATION_KINDS = [
"annotate_ledger",
"mark_blocked_superseded",
] as const satisfies readonly string[];
export type UltragoalSteeringMutationKind = (typeof ULTRAGOAL_STEERING_MUTATION_KINDS)[number];
export type UlwLoopSteeringMutationKind = (typeof ULW_LOOP_STEERING_MUTATION_KINDS)[number];
export type UltragoalSteeringSource = "user_prompt_submit" | "finding" | "cli";
export type UlwLoopSteeringSource = "user_prompt_submit" | "finding" | "cli";
export const ULTRAGOAL_SUCCESS_CRITERION_USER_MODELS = [
export const ULW_LOOP_SUCCESS_CRITERION_USER_MODELS = [
"happy",
"edge",
"regression",
"adversarial",
] as const satisfies readonly string[];
export type UltragoalSuccessCriterionUserModel = (typeof ULTRAGOAL_SUCCESS_CRITERION_USER_MODELS)[number];
export type UlwLoopSuccessCriterionUserModel = (typeof ULW_LOOP_SUCCESS_CRITERION_USER_MODELS)[number];
export const ULTRAGOAL_CRITERION_STATUSES = ["pending", "pass", "fail", "blocked"] as const satisfies readonly string[];
export type UltragoalCriterionStatus = (typeof ULTRAGOAL_CRITERION_STATUSES)[number];
export const ULW_LOOP_CRITERION_STATUSES = ["pending", "pass", "fail", "blocked"] as const satisfies readonly string[];
export type UlwLoopCriterionStatus = (typeof ULW_LOOP_CRITERION_STATUSES)[number];
export const ULTRAGOAL_LEDGER_EVENT_KINDS = [
export const ULW_LOOP_LEDGER_EVENT_KINDS = [
"plan_created",
"goal_started",
"goal_resumed",
@@ -61,20 +61,20 @@ export const ULTRAGOAL_LEDGER_EVENT_KINDS = [
"criterion_blocked",
"criteria_revised",
] as const satisfies readonly string[];
export type UltragoalLedgerEventKind = (typeof ULTRAGOAL_LEDGER_EVENT_KINDS)[number];
export type UlwLoopLedgerEventKind = (typeof ULW_LOOP_LEDGER_EVENT_KINDS)[number];
export interface UltragoalSuccessCriterion {
export interface UlwLoopSuccessCriterion {
readonly id: string;
readonly scenario: string;
readonly userModel: UltragoalSuccessCriterionUserModel;
readonly userModel: UlwLoopSuccessCriterionUserModel;
readonly expectedEvidence: string;
capturedEvidence: string | null;
status: UltragoalCriterionStatus;
status: UlwLoopCriterionStatus;
capturedAt?: string;
notes?: string;
}
export interface UltragoalSteeringInvariantResult {
export interface UlwLoopSteeringInvariantResult {
accepted: boolean;
structuralInvariantAccepted: boolean;
evidenceBackedNecessity: boolean;
@@ -83,21 +83,21 @@ export interface UltragoalSteeringInvariantResult {
reasons?: string[];
}
export interface UltragoalSteeringChildGoal {
export interface UlwLoopSteeringChildGoal {
title: string;
objective: string;
}
export interface UltragoalSteeringAfterPayload {
export interface UlwLoopSteeringAfterPayload {
title?: string;
objective?: string;
pendingGoalIds?: string[];
children?: UltragoalSteeringChildGoal[];
children?: UlwLoopSteeringChildGoal[];
}
export interface UltragoalSteeringProposal {
kind: UltragoalSteeringMutationKind;
source: UltragoalSteeringSource;
export interface UlwLoopSteeringProposal {
kind: UlwLoopSteeringMutationKind;
source: UlwLoopSteeringSource;
targetGoalId?: string;
targetGoalIds?: string[];
criterionId?: string;
@@ -105,48 +105,48 @@ export interface UltragoalSteeringProposal {
rationale: string;
title?: string;
objective?: string;
childGoals?: UltragoalSteeringChildGoal[];
childGoals?: UlwLoopSteeringChildGoal[];
revisedTitle?: string;
revisedObjective?: string;
pendingOrder?: string[];
blockedReason?: string;
after?: UltragoalSteeringAfterPayload;
after?: UlwLoopSteeringAfterPayload;
directiveText?: string;
promptSignature?: string;
idempotencyKey?: string;
now?: Date;
}
export interface UltragoalSteeringAudit {
kind: UltragoalSteeringMutationKind;
source: UltragoalSteeringSource;
export interface UlwLoopSteeringAudit {
kind: UlwLoopSteeringMutationKind;
source: UlwLoopSteeringSource;
targetGoalIds: string[];
criterionId?: string;
before?: unknown;
after?: unknown;
evidence: string;
rationale: string;
invariant: UltragoalSteeringInvariantResult;
invariant: UlwLoopSteeringInvariantResult;
directiveText?: string;
promptSignature?: string;
idempotencyKey?: string;
deduped?: boolean;
}
export interface SteerUltragoalResult {
plan: UltragoalPlan;
export interface SteerUlwLoopResult {
plan: UlwLoopPlan;
accepted: boolean;
audit: UltragoalSteeringAudit;
audit: UlwLoopSteeringAudit;
rejectedReasons: string[];
deduped: boolean;
}
export interface UltragoalItem {
export interface UlwLoopItem {
id: string;
title: string;
objective: string;
status: UltragoalStatus;
successCriteria: UltragoalSuccessCriterion[];
status: UlwLoopStatus;
successCriteria: UlwLoopSuccessCriterion[];
attempt: number;
createdAt: string;
updatedAt: string;
@@ -156,7 +156,7 @@ export interface UltragoalItem {
reviewBlockedAt?: string;
evidence?: string;
failureReason?: string;
steeringStatus?: UltragoalSteeringStatus;
steeringStatus?: UlwLoopSteeringStatus;
supersededBy?: string[];
supersedes?: string[];
blockedReason?: string;
@@ -168,54 +168,54 @@ export interface UltragoalItem {
steeringRationale?: string;
}
export interface UltragoalAggregateCompletion {
export interface UlwLoopAggregateCompletion {
status: "complete";
completedAt: string;
evidence: string;
codexGoal?: unknown;
}
export interface UltragoalPlan {
export interface UlwLoopPlan {
version: 1;
createdAt: string;
updatedAt: string;
briefPath: string;
goalsPath: string;
ledgerPath: string;
codexGoalMode?: UltragoalCodexGoalMode;
codexGoalMode?: UlwLoopCodexGoalMode;
codexObjective?: string;
codexObjectiveAliases?: string[];
aggregateCompletion?: UltragoalAggregateCompletion;
aggregateCompletion?: UlwLoopAggregateCompletion;
activeGoalId?: string;
goals: UltragoalItem[];
goals: UlwLoopItem[];
}
export interface UltragoalLedgerEntry {
export interface UlwLoopLedgerEntry {
at: string;
kind: UltragoalLedgerEventKind;
kind: UlwLoopLedgerEventKind;
goalId?: string;
criterionId?: string;
status?: UltragoalStatus;
criterionStatus?: UltragoalCriterionStatus;
status?: UlwLoopStatus;
criterionStatus?: UlwLoopCriterionStatus;
message?: string;
codexGoal?: unknown;
evidence?: string;
capturedEvidence?: string;
qualityGate?: UltragoalQualityGate;
steering?: UltragoalSteeringAudit;
qualityGate?: UlwLoopQualityGate;
steering?: UlwLoopSteeringAudit;
before?: unknown;
after?: unknown;
mutationKind?: UltragoalSteeringMutationKind;
mutationKind?: UlwLoopSteeringMutationKind;
idempotencyKey?: string;
blockerSignature?: string;
blockerOccurrenceCount?: number;
requiredExternalDecision?: string;
}
export interface CreateUltragoalOptions {
export interface CreateUlwLoopOptions {
brief: string;
goals?: Array<{ title?: string; objective: string }>;
codexGoalMode?: UltragoalCodexGoalMode;
codexGoalMode?: UlwLoopCodexGoalMode;
now?: Date;
force?: boolean;
}
@@ -227,7 +227,7 @@ export interface StartNextOptions {
export interface CheckpointOptions {
goalId: string;
status: Extract<UltragoalStatus, "complete" | "failed"> | "blocked";
status: Extract<UlwLoopStatus, "complete" | "failed"> | "blocked";
evidence?: string;
codexGoal?: unknown;
qualityGate?: unknown;
@@ -235,36 +235,36 @@ export interface CheckpointOptions {
now?: Date;
}
export interface AddUltragoalGoalOptions {
export interface AddUlwLoopGoalOptions {
title: string;
objective: string;
evidence?: string;
now?: Date;
}
export interface RecordFinalReviewBlockersOptions extends AddUltragoalGoalOptions {
export interface RecordFinalReviewBlockersOptions extends AddUlwLoopGoalOptions {
goalId: string;
codexGoal?: unknown;
}
export interface UltragoalQualityGate {
export interface UlwLoopQualityGate {
aiSlopCleaner: { status: "passed"; evidence: string };
verification: { status: "passed"; commands: string[]; evidence: string };
codeReview: { recommendation: "APPROVE"; architectStatus: "CLEAR"; evidence: string };
}
export interface UltragoalErrorOptions {
export interface UlwLoopErrorOptions {
readonly cause?: unknown;
readonly details?: Record<string, unknown>;
}
export class UltragoalError extends Error {
export class UlwLoopError extends Error {
readonly code: string;
readonly details?: Record<string, unknown>;
constructor(message: string, code: string, opts?: UltragoalErrorOptions) {
constructor(message: string, code: string, opts?: UlwLoopErrorOptions) {
super(message, opts?.cause === undefined ? undefined : { cause: opts.cause });
this.name = "UltragoalError";
this.name = "UlwLoopError";
this.code = code;
if (opts?.details !== undefined) {
this.details = opts.details;
@@ -4,52 +4,52 @@ import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { checkpointUltragoal } from "../src/checkpoint.js";
import { ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE } from "../src/goal-status.js";
import { ultragoalBriefPath, ultragoalDir, ultragoalLedgerPath } from "../src/paths.js";
import { checkpointUlwLoop } from "../src/checkpoint.js";
import { ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE } from "../src/goal-status.js";
import { ulwLoopBriefPath, ulwLoopDir, ulwLoopLedgerPath } from "../src/paths.js";
import { writePlan } from "../src/plan-io.js";
import type { UltragoalItem, UltragoalLedgerEntry, UltragoalPlan, UltragoalSuccessCriterion } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
import type { UlwLoopItem, UlwLoopLedgerEntry, UlwLoopPlan, UlwLoopSuccessCriterion } from "../src/types.js";
import { UlwLoopError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
const QUALITY_GATE_PATH = join(process.cwd(), "test", "fixtures", "sample-quality-gate.json");
function criterion(id: string, status: UltragoalSuccessCriterion["status"]): UltragoalSuccessCriterion {
function criterion(id: string, status: UlwLoopSuccessCriterion["status"]): UlwLoopSuccessCriterion {
return { id, scenario: `${id} scenario`, userModel: "happy", expectedEvidence: `${id} proof`, capturedEvidence: status === "pass" ? `${id} passed` : null, status };
}
function goal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function goal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return { id: "G001", title: "Build auth", objective: "Implement JWT auth endpoint", status: "in_progress", successCriteria: [criterion("C001", "pass"), criterion("C002", "pass"), criterion("C003", "pass")], attempt: 1, createdAt: NOW, updatedAt: NOW, ...overrides };
}
function plan(goals: UltragoalItem[], overrides: Partial<UltragoalPlan> = {}): UltragoalPlan {
const result: UltragoalPlan = { version: 1, createdAt: NOW, updatedAt: NOW, briefPath: ".omo/ultragoal/brief.md", goalsPath: ".omo/ultragoal/goals.json", ledgerPath: ".omo/ultragoal/ledger.jsonl", codexGoalMode: "aggregate", codexObjective: ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE, goals };
function plan(goals: UlwLoopItem[], overrides: Partial<UlwLoopPlan> = {}): UlwLoopPlan {
const result: UlwLoopPlan = { version: 1, createdAt: NOW, updatedAt: NOW, briefPath: ".omo/ulw-loop/brief.md", goalsPath: ".omo/ulw-loop/goals.json", ledgerPath: ".omo/ulw-loop/ledger.jsonl", codexGoalMode: "aggregate", codexObjective: ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE, goals };
Object.assign(result, overrides);
const activeGoalId = goals.find((candidate) => candidate.status === "in_progress")?.id;
if (result.activeGoalId === undefined && activeGoalId !== undefined) result.activeGoalId = activeGoalId;
return result;
}
async function samplePlan(overrides: Partial<UltragoalPlan> = {}): Promise<UltragoalPlan> {
const fixture: UltragoalPlan = JSON.parse(await readFile(new URL("./fixtures/sample-plan.json", import.meta.url), "utf8"));
async function samplePlan(overrides: Partial<UlwLoopPlan> = {}): Promise<UlwLoopPlan> {
const fixture: UlwLoopPlan = JSON.parse(await readFile(new URL("./fixtures/sample-plan.json", import.meta.url), "utf8"));
return plan(fixture.goals.map((item, index) => goal({ ...item, attempt: index + 1, createdAt: NOW, updatedAt: NOW })), overrides);
}
async function repoWith(seed: UltragoalPlan): Promise<string> {
async function repoWith(seed: UlwLoopPlan): Promise<string> {
const repo = await mkdtemp(join(tmpdir(), "ug-checkpoint-"));
await mkdir(ultragoalDir(repo), { recursive: true });
await mkdir(ulwLoopDir(repo), { recursive: true });
await writePlan(repo, seed);
return repo;
}
function snapshot(status: "active" | "complete", objective = ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE): string {
function snapshot(status: "active" | "complete", objective = ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE): string {
return JSON.stringify({ goal: { objective, status } });
}
async function lastLedger(repo: string): Promise<UltragoalLedgerEntry> {
const last = (await readFile(ultragoalLedgerPath(repo), "utf8")).trim().split(/\r?\n/).at(-1);
async function lastLedger(repo: string): Promise<UlwLoopLedgerEntry> {
const last = (await readFile(ulwLoopLedgerPath(repo), "utf8")).trim().split(/\r?\n/).at(-1);
if (last === undefined) throw new Error("expected ledger entry");
const entry: UltragoalLedgerEntry = JSON.parse(last);
const entry: UlwLoopLedgerEntry = JSON.parse(last);
return entry;
}
@@ -57,80 +57,80 @@ async function expectCode(action: () => Promise<unknown>, code: string): Promise
try {
await action();
} catch (error) {
expect(error).toBeInstanceOf(UltragoalError);
if (!(error instanceof UltragoalError)) throw error;
expect(error).toBeInstanceOf(UlwLoopError);
if (!(error instanceof UlwLoopError)) throw error;
expect(error.code).toBe(code);
return;
}
throw new Error("Expected UltragoalError");
throw new Error("Expected UlwLoopError");
}
function passGoal(id: string, overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function passGoal(id: string, overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return goal({ id, successCriteria: [criterion("C001", "pass"), criterion("C002", "pass"), criterion("C003", "pass")], ...overrides });
}
describe("checkpointUltragoal status=complete criteria gate", () => {
it("THROWS ultragoal_criteria_not_all_pass when any criterion is pending", async () => {
describe("checkpointUlwLoop status=complete criteria gate", () => {
it("THROWS ulw_loop_criteria_not_all_pass when any criterion is pending", async () => {
const repo = await repoWith(await samplePlan({ goals: [goal({ successCriteria: [criterion("C001", "pass"), criterion("C002", "pending"), criterion("C003", "pass")] })] }));
await expectCode(() => checkpointUltragoal(repo, { goalId: "G001", status: "complete", evidence: "done" }), "ultragoal_criteria_not_all_pass");
await expectCode(() => checkpointUlwLoop(repo, { goalId: "G001", status: "complete", evidence: "done" }), "ulw_loop_criteria_not_all_pass");
});
it("THROWS when any criterion is fail or blocked", async () => {
for (const status of ["fail", "blocked"] satisfies UltragoalSuccessCriterion["status"][]) {
for (const status of ["fail", "blocked"] satisfies UlwLoopSuccessCriterion["status"][]) {
const repo = await repoWith(plan([goal({ successCriteria: [criterion("C001", "pass"), criterion("C002", status), criterion("C003", "pass")] })]));
await expectCode(() => checkpointUltragoal(repo, { goalId: "G001", status: "complete", evidence: "done" }), "ultragoal_criteria_not_all_pass");
await expectCode(() => checkpointUlwLoop(repo, { goalId: "G001", status: "complete", evidence: "done" }), "ulw_loop_criteria_not_all_pass");
}
});
it("THROWS when criteria list is empty", async () => {
const repo = await repoWith(plan([goal({ successCriteria: [] }), goal({ id: "G002", status: "pending" })]));
await expectCode(() => checkpointUltragoal(repo, { goalId: "G001", status: "complete", evidence: "done", codexGoalJson: snapshot("active") }), "ultragoal_criteria_not_all_pass");
await expectCode(() => checkpointUlwLoop(repo, { goalId: "G001", status: "complete", evidence: "done", codexGoalJson: snapshot("active") }), "ulw_loop_criteria_not_all_pass");
});
it("ACCEPTS complete when ALL criteria pass (with valid snapshot)", async () => {
const repo = await repoWith(plan([passGoal("G001"), goal({ id: "G002", status: "pending" })]));
const result = await checkpointUltragoal(repo, { goalId: "G001", status: "complete", evidence: "implementation done and tests passed", codexGoalJson: snapshot("active") });
const result = await checkpointUlwLoop(repo, { goalId: "G001", status: "complete", evidence: "implementation done and tests passed", codexGoalJson: snapshot("active") });
expect(result.goal.status).toBe("complete");
expect((await lastLedger(repo)).kind).toBe("goal_completed");
});
});
describe("checkpointUltragoal reconciliation (status=complete)", () => {
describe("checkpointUlwLoop reconciliation (status=complete)", () => {
it("succeeds when snapshot objective matches expected (aggregate active)", async () => {
const repo = await repoWith(plan([passGoal("G001"), goal({ id: "G002", status: "pending" })]));
await expect(checkpointUltragoal(repo, { goalId: "G001", status: "complete", evidence: "work complete and validation passed", codexGoalJson: snapshot("active") })).resolves.toMatchObject({ goal: { status: "complete" } });
await expect(checkpointUlwLoop(repo, { goalId: "G001", status: "complete", evidence: "work complete and validation passed", codexGoalJson: snapshot("active") })).resolves.toMatchObject({ goal: { status: "complete" } });
});
it("throws on mismatched objective", async () => {
const repo = await repoWith(plan([passGoal("G001"), goal({ id: "G002", status: "pending" })]));
await expectCode(() => checkpointUltragoal(repo, { goalId: "G001", status: "complete", evidence: "work complete and validation passed", codexGoalJson: snapshot("active", "wrong objective") }), "ultragoal_codex_snapshot_mismatch");
await expectCode(() => checkpointUlwLoop(repo, { goalId: "G001", status: "complete", evidence: "work complete and validation passed", codexGoalJson: snapshot("active", "wrong objective") }), "ulw_loop_codex_snapshot_mismatch");
});
it("throws on mismatched status (snapshot complete when expected active)", async () => {
const repo = await repoWith(plan([passGoal("G001"), goal({ id: "G002", status: "pending" })]));
await expectCode(() => checkpointUltragoal(repo, { goalId: "G001", status: "complete", evidence: "work complete and validation passed", codexGoalJson: snapshot("complete") }), "ultragoal_codex_snapshot_mismatch");
await expectCode(() => checkpointUlwLoop(repo, { goalId: "G001", status: "complete", evidence: "work complete and validation passed", codexGoalJson: snapshot("complete") }), "ulw_loop_codex_snapshot_mismatch");
});
});
describe("checkpointUltragoal final story", () => {
describe("checkpointUlwLoop final story", () => {
it("requires quality-gate-json for the final goal complete", async () => {
const repo = await repoWith(plan([passGoal("G001", { status: "complete" }), passGoal("G002")], { activeGoalId: "G002" }));
await expectCode(() => checkpointUltragoal(repo, { goalId: "G002", status: "complete", evidence: "final work complete and validation passed", codexGoalJson: snapshot("complete") }), "ULTRAGOAL_QUALITY_GATE_INVALID");
await expectCode(() => checkpointUlwLoop(repo, { goalId: "G002", status: "complete", evidence: "final work complete and validation passed", codexGoalJson: snapshot("complete") }), "ULW_LOOP_QUALITY_GATE_INVALID");
});
it("accepts final story when quality gate JSON includes valid criteriaCoverage", async () => {
const repo = await repoWith(plan([passGoal("G001", { status: "complete" }), passGoal("G002")], { activeGoalId: "G002" }));
const result = await checkpointUltragoal(repo, { goalId: "G002", status: "complete", evidence: "final work complete and validation passed", codexGoalJson: snapshot("complete"), qualityGateJson: QUALITY_GATE_PATH });
const result = await checkpointUlwLoop(repo, { goalId: "G002", status: "complete", evidence: "final work complete and validation passed", codexGoalJson: snapshot("complete"), qualityGateJson: QUALITY_GATE_PATH });
expect(result.aggregateCompletion?.status).toBe("complete");
expect(result.plan.aggregateCompletion?.status).toBe("complete");
});
it("ACCEPTS complete when task-scoped completed Codex objective maps to the ultragoal brief", async () => {
const taskObjective = "Fix ultragoal objective mismatch and install local ulw";
it("ACCEPTS complete when task-scoped completed Codex objective maps to the ulw-loop brief", async () => {
const taskObjective = "Fix ulw-loop objective mismatch and install local ulw";
const repo = await repoWith(plan([passGoal("G001")], { activeGoalId: "G001" }));
await writeFile(ultragoalBriefPath(repo), `${taskObjective}\n`, "utf8");
await writeFile(ulwLoopBriefPath(repo), `${taskObjective}\n`, "utf8");
const result = await checkpointUltragoal(repo, {
const result = await checkpointUlwLoop(repo, {
goalId: "G001",
status: "complete",
evidence: "final implementation complete and quality gate passed",
@@ -144,10 +144,10 @@ describe("checkpointUltragoal final story", () => {
it("explains final task-scoped objective mapping when completed Codex objective is unrelated", async () => {
const repo = await repoWith(plan([passGoal("G001")], { activeGoalId: "G001" }));
await writeFile(ultragoalBriefPath(repo), "Fix ultragoal objective mismatch and install local ulw\n", "utf8");
await writeFile(ulwLoopBriefPath(repo), "Fix ulw-loop objective mismatch and install local ulw\n", "utf8");
await expect(
checkpointUltragoal(repo, {
checkpointUlwLoop(repo, {
goalId: "G001",
status: "complete",
evidence: "final implementation complete and quality gate passed",
@@ -158,10 +158,10 @@ describe("checkpointUltragoal final story", () => {
});
});
describe("checkpointUltragoal status=failed", () => {
describe("checkpointUlwLoop status=failed", () => {
it("sets goal.status=failed, goal.failedAt, appends ledger", async () => {
const repo = await repoWith(plan([goal({ successCriteria: [criterion("C001", "pending")] })]));
const result = await checkpointUltragoal(repo, { goalId: "G001", status: "failed", evidence: "tests failed" });
const result = await checkpointUlwLoop(repo, { goalId: "G001", status: "failed", evidence: "tests failed" });
expect(result.goal.status).toBe("failed");
expect(result.goal.failedAt).toMatch(/^\d{4}-\d{2}-\d{2}T/u);
expect((await lastLedger(repo)).kind).toBe("goal_failed");
@@ -169,27 +169,27 @@ describe("checkpointUltragoal status=failed", () => {
it("classifies external authorization blocker signatures", async () => {
const repo = await repoWith(plan([goal()]));
const result = await checkpointUltragoal(repo, { goalId: "G001", status: "failed", evidence: "ghcr.io returned 401 authentication required because token missing" });
const result = await checkpointUlwLoop(repo, { goalId: "G001", status: "failed", evidence: "ghcr.io returned 401 authentication required because token missing" });
expect(result.goal.blockerSignature).toBe("GHCR_PULL_ACCESS:HTTP_401_ANONYMOUS:GHCR_VISIBILITY_OR_CREDENTIAL_REQUIRED");
});
it("after 3 same-signature blockers, marks needs_user_decision + nonRetriable", async () => {
const repo = await repoWith(plan([goal({ id: "G001", status: "failed", blockerSignature: "EXTERNAL_AUTHORIZATION_REQUIRED" }), goal({ id: "G002", status: "blocked", blockerSignature: "EXTERNAL_AUTHORIZATION_REQUIRED" }), goal({ id: "G003" })], { activeGoalId: "G003" }));
const result = await checkpointUltragoal(repo, { goalId: "G003", status: "failed", evidence: "Registry returned 401 because credentials are missing" });
const result = await checkpointUlwLoop(repo, { goalId: "G003", status: "failed", evidence: "Registry returned 401 because credentials are missing" });
expect(result.goal.status).toBe("needs_user_decision");
expect(result.goal.nonRetriable).toBe(true);
});
it("skips the criteria gate for failed status", async () => {
const repo = await repoWith(plan([goal({ successCriteria: [criterion("C001", "pending")] })]));
await expect(checkpointUltragoal(repo, { goalId: "G001", status: "failed", evidence: "not done" })).resolves.toMatchObject({ goal: { status: "failed" } });
await expect(checkpointUlwLoop(repo, { goalId: "G001", status: "failed", evidence: "not done" })).resolves.toMatchObject({ goal: { status: "failed" } });
});
});
describe("checkpointUltragoal status=blocked", () => {
describe("checkpointUlwLoop status=blocked", () => {
it("preserves blocker fields + appends ledger", async () => {
const repo = await repoWith(plan([goal()]));
const result = await checkpointUltragoal(repo, { goalId: "G001", status: "blocked", evidence: "ghcr.io requires token and credentials are missing" });
const result = await checkpointUlwLoop(repo, { goalId: "G001", status: "blocked", evidence: "ghcr.io requires token and credentials are missing" });
expect(result.goal.status).toBe("blocked");
expect(result.goal.blockedReason).toContain("ghcr.io");
expect(result.goal.blockerSignature).toContain("GHCR_PULL_ACCESS");
@@ -198,16 +198,16 @@ describe("checkpointUltragoal status=blocked", () => {
it("skips the criteria gate for blocked status", async () => {
const repo = await repoWith(plan([goal({ successCriteria: [criterion("C001", "pending")] })]));
await expect(checkpointUltragoal(repo, { goalId: "G001", status: "blocked", evidence: "waiting for approval" })).resolves.toMatchObject({ goal: { status: "blocked" } });
await expect(checkpointUlwLoop(repo, { goalId: "G001", status: "blocked", evidence: "waiting for approval" })).resolves.toMatchObject({ goal: { status: "blocked" } });
});
});
describe("checkpointUltragoal rebrand", () => {
describe("checkpointUlwLoop rebrand", () => {
it("does not emit legacy brand token in any returned text or ledger payload", async () => {
const repo = await repoWith(plan([passGoal("G001"), goal({ id: "G002", status: "pending" })]));
const result = await checkpointUltragoal(repo, { goalId: "G001", status: "complete", evidence: "implementation done in .omo/ultragoal/goals.json for G001 and validation passed", codexGoalJson: snapshot("active") });
const result = await checkpointUlwLoop(repo, { goalId: "G001", status: "complete", evidence: "implementation done in .omo/ulw-loop/goals.json for G001 and validation passed", codexGoalJson: snapshot("active") });
const forbidden = ["o", "m", "x"].join("");
const payload = `${JSON.stringify(result)}\n${await readFile(ultragoalLedgerPath(repo), "utf8")}`.toLowerCase();
const payload = `${JSON.stringify(result)}\n${await readFile(ulwLoopLedgerPath(repo), "utf8")}`.toLowerCase();
expect(payload).not.toContain(forbidden);
});
});
@@ -3,8 +3,8 @@ import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { ultragoalCommand } from "../src/cli-commands.ts";
import { ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE } from "../src/goal-status.js";
import { ulwLoopCommand } from "../src/cli-commands.ts";
import { ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE } from "../src/goal-status.js";
let testDir: string;
let out: string[];
@@ -38,12 +38,12 @@ function stdoutJson(): Record<string, unknown> {
return JSON.parse(out.join(""));
}
function codexSnapshot(status: "active" | "complete" = "active"): string {
return JSON.stringify({ goal: { objective: ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE, status } });
return JSON.stringify({ goal: { objective: ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE, status } });
}
async function createPlan(brief = "- Goal A\n- Goal B"): Promise<Record<string, unknown>> {
resetOutput();
expect(await ultragoalCommand(["create-goals", "--brief", brief, "--json"])).toBe(0);
expect(await ulwLoopCommand(["create-goals", "--brief", brief, "--json"])).toBe(0);
const parsed = stdoutJson();
resetOutput();
return parsed;
@@ -51,7 +51,7 @@ async function createPlan(brief = "- Goal A\n- Goal B"): Promise<Record<string,
async function passCriterion(goalId: string, criterionId: string): Promise<void> {
expect(
await ultragoalCommand([
await ulwLoopCommand([
"record-evidence",
"--goal-id",
goalId,
@@ -66,41 +66,41 @@ async function passCriterion(goalId: string, criterionId: string): Promise<void>
resetOutput();
}
describe("ultragoalCommand help", () => {
describe("ulwLoopCommand help", () => {
it("prints usage when no subcommand", async () => {
expect(await ultragoalCommand([])).toBe(0);
expect(out.join("")).toContain("omo ultragoal");
expect(await ulwLoopCommand([])).toBe(0);
expect(out.join("")).toContain("omo ulw-loop");
});
});
describe("ultragoalCommand create-goals", () => {
describe("ulwLoopCommand create-goals", () => {
it("creates plan + writes 3 artifacts + seeds criteria per goal", async () => {
const code = await ultragoalCommand(["create-goals", "--brief", "- Goal A\n- Goal B", "--json"]);
const code = await ulwLoopCommand(["create-goals", "--brief", "- Goal A\n- Goal B", "--json"]);
expect(code).toBe(0);
const parsed = stdoutJson();
expect(parsed).toMatchObject({ ok: true });
expect(parsed).toHaveProperty("plan.goals.0.successCriteria.0.id", "C001");
expect(await readFile(join(testDir, ".omo/ultragoal/brief.md"), "utf8")).toContain("Goal A");
expect(await readFile(join(testDir, ".omo/ultragoal/goals.json"), "utf8")).toContain("successCriteria");
expect(await readFile(join(testDir, ".omo/ultragoal/ledger.jsonl"), "utf8")).toContain("plan_created");
expect(await readFile(join(testDir, ".omo/ulw-loop/brief.md"), "utf8")).toContain("Goal A");
expect(await readFile(join(testDir, ".omo/ulw-loop/goals.json"), "utf8")).toContain("successCriteria");
expect(await readFile(join(testDir, ".omo/ulw-loop/ledger.jsonl"), "utf8")).toContain("plan_created");
});
});
describe("ultragoalCommand status", () => {
describe("ulwLoopCommand status", () => {
it("prints plan summary including criteria counts", async () => {
await createPlan();
expect(await ultragoalCommand(["status"])).toBe(0);
expect(await ulwLoopCommand(["status"])).toBe(0);
expect(out.join("")).toContain("criteria: 0/6 pass");
});
});
describe("ultragoalCommand complete-goals", () => {
describe("ulwLoopCommand complete-goals", () => {
it("starts the next goal and returns a Codex instruction", async () => {
await createPlan();
expect(await ultragoalCommand(["complete-goals", "--json"])).toBe(0);
expect(await ulwLoopCommand(["complete-goals", "--json"])).toBe(0);
expect(stdoutJson()).toMatchObject({
ok: true,
goal: { status: "in_progress" },
@@ -109,12 +109,12 @@ describe("ultragoalCommand complete-goals", () => {
});
});
describe("ultragoalCommand record-evidence", () => {
describe("ulwLoopCommand record-evidence", () => {
it("records evidence + returns updated criterion", async () => {
await createPlan();
expect(
await ultragoalCommand([
await ulwLoopCommand([
"record-evidence",
"--goal-id",
"G001-goal-a",
@@ -137,7 +137,7 @@ describe("ultragoalCommand record-evidence", () => {
await createPlan();
expect(
await ultragoalCommand([
await ulwLoopCommand([
"record-evidence",
"--goal-id",
"G404",
@@ -149,22 +149,22 @@ describe("ultragoalCommand record-evidence", () => {
"x",
]),
).toBe(1);
expect(err.join("")).toContain("[ultragoal]");
expect(err.join("")).toContain("[ulw-loop]");
});
it("returns 1 + error on missing flags", async () => {
expect(
await ultragoalCommand(["record-evidence", "--criterion-id", "C001", "--status", "pass", "--evidence", "x"]),
await ulwLoopCommand(["record-evidence", "--criterion-id", "C001", "--status", "pass", "--evidence", "x"]),
).toBe(1);
expect(err.join("")).toContain("Missing --goal-id");
});
});
describe("ultragoalCommand criteria", () => {
describe("ulwLoopCommand criteria", () => {
it("lists criteria for a goal", async () => {
await createPlan();
expect(await ultragoalCommand(["criteria", "--goal-id", "G001-goal-a"])).toBe(0);
expect(await ulwLoopCommand(["criteria", "--goal-id", "G001-goal-a"])).toBe(0);
expect(out.join("")).toContain("C001");
expect(out.join("")).toContain("happy");
});
@@ -172,18 +172,18 @@ describe("ultragoalCommand criteria", () => {
it("supports --json output", async () => {
await createPlan();
expect(await ultragoalCommand(["criteria", "--goal-id", "G001-goal-a", "--json"])).toBe(0);
expect(await ulwLoopCommand(["criteria", "--goal-id", "G001-goal-a", "--json"])).toBe(0);
expect(stdoutJson()).toMatchObject({ ok: true, goalId: "G001-goal-a" });
expect(stdoutJson()).toHaveProperty("criteria.0.id", "C001");
});
});
describe("ultragoalCommand checkpoint", () => {
describe("ulwLoopCommand checkpoint", () => {
it("REJECTS status=complete when criteria pending", async () => {
await createPlan();
expect(
await ultragoalCommand([
await ulwLoopCommand([
"checkpoint",
"--goal-id",
"G001-goal-a",
@@ -205,7 +205,7 @@ describe("ultragoalCommand checkpoint", () => {
await passCriterion("G001-goal-a", "C003");
expect(
await ultragoalCommand([
await ulwLoopCommand([
"checkpoint",
"--goal-id",
"G001-goal-a",
@@ -222,12 +222,12 @@ describe("ultragoalCommand checkpoint", () => {
});
});
describe("ultragoalCommand steer", () => {
describe("ulwLoopCommand steer", () => {
it("dispatches to the steering engine", async () => {
await createPlan();
expect(
await ultragoalCommand([
await ulwLoopCommand([
"steer",
"--kind",
"add_subgoal",
@@ -250,25 +250,25 @@ describe("ultragoalCommand steer", () => {
});
});
describe("ultragoalCommand add-goal", () => {
describe("ulwLoopCommand add-goal", () => {
it("appends a pending goal", async () => {
await createPlan();
expect(await ultragoalCommand(["add-goal", "--title", "Later", "--objective", "Do later", "--json"])).toBe(0);
expect(await ulwLoopCommand(["add-goal", "--title", "Later", "--objective", "Do later", "--json"])).toBe(0);
expect(stdoutJson()).toMatchObject({ ok: true, goal: { title: "Later", status: "pending" } });
});
});
describe("ultragoalCommand unknown", () => {
describe("ulwLoopCommand unknown", () => {
it("returns 1 + prints help on unknown subcommand", async () => {
expect(await ultragoalCommand(["wat"])).toBe(1);
expect(out.join("")).toContain("omo ultragoal");
expect(await ulwLoopCommand(["wat"])).toBe(1);
expect(out.join("")).toContain("omo ulw-loop");
});
});
describe("ultragoalCommand error handling", () => {
it("returns 1 + prints [ultragoal] prefix on UltragoalError", async () => {
expect(await ultragoalCommand(["status"])).toBe(1);
expect(err.join("")).toContain("[ultragoal]");
describe("ulwLoopCommand error handling", () => {
it("returns 1 + prints [ulw-loop] prefix on UlwLoopError", async () => {
expect(await ulwLoopCommand(["status"])).toBe(1);
expect(err.join("")).toContain("[ulw-loop]");
});
});
@@ -13,13 +13,13 @@ import {
readRepeated,
readValue,
} from "../src/cli-arg-parser.js";
import { normalizeCodexGoalMode, printStatus, ULTRAGOAL_HELP } from "../src/cli-output.js";
import type { UltragoalItem, UltragoalPlan, UltragoalSuccessCriterion } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
import { normalizeCodexGoalMode, printStatus, ULW_LOOP_HELP } from "../src/cli-output.js";
import type { UlwLoopItem, UlwLoopPlan, UlwLoopSuccessCriterion } from "../src/types.js";
import { UlwLoopError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
function criterion(overrides: Partial<UltragoalSuccessCriterion> = {}): UltragoalSuccessCriterion {
function criterion(overrides: Partial<UlwLoopSuccessCriterion> = {}): UlwLoopSuccessCriterion {
return {
id: "C001",
scenario: "happy path returns 200",
@@ -31,7 +31,7 @@ function criterion(overrides: Partial<UltragoalSuccessCriterion> = {}): Ultragoa
};
}
function goal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function goal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Auth endpoint",
@@ -49,14 +49,14 @@ function goal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
};
}
function plan(overrides: Partial<UltragoalPlan> = {}): UltragoalPlan {
function plan(overrides: Partial<UlwLoopPlan> = {}): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
activeGoalId: "G001",
goals: [goal()],
...overrides,
@@ -159,7 +159,7 @@ describe("parseRecordEvidenceArgs", () => {
it("throws when goal-id missing", () => {
expect(() =>
parseRecordEvidenceArgs(["record-evidence", "--criterion-id", "C001", "--status", "pass", "--evidence", "x"]),
).toThrow(UltragoalError);
).toThrow(UlwLoopError);
});
it("throws when status is not pass|fail|blocked", () => {
@@ -175,7 +175,7 @@ describe("parseRecordEvidenceArgs", () => {
"--evidence",
"x",
]),
).toThrow(UltragoalError);
).toThrow(UlwLoopError);
});
it("includes optional --notes when present", () => {
@@ -197,24 +197,24 @@ describe("parseRecordEvidenceArgs", () => {
});
});
describe("ULTRAGOAL_HELP", () => {
it("mentions omo ultragoal + every subcommand", () => {
expect(ULTRAGOAL_HELP).toContain("omo ultragoal");
expect(ULTRAGOAL_HELP).toContain("create-goals");
expect(ULTRAGOAL_HELP).toContain("complete-goals");
expect(ULTRAGOAL_HELP).toContain("status");
expect(ULTRAGOAL_HELP).toContain("checkpoint");
expect(ULTRAGOAL_HELP).toContain("steer");
expect(ULTRAGOAL_HELP).toContain("record-evidence");
expect(ULTRAGOAL_HELP).toContain("criteria");
expect(ULTRAGOAL_HELP).toContain("add-goal");
expect(ULTRAGOAL_HELP).toContain("record-review-blockers");
describe("ULW_LOOP_HELP", () => {
it("mentions omo ulw-loop + every subcommand", () => {
expect(ULW_LOOP_HELP).toContain("omo ulw-loop");
expect(ULW_LOOP_HELP).toContain("create-goals");
expect(ULW_LOOP_HELP).toContain("complete-goals");
expect(ULW_LOOP_HELP).toContain("status");
expect(ULW_LOOP_HELP).toContain("checkpoint");
expect(ULW_LOOP_HELP).toContain("steer");
expect(ULW_LOOP_HELP).toContain("record-evidence");
expect(ULW_LOOP_HELP).toContain("criteria");
expect(ULW_LOOP_HELP).toContain("add-goal");
expect(ULW_LOOP_HELP).toContain("record-review-blockers");
});
it("never mentions the legacy typo", () => {
const typo = ["o", "m", "x"].join("");
expect(ULTRAGOAL_HELP).not.toMatch(new RegExp(typo, "i"));
expect(ULW_LOOP_HELP).not.toMatch(new RegExp(typo, "i"));
});
});
@@ -244,7 +244,7 @@ describe("normalizeCodexGoalMode", () => {
expect(normalizeCodexGoalMode("per_story")).toBe("per_story");
});
it("throws UltragoalError when invalid", () => {
expect(() => normalizeCodexGoalMode("per-story")).toThrow(UltragoalError);
it("throws UlwLoopError when invalid", () => {
expect(() => normalizeCodexGoalMode("per-story")).toThrow(UlwLoopError);
});
});
@@ -11,24 +11,24 @@ import {
parseSteeringSource,
printSteerResult,
} from "../src/cli-steering.js";
import type { SteerUltragoalResult, UltragoalPlan } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
import type { SteerUlwLoopResult, UlwLoopPlan } from "../src/types.js";
import { UlwLoopError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
function plan(): UltragoalPlan {
function plan(): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
goals: [],
};
}
function steerResult(overrides: Partial<SteerUltragoalResult> = {}): SteerUltragoalResult {
function steerResult(overrides: Partial<SteerUlwLoopResult> = {}): SteerUlwLoopResult {
return {
plan: plan(),
accepted: true,
@@ -73,11 +73,11 @@ describe("parseSteeringKind", () => {
});
it("throws when --kind missing", () => {
expect(() => parseSteeringKind([])).toThrow(UltragoalError);
expect(() => parseSteeringKind([])).toThrow(UlwLoopError);
});
it("throws when kind unknown", () => {
expect(() => parseSteeringKind(["--kind", "bogus"])).toThrow(UltragoalError);
expect(() => parseSteeringKind(["--kind", "bogus"])).toThrow(UlwLoopError);
});
});
@@ -128,13 +128,13 @@ describe("parseSteeringProposal add_subgoal", () => {
"--rationale",
"y",
]),
).rejects.toThrow(UltragoalError);
).rejects.toThrow(UlwLoopError);
});
it("throws when --evidence missing", async () => {
await expect(
parseSteeringProposal(["--kind", "add_subgoal", "--title", "New", "--objective", "Build", "--rationale", "y"]),
).rejects.toThrow(UltragoalError);
).rejects.toThrow(UlwLoopError);
});
});
@@ -214,7 +214,7 @@ describe("parseSteeringProposal revise_criterion", () => {
"--rationale",
"y",
]),
).rejects.toThrow(UltragoalError);
).rejects.toThrow(UlwLoopError);
});
it("throws when goal-id missing", async () => {
@@ -231,7 +231,7 @@ describe("parseSteeringProposal revise_criterion", () => {
"--rationale",
"y",
]),
).rejects.toThrow(UltragoalError);
).rejects.toThrow(UlwLoopError);
});
it("throws when criterion-id missing", async () => {
@@ -248,7 +248,7 @@ describe("parseSteeringProposal revise_criterion", () => {
"--rationale",
"y",
]),
).rejects.toThrow(UltragoalError);
).rejects.toThrow(UlwLoopError);
});
});
@@ -387,7 +387,7 @@ describe("normalizeSteeringProposal", () => {
it("rejects empty evidence after trim", () => {
expect(() =>
normalizeSteeringProposal({ kind: "annotate_ledger", source: "cli", evidence: " ", rationale: "y" }),
).toThrow(UltragoalError);
).toThrow(UlwLoopError);
});
});
@@ -401,7 +401,7 @@ describe("printSteerResult", () => {
it("prints human-readable when json=false", () => {
const output = captureStdout(() => printSteerResult(steerResult(), false));
expect(output).toContain("ultragoal steer: accepted add_subgoal");
expect(output).toContain("ultragoal status");
expect(output).toContain("ulw-loop steer: accepted add_subgoal");
expect(output).toContain("ulw-loop status");
});
});
@@ -1,12 +1,12 @@
import { describe, expect, it } from "vitest";
import { buildCodexGoalInstruction } from "../src/codex-goal-instruction.js";
import { ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE } from "../src/goal-status.js";
import type { UltragoalItem, UltragoalPlan, UltragoalSuccessCriterion } from "../src/types.js";
import { ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE } from "../src/goal-status.js";
import type { UlwLoopItem, UlwLoopPlan, UlwLoopSuccessCriterion } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): UltragoalSuccessCriterion {
function makeCriterion(overrides: Partial<UlwLoopSuccessCriterion> = {}): UlwLoopSuccessCriterion {
return {
id: "C001",
scenario: "happy path",
@@ -18,7 +18,7 @@ function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): Ultr
};
}
function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function makeGoal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Goal one",
@@ -32,24 +32,24 @@ function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
};
}
function makePlan(overrides: Partial<UltragoalPlan> = {}): UltragoalPlan {
function makePlan(overrides: Partial<UlwLoopPlan> = {}): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
goals: [],
...overrides,
};
}
describe("buildCodexGoalInstruction aggregate mode", () => {
it("references the aggregate handoff and the .omo/ultragoal/goals.json artifact", () => {
it("references the aggregate handoff and the .omo/ulw-loop/goals.json artifact", () => {
const { text } = buildCodexGoalInstruction({ plan: makePlan({ codexGoalMode: "aggregate" }), goal: makeGoal() });
expect(text).toContain("aggregate");
expect(text).toContain(".omo/ultragoal/goals.json");
expect(text).toContain(".omo/ulw-loop/goals.json");
});
it("given aggregate mode when rendering create_goal payload then omits numeric limits", () => {
@@ -58,7 +58,7 @@ describe("buildCodexGoalInstruction aggregate mode", () => {
goal: makeGoal(),
});
expect(json).toEqual({
objective: ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE,
objective: ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE,
status: "active",
});
expect(text).toContain("objective and status only");
@@ -146,8 +146,8 @@ describe("buildCodexGoalInstruction rebrand audit", () => {
expect(text).not.toMatch(new RegExp(legacyBrand, "i"));
});
it("references .omo/ultragoal in artifact paths", () => {
it("references .omo/ulw-loop in artifact paths", () => {
const { text } = buildCodexGoalInstruction({ plan: makePlan({ codexGoalMode: "aggregate" }), goal: makeGoal() });
expect(text).toContain(".omo/ultragoal");
expect(text).toContain(".omo/ulw-loop");
});
});
@@ -92,7 +92,7 @@ describe("readCodexGoalSnapshotInput", () => {
// then
expect(snapshot?.available).toBe(true);
expect(snapshot?.objective).toBe("Complete the durable ultragoal plan");
expect(snapshot?.objective).toBe("Complete the durable ulw-loop plan");
});
it("throws CodexGoalSnapshotError when input is neither JSON nor a path", async () => {
@@ -6,34 +6,34 @@ import { describe, expect, it } from "vitest";
import {
applyPreToolUseGoalBudgetGuard,
applyUserPromptUltragoalSteering,
applyUserPromptUlwLoopSteering,
type PreToolUsePayload,
parseUserPromptSubmitPayload,
runPreToolUseGoalBudgetGuardCli,
runUltragoalHookCli,
runUlwLoopHookCli,
type UserPromptSubmitPayload,
} from "../src/codex-hook.js";
import { ultragoalDir } from "../src/paths.js";
import { ulwLoopDir } from "../src/paths.js";
import { writePlan } from "../src/plan-io.js";
import type { UltragoalPlan } from "../src/types.js";
import type { UlwLoopPlan } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
async function bootstrapPlanRepo(): Promise<string> {
const repoRoot = await mkdtemp(join(tmpdir(), "ug-hook-"));
await mkdir(ultragoalDir(repoRoot), { recursive: true });
await mkdir(ulwLoopDir(repoRoot), { recursive: true });
await writePlan(repoRoot, samplePlan());
return repoRoot;
}
function samplePlan(): UltragoalPlan {
function samplePlan(): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
goals: [
{
id: "G001",
@@ -70,7 +70,7 @@ function preToolPayload(toolName: string, toolInput: unknown): PreToolUsePayload
function payloadWithRuntimeEvent(hookEventName: string): UserPromptSubmitPayload {
const input = payload(
'OMO_ULTRAGOAL_STEER: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
'OMO_ULW_LOOP_STEER: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
"/tmp",
);
Object.defineProperty(input, "hook_event_name", { value: hookEventName });
@@ -93,7 +93,7 @@ describe("parseUserPromptSubmitPayload", () => {
const raw = await readFile("test/fixtures/user-prompt-submit.json", "utf8");
const parsed = parseUserPromptSubmitPayload(raw);
expect(parsed?.hook_event_name).toBe("UserPromptSubmit");
expect(parsed?.prompt).toContain("OMO_ULTRAGOAL_STEER");
expect(parsed?.prompt).toContain("OMO_ULW_LOOP_STEER");
});
it("returns null for empty input", () => {
@@ -109,12 +109,12 @@ describe("parseUserPromptSubmitPayload", () => {
});
});
describe("applyUserPromptUltragoalSteering - OMO directive patterns", () => {
it("processes OMO_ULTRAGOAL_STEER: prompt and returns audit text on success", async () => {
describe("applyUserPromptUlwLoopSteering - OMO directive patterns", () => {
it("processes OMO_ULW_LOOP_STEER: prompt and returns audit text on success", async () => {
const repoRoot = await bootstrapPlanRepo();
const out = await applyUserPromptUltragoalSteering(
const out = await applyUserPromptUlwLoopSteering(
payload(
'OMO_ULTRAGOAL_STEER: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
'OMO_ULW_LOOP_STEER: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
repoRoot,
),
);
@@ -122,22 +122,22 @@ describe("applyUserPromptUltragoalSteering - OMO directive patterns", () => {
expect(out).toContain("annotate_ledger");
});
it("processes omo.ultragoal.steer: pattern", async () => {
it("processes omo.ulw-loop.steer: pattern", async () => {
const repoRoot = await bootstrapPlanRepo();
const out = await applyUserPromptUltragoalSteering(
const out = await applyUserPromptUlwLoopSteering(
payload(
'omo.ultragoal.steer: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
'omo.ulw-loop.steer: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
repoRoot,
),
);
expect(out).toContain("accepted");
});
it("processes omo ultragoal steer: pattern", async () => {
it("processes omo ulw-loop steer: pattern", async () => {
const repoRoot = await bootstrapPlanRepo();
const out = await applyUserPromptUltragoalSteering(
const out = await applyUserPromptUlwLoopSteering(
payload(
'omo ultragoal steer: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
'omo ulw-loop steer: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
repoRoot,
),
);
@@ -145,30 +145,30 @@ describe("applyUserPromptUltragoalSteering - OMO directive patterns", () => {
});
});
describe("applyUserPromptUltragoalSteering - non-matching prompts", () => {
describe("applyUserPromptUlwLoopSteering - non-matching prompts", () => {
it("returns empty string when no directive in prompt", async () => {
expect(await applyUserPromptUltragoalSteering(payload("just a normal user message", "/tmp"))).toBe("");
expect(await applyUserPromptUlwLoopSteering(payload("just a normal user message", "/tmp"))).toBe("");
});
it("returns empty for OMX_ULTRAGOAL_STEER (deprecated marker - must reject)", async () => {
it("returns empty for OMX_ULW_LOOP_STEER (deprecated marker - must reject)", async () => {
expect(
await applyUserPromptUltragoalSteering(
payload('OMX_ULTRAGOAL_STEER: {"kind":"annotate_ledger","evidence":"x","rationale":"y"}', "/tmp"),
await applyUserPromptUlwLoopSteering(
payload('OMX_ULW_LOOP_STEER: {"kind":"annotate_ledger","evidence":"x","rationale":"y"}', "/tmp"),
),
).toBe("");
});
it("returns empty when hook_event_name is not UserPromptSubmit", async () => {
expect(await applyUserPromptUltragoalSteering(payloadWithRuntimeEvent("PostToolUse"))).toBe("");
expect(await applyUserPromptUlwLoopSteering(payloadWithRuntimeEvent("PostToolUse"))).toBe("");
});
});
describe("applyUserPromptUltragoalSteering - error swallowing", () => {
describe("applyUserPromptUlwLoopSteering - error swallowing", () => {
it("returns empty (never throws) when plan does not exist", async () => {
const repoRoot = await mkdtemp(join(tmpdir(), "ug-nohook-"));
const out = await applyUserPromptUltragoalSteering(
const out = await applyUserPromptUlwLoopSteering(
payload(
'OMO_ULTRAGOAL_STEER: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
'OMO_ULW_LOOP_STEER: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
repoRoot,
),
);
@@ -176,30 +176,30 @@ describe("applyUserPromptUltragoalSteering - error swallowing", () => {
});
it("returns empty when steering proposal is malformed JSON after marker", async () => {
const out = await applyUserPromptUltragoalSteering(payload("OMO_ULTRAGOAL_STEER: {bad", "/tmp"));
const out = await applyUserPromptUlwLoopSteering(payload("OMO_ULW_LOOP_STEER: {bad", "/tmp"));
expect(out).toBe("");
});
});
describe("runUltragoalHookCli (stdin/stdout integration)", () => {
describe("runUlwLoopHookCli (stdin/stdout integration)", () => {
it("reads stdin, applies steering, writes audit to stdout", async () => {
const repoRoot = await bootstrapPlanRepo();
const stdin = Readable.from([
JSON.stringify(
payload(
'OMO_ULTRAGOAL_STEER: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
'OMO_ULW_LOOP_STEER: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
repoRoot,
),
),
]);
const capture = captureStdout();
await runUltragoalHookCli(stdin, capture.stdout);
await runUlwLoopHookCli(stdin, capture.stdout);
expect(capture.read().length).toBeGreaterThan(0);
});
it("writes nothing when stdin is empty", async () => {
const capture = captureStdout();
await runUltragoalHookCli(Readable.from([""]), capture.stdout);
await runUlwLoopHookCli(Readable.from([""]), capture.stdout);
expect(capture.read()).toBe("");
});
});
@@ -1,12 +1,12 @@
import { describe, expect, it } from "vitest";
import { requireAllCriteriaPass } from "../src/evidence.js";
import type { UltragoalItem, UltragoalSuccessCriterion } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
import type { UlwLoopItem, UlwLoopSuccessCriterion } from "../src/types.js";
import { UlwLoopError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): UltragoalSuccessCriterion {
function makeCriterion(overrides: Partial<UlwLoopSuccessCriterion> = {}): UlwLoopSuccessCriterion {
return {
id: "C001",
scenario: "happy path login returns 200",
@@ -18,7 +18,7 @@ function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): Ultr
};
}
function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function makeGoal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Auth endpoint",
@@ -50,7 +50,7 @@ describe("requireAllCriteriaPass", () => {
expect(() => requireAllCriteriaPass(goal)).not.toThrow();
});
it("throws UltragoalError when any criterion pending", () => {
it("throws UlwLoopError when any criterion pending", () => {
// given
const goal = makeGoal({
successCriteria: [
@@ -61,7 +61,7 @@ describe("requireAllCriteriaPass", () => {
});
// when / then
expect(() => requireAllCriteriaPass(goal)).toThrow(UltragoalError);
expect(() => requireAllCriteriaPass(goal)).toThrow(UlwLoopError);
});
it("throws when any fail/blocked too", () => {
@@ -70,11 +70,11 @@ describe("requireAllCriteriaPass", () => {
const goal2 = makeGoal({ successCriteria: [makeCriterion({ id: "C001", status: "blocked" })] });
// when / then
expect(() => requireAllCriteriaPass(goal1)).toThrow(UltragoalError);
expect(() => requireAllCriteriaPass(goal2)).toThrow(UltragoalError);
expect(() => requireAllCriteriaPass(goal1)).toThrow(UlwLoopError);
expect(() => requireAllCriteriaPass(goal2)).toThrow(UlwLoopError);
});
it("UltragoalError includes details.goalId + details.unresolved", () => {
it("UlwLoopError includes details.goalId + details.unresolved", () => {
// given
const goal = makeGoal({
id: "G001",
@@ -90,9 +90,9 @@ describe("requireAllCriteriaPass", () => {
requireAllCriteriaPass(goal);
expect.fail("expected throw");
} catch (error) {
expect(error).toBeInstanceOf(UltragoalError);
if (!(error instanceof UltragoalError)) throw error;
expect(error.code).toBe("ultragoal_criteria_not_all_pass");
expect(error).toBeInstanceOf(UlwLoopError);
if (!(error instanceof UlwLoopError)) throw error;
expect(error.code).toBe("ulw_loop_criteria_not_all_pass");
expect(error.details?.["goalId"]).toBe("G001");
expect(Array.isArray(error.details?.["unresolved"])).toBe(true);
}
@@ -9,34 +9,34 @@ import {
recordEvidence,
unresolvedCriteriaOf,
} from "../src/evidence.js";
import { ultragoalDir } from "../src/paths.js";
import { readUltragoalPlan, writePlan } from "../src/plan-io.js";
import type { UltragoalItem, UltragoalLedgerEntry, UltragoalPlan, UltragoalSuccessCriterion } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
import { ulwLoopDir } from "../src/paths.js";
import { readUlwLoopPlan, writePlan } from "../src/plan-io.js";
import type { UlwLoopItem, UlwLoopLedgerEntry, UlwLoopPlan, UlwLoopSuccessCriterion } from "../src/types.js";
import { UlwLoopError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
async function bootstrapRepo(plan: UltragoalPlan): Promise<string> {
async function bootstrapRepo(plan: UlwLoopPlan): Promise<string> {
const repo = await mkdtemp(join(tmpdir(), "ug-evidence-"));
await mkdir(ultragoalDir(repo), { recursive: true });
await mkdir(ulwLoopDir(repo), { recursive: true });
await writePlan(repo, plan);
return repo;
}
async function readLastLedgerEntry(repo: string): Promise<UltragoalLedgerEntry> {
const lines = (await readFile(join(repo, ".omo/ultragoal/ledger.jsonl"), "utf8")).trim().split("\n");
async function readLastLedgerEntry(repo: string): Promise<UlwLoopLedgerEntry> {
const lines = (await readFile(join(repo, ".omo/ulw-loop/ledger.jsonl"), "utf8")).trim().split("\n");
const last = lines.at(-1);
if (last === undefined) throw new Error("expected ledger entry");
return JSON.parse(last);
}
function firstGoal(plan: UltragoalPlan): UltragoalItem {
function firstGoal(plan: UlwLoopPlan): UlwLoopItem {
const goal = plan.goals.at(0);
if (goal === undefined) throw new Error("expected goal");
return goal;
}
function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): UltragoalSuccessCriterion {
function makeCriterion(overrides: Partial<UlwLoopSuccessCriterion> = {}): UlwLoopSuccessCriterion {
return {
id: "C001",
scenario: "happy path login returns 200",
@@ -48,7 +48,7 @@ function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): Ultr
};
}
function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function makeGoal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Auth endpoint",
@@ -66,16 +66,16 @@ function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
};
}
function makePlan(overrides: Partial<UltragoalPlan> = {}): UltragoalPlan {
function makePlan(overrides: Partial<UlwLoopPlan> = {}): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
codexGoalMode: "aggregate",
codexObjective: "Complete the durable ultragoal plan in .omo/ultragoal/goals.json",
codexObjective: "Complete the durable ulw-loop plan in .omo/ulw-loop/goals.json",
codexObjectiveAliases: [],
goals: [makeGoal()],
...overrides,
@@ -114,7 +114,7 @@ describe("recordEvidence (status=pass)", () => {
await recordEvidence(repo, { goalId: "G001", criterionId: "C001", status: "pass", evidence: "observable proof" });
const criterion = firstGoal(await readUltragoalPlan(repo)).successCriteria.find((c) => c.id === "C001");
const criterion = firstGoal(await readUlwLoopPlan(repo)).successCriteria.find((c) => c.id === "C001");
expect(criterion?.status).toBe("pass");
});
});
@@ -157,7 +157,7 @@ describe("recordEvidence error cases", () => {
await expect(
recordEvidence(repo, { goalId: "GUNKNOWN", criterionId: "C001", status: "pass", evidence: "x" }),
).rejects.toBeInstanceOf(UltragoalError);
).rejects.toBeInstanceOf(UlwLoopError);
});
it("throws when criterionId not found within goal", async () => {
@@ -165,7 +165,7 @@ describe("recordEvidence error cases", () => {
await expect(
recordEvidence(repo, { goalId: "G001", criterionId: "CUNKNOWN", status: "pass", evidence: "x" }),
).rejects.toBeInstanceOf(UltragoalError);
).rejects.toBeInstanceOf(UlwLoopError);
});
it("throws when evidence is empty/whitespace", async () => {
@@ -173,7 +173,7 @@ describe("recordEvidence error cases", () => {
await expect(
recordEvidence(repo, { goalId: "G001", criterionId: "C001", status: "pass", evidence: " " }),
).rejects.toBeInstanceOf(UltragoalError);
).rejects.toBeInstanceOf(UlwLoopError);
});
});
@@ -0,0 +1 @@
{ "goal": { "objective": "Complete the durable ulw-loop plan", "status": "active" } }
@@ -2,7 +2,7 @@
"version": 1,
"createdAt": "2026-05-23T00:00:00.000Z",
"codexGoalMode": "aggregate",
"codexObjective": "Complete the durable ultragoal plan in .omo/ultragoal/goals.json...",
"codexObjective": "Complete the durable ulw-loop plan in .omo/ulw-loop/goals.json...",
"codexObjectiveAliases": [],
"goals": [
{
@@ -3,7 +3,7 @@
"hook_event_name": "UserPromptSubmit",
"model": "gpt-5.5",
"permission_mode": "default",
"prompt": "OMO_ULTRAGOAL_STEER: {\"kind\":\"annotate_ledger\",\"source\":\"user_prompt_submit\",\"evidence\":\"test note\",\"rationale\":\"testing hook\"}",
"prompt": "OMO_ULW_LOOP_STEER: {\"kind\":\"annotate_ledger\",\"source\":\"user_prompt_submit\",\"evidence\":\"test note\",\"rationale\":\"testing hook\"}",
"session_id": "s1",
"transcript_path": "/tmp/transcript.log",
"turn_id": "t1"
@@ -8,14 +8,14 @@ import {
firstUnresolvedCriterion,
hasAllCriteriaPass,
isFinalRunCompletionCandidate,
isUltragoalDone,
ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE,
isUlwLoopDone,
ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE,
} from "../src/goal-status.js";
import type { UltragoalItem, UltragoalPlan, UltragoalSuccessCriterion } from "../src/types.js";
import type { UlwLoopItem, UlwLoopPlan, UlwLoopSuccessCriterion } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): UltragoalSuccessCriterion {
function makeCriterion(overrides: Partial<UlwLoopSuccessCriterion> = {}): UlwLoopSuccessCriterion {
return {
id: "C001",
scenario: "happy path",
@@ -27,7 +27,7 @@ function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): Ultr
};
}
function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function makeGoal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Goal one",
@@ -41,20 +41,20 @@ function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
};
}
function makePlan(overrides: Partial<UltragoalPlan> = {}): UltragoalPlan {
function makePlan(overrides: Partial<UlwLoopPlan> = {}): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
goals: [],
...overrides,
};
}
describe("isUltragoalDone", () => {
describe("isUlwLoopDone", () => {
it("returns true when all goals complete", () => {
// given
const plan = makePlan({
@@ -62,7 +62,7 @@ describe("isUltragoalDone", () => {
});
// when
const done = isUltragoalDone(plan);
const done = isUlwLoopDone(plan);
// then
expect(done).toBe(true);
@@ -73,7 +73,7 @@ describe("isUltragoalDone", () => {
const plan = makePlan({ goals: [makeGoal({ status: "complete" }), makeGoal({ id: "G002", status: "pending" })] });
// when
const done = isUltragoalDone(plan);
const done = isUlwLoopDone(plan);
// then
expect(done).toBe(false);
@@ -91,7 +91,7 @@ describe("isUltragoalDone", () => {
const plan = makePlan({ goals: [superseded, replacement] });
// when
const done = isUltragoalDone(plan);
const done = isUlwLoopDone(plan);
// then
expect(done).toBe(true);
@@ -155,7 +155,7 @@ describe("expectedCodexObjective", () => {
expect(objective).toBe("aggregate objective");
});
it("aggregate mode falls back to ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE when codexObjective missing", () => {
it("aggregate mode falls back to ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE when codexObjective missing", () => {
// given
const goal = makeGoal({ objective: "story objective" });
const plan = makePlan({ codexGoalMode: "aggregate" });
@@ -164,7 +164,7 @@ describe("expectedCodexObjective", () => {
const objective = expectedCodexObjective(plan, goal);
// then
expect(objective).toBe(ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE);
expect(objective).toBe(ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE);
});
it("per_story mode returns goal.objective", () => {
@@ -189,12 +189,12 @@ describe("aggregateCodexObjective", () => {
expect(objective).toBe("aggregate objective");
});
it("falls back to ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE", () => {
it("falls back to ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE", () => {
// when
const objective = aggregateCodexObjective(makePlan());
// then
expect(objective).toBe(ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE);
expect(objective).toBe(ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE);
});
});
@@ -317,11 +317,11 @@ describe("firstUnresolvedCriterion", () => {
});
});
describe("ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE", () => {
it("references the .omo/ultragoal path and excludes the legacy workspace", () => {
describe("ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE", () => {
it("references the .omo/ulw-loop path and excludes the legacy workspace", () => {
const legacyWorkspace = [".", "om", "x"].join("");
expect(ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE).toContain(".omo/ultragoal");
expect(ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE).not.toContain(legacyWorkspace);
expect(ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE).toContain(".omo/ulw-loop");
expect(ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE).not.toContain(legacyWorkspace);
});
});
@@ -55,7 +55,7 @@ describe("hooks/hooks.json", () => {
expect(command).toContain("hook user-prompt-submit");
});
it("#given ultragoal component is enabled #when hooks are inspected #then create_goal PreToolUse guard is registered", async () => {
it("#given ulw-loop component is enabled #when hooks are inspected #then create_goal PreToolUse guard is registered", async () => {
const text = await readText("hooks/hooks.json");
expect(text).toContain('"PreToolUse"');
@@ -71,67 +71,67 @@ describe("src/cli.ts", () => {
});
});
describe("skills/ultragoal/SKILL.md", () => {
describe("skills/ulw-loop/SKILL.md", () => {
it("exists", async () => {
const info = await stat(join(repoRoot, "skills/ultragoal/SKILL.md"));
const info = await stat(join(repoRoot, "skills/ulw-loop/SKILL.md"));
expect(info.isFile()).toBe(true);
});
it("#given Codex skill hinting #when ultragoal skill metadata is inspected #then ulw-loop is the primary mention name", async () => {
const text = await readText("skills/ultragoal/SKILL.md");
it("#given Codex skill hinting #when ulw-loop skill metadata is inspected #then ulw-loop is the primary mention name", async () => {
const text = await readText("skills/ulw-loop/SKILL.md");
expect(text).toMatch(/^---\nname: ulw-loop\n/m);
expect(text).toContain("Goal-like loop that uses ultrawork mode to decompose work into systematic, evidence-bound steps.");
expect(text).toContain("short-description: Goal-like ultrawork loop for systematic decomposition");
});
it("#given Codex dollar hinting #when querying ulw-loop #then ulw-loop surfaces the ultragoal alias", async () => {
const text = await readText("skills/ultragoal/agents/openai.yaml");
it("#given Codex dollar hinting #when querying ulw-loop #then ulw-loop surfaces the ulw-loop alias", async () => {
const text = await readText("skills/ulw-loop/agents/openai.yaml");
expect(text).toContain('display_name: "ulw loop"');
expect(text).not.toContain("ulw-loop / ultragoal");
expect(text).not.toContain("ulw-loop / ulw-loop");
expect(text).toContain('short_description: "Goal-like ultrawork loop for systematic decomposition"');
expect(text).toContain("Use $ulw-loop");
});
it("#given Codex dollar hinting #when querying ultragoal #then ultragoal remains discoverable as an alias", async () => {
const text = await readText("skills/ultragoal/agents/openai.yaml");
it("#given Codex dollar hinting #when querying ulw-loop #then ulw-loop remains discoverable as an alias", async () => {
const text = await readText("skills/ulw-loop/agents/openai.yaml");
expect(text).toContain("search_terms:");
expect(text).toContain('- "ultragoal"');
expect(text).toContain('- "ulw-loop"');
});
it("contains no omx references", async () => {
const text = await readText("skills/ultragoal/SKILL.md");
const text = await readText("skills/ulw-loop/SKILL.md");
expect(text.toLowerCase()).not.toContain("omx");
});
it("references the success criteria and record-evidence vocabulary", async () => {
const text = await readText("skills/ultragoal/SKILL.md");
const text = await readText("skills/ulw-loop/SKILL.md");
expect(text.toLowerCase()).toMatch(/success criteria|successcriteria/);
expect(text.toLowerCase()).toContain("record-evidence");
});
it("#given omo is absent from PATH #when bootstrap instructions are read #then local cached CLI fallback is documented", async () => {
const text = await readText("skills/ultragoal/SKILL.md");
const text = await readText("skills/ulw-loop/SKILL.md");
expect(text).toContain("If `omo` is absent from PATH");
expect(text).toContain("ULTRAGOAL_CLI");
expect(text).toContain("components/ultragoal/dist/cli.js");
expect(text).toContain("ULW_LOOP_CLI");
expect(text).toContain("components/ulw-loop/dist/cli.js");
});
it("#given empty PATH #when bootstrap instructions are read #then handles empty PATH without losing notepad bootstrap", async () => {
const text = await readText("skills/ultragoal/SKILL.md");
const text = await readText("skills/ulw-loop/SKILL.md");
expect(text).toContain("If PATH is empty");
expect(text).toContain("ULTRAGOAL_NODE");
expect(text).toContain(".omo/ultragoal/bootstrap-notepad.md");
expect(text).toContain("ULW_LOOP_NODE");
expect(text).toContain(".omo/ulw-loop/bootstrap-notepad.md");
expect(text).not.toContain("ls -1");
});
it("uses the .omo workspace path", async () => {
const text = await readText("skills/ultragoal/SKILL.md");
expect(text).toContain(".omo/ultragoal");
const text = await readText("skills/ulw-loop/SKILL.md");
expect(text).toContain(".omo/ulw-loop");
});
});
@@ -0,0 +1,31 @@
import { describe, expect, it } from "vitest";
import { repoRelative, ulwLoopBriefPath, ulwLoopDir, ulwLoopGoalsPath, ulwLoopLedgerPath } from "../src/paths.ts";
describe("ulwLoopDir(repo)", () => {
it("returns repo + '/.omo/ulw-loop'", () => {
// when/then
expect(ulwLoopDir("/repo")).toBe("/repo/.omo/ulw-loop");
});
});
describe("ulw-loop*Path helpers", () => {
it("compose artifact filenames under ulwLoopDir", () => {
// when/then
expect(ulwLoopBriefPath("/r")).toBe("/r/.omo/ulw-loop/brief.md");
expect(ulwLoopGoalsPath("/r")).toBe("/r/.omo/ulw-loop/goals.json");
expect(ulwLoopLedgerPath("/r")).toBe("/r/.omo/ulw-loop/ledger.jsonl");
});
});
describe("repoRelative", () => {
it("strips repo prefix when path is inside repo", () => {
// when/then
expect(repoRelative("/repo/.omo/ulw-loop/goals.json", "/repo")).toBe(".omo/ulw-loop/goals.json");
});
it("returns absolute when path is outside repo", () => {
// when/then
expect(repoRelative("/elsewhere/file", "/repo")).toBe("/elsewhere/file");
});
});
@@ -3,18 +3,18 @@ import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { ultragoalBriefPath, ultragoalGoalsPath, ultragoalLedgerPath } from "../src/paths.js";
import { ulwLoopBriefPath, ulwLoopGoalsPath, ulwLoopLedgerPath } from "../src/paths.js";
import {
addUltragoalGoal,
createUltragoalPlan,
addUlwLoopGoal,
createUlwLoopPlan,
deriveGoalCandidates,
seedDefaultSuccessCriteria,
startNextUltragoal,
summarizeUltragoalPlan,
startNextUlwLoop,
summarizeUlwLoopPlan,
} from "../src/plan-crud.js";
import { writePlan } from "../src/plan-io.js";
import type { UltragoalItem, UltragoalPlan, UltragoalSuccessCriterion } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
import type { UlwLoopItem, UlwLoopPlan, UlwLoopSuccessCriterion } from "../src/types.js";
import { UlwLoopError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
@@ -27,20 +27,20 @@ async function readBriefFixture(): Promise<string> {
}
async function ledgerKinds(repoRoot: string): Promise<string[]> {
const raw = await readFile(ultragoalLedgerPath(repoRoot), "utf8");
const raw = await readFile(ulwLoopLedgerPath(repoRoot), "utf8");
return raw
.split(/\r?\n/)
.filter(Boolean)
.map((line) => JSON.parse(line).kind);
}
function criterion(status: UltragoalSuccessCriterion["status"]): UltragoalSuccessCriterion {
function criterion(status: UlwLoopSuccessCriterion["status"]): UlwLoopSuccessCriterion {
const [base] = seedDefaultSuccessCriteria(0, "Implement auth endpoint");
if (base === undefined) throw new Error("expected seeded criterion");
return { ...base, status };
}
function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function makeGoal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Build auth service",
@@ -54,20 +54,20 @@ function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
};
}
function makePlan(goals: UltragoalItem[]): UltragoalPlan {
function makePlan(goals: UlwLoopItem[]): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
codexGoalMode: "aggregate",
goals,
};
}
function scheduled(result: Awaited<ReturnType<typeof startNextUltragoal>>) {
function scheduled(result: Awaited<ReturnType<typeof startNextUlwLoop>>) {
if ("done" in result) throw new Error("expected scheduled goal");
return result;
}
@@ -93,20 +93,20 @@ describe("seedDefaultSuccessCriteria", () => {
});
});
describe("createUltragoalPlan", () => {
it("creates .omo/ultragoal/{brief.md, goals.json, ledger.jsonl} in repoRoot", async () => {
describe("createUlwLoopPlan", () => {
it("creates .omo/ulw-loop/{brief.md, goals.json, ledger.jsonl} in repoRoot", async () => {
const repoRoot = await makeRepo();
const brief = await readBriefFixture();
await createUltragoalPlan(repoRoot, { brief });
await createUlwLoopPlan(repoRoot, { brief });
expect(await readFile(ultragoalBriefPath(repoRoot), "utf8")).toBe(brief.endsWith("\n") ? brief : `${brief}\n`);
expect(await readFile(ultragoalGoalsPath(repoRoot), "utf8")).toContain("G001-build-the-jwt-auth-endpoint");
expect(await readFile(ulwLoopBriefPath(repoRoot), "utf8")).toBe(brief.endsWith("\n") ? brief : `${brief}\n`);
expect(await readFile(ulwLoopGoalsPath(repoRoot), "utf8")).toContain("G001-build-the-jwt-auth-endpoint");
expect(await ledgerKinds(repoRoot)).toEqual(["plan_created"]);
});
it("seeds at least 3 successCriteria per goal", async () => {
const plan = await createUltragoalPlan(await makeRepo(), { brief: await readBriefFixture() });
const plan = await createUlwLoopPlan(await makeRepo(), { brief: await readBriefFixture() });
expect(plan.goals).toHaveLength(3);
expect(plan.goals.every((goal) => goal.successCriteria.length >= 3)).toBe(true);
@@ -114,17 +114,17 @@ describe("createUltragoalPlan", () => {
it("refuses overwrite of an existing plan without --force", async () => {
const repoRoot = await makeRepo();
await createUltragoalPlan(repoRoot, { brief: "first" });
await createUlwLoopPlan(repoRoot, { brief: "first" });
await expect(createUltragoalPlan(repoRoot, { brief: "second" })).rejects.toThrow(UltragoalError);
await expect(createUltragoalPlan(repoRoot, { brief: "second" })).rejects.toThrow("Refusing to overwrite");
await expect(createUlwLoopPlan(repoRoot, { brief: "second" })).rejects.toThrow(UlwLoopError);
await expect(createUlwLoopPlan(repoRoot, { brief: "second" })).rejects.toThrow("Refusing to overwrite");
});
it("aggregate is the default codexGoalMode", async () => {
const plan = await createUltragoalPlan(await makeRepo(), { brief: "Ship the feature" });
const plan = await createUlwLoopPlan(await makeRepo(), { brief: "Ship the feature" });
expect(plan.codexGoalMode).toBe("aggregate");
expect(plan.codexObjective).toContain(".omo/ultragoal/goals.json");
expect(plan.codexObjective).toContain(".omo/ulw-loop/goals.json");
});
});
@@ -150,12 +150,12 @@ describe("deriveGoalCandidates", () => {
});
});
describe("addUltragoalGoal", () => {
describe("addUlwLoopGoal", () => {
it("appends a new goal to plan with seeded successCriteria", async () => {
const repoRoot = await makeRepo();
await createUltragoalPlan(repoRoot, { brief: "Build auth" });
await createUlwLoopPlan(repoRoot, { brief: "Build auth" });
const { plan, goal } = await addUltragoalGoal(repoRoot, { title: "Add rate limit", objective: "Throttle login" });
const { plan, goal } = await addUlwLoopGoal(repoRoot, { title: "Add rate limit", objective: "Throttle login" });
expect(plan.goals).toHaveLength(2);
expect(goal.id).toBe("G002-add-rate-limit");
@@ -164,20 +164,20 @@ describe("addUltragoalGoal", () => {
it("appends a ledger entry for goal_added", async () => {
const repoRoot = await makeRepo();
await createUltragoalPlan(repoRoot, { brief: "Build auth" });
await createUlwLoopPlan(repoRoot, { brief: "Build auth" });
await addUltragoalGoal(repoRoot, { title: "Add rate limit", objective: "Throttle login" });
await addUlwLoopGoal(repoRoot, { title: "Add rate limit", objective: "Throttle login" });
expect(await ledgerKinds(repoRoot)).toEqual(["plan_created", "goal_added"]);
});
});
describe("startNextUltragoal", () => {
describe("startNextUlwLoop", () => {
it("picks the first pending goal", async () => {
const repoRoot = await makeRepo();
await createUltragoalPlan(repoRoot, { brief: "- First\n- Second" });
await createUlwLoopPlan(repoRoot, { brief: "- First\n- Second" });
const result = scheduled(await startNextUltragoal(repoRoot, {}));
const result = scheduled(await startNextUlwLoop(repoRoot, {}));
expect(result.goal.id).toBe("G001-first");
expect(result.goal.status).toBe("in_progress");
@@ -186,11 +186,11 @@ describe("startNextUltragoal", () => {
it("resumes the in_progress goal when one exists", async () => {
const repoRoot = await makeRepo();
const plan = await createUltragoalPlan(repoRoot, { brief: "- First\n- Second" });
const plan = await createUlwLoopPlan(repoRoot, { brief: "- First\n- Second" });
const active = makeGoal({ ...plan.goals[1], status: "in_progress" });
await writePlan(repoRoot, { ...plan, goals: [makeGoal({ ...plan.goals[0] }), active], activeGoalId: active.id });
const result = scheduled(await startNextUltragoal(repoRoot, {}));
const result = scheduled(await startNextUlwLoop(repoRoot, {}));
expect(result.goal.id).toBe(active.id);
expect(result.resumed).toBe(true);
@@ -199,10 +199,10 @@ describe("startNextUltragoal", () => {
it("with retryFailed picks first failed (non-blocked) goal", async () => {
const repoRoot = await makeRepo();
const failed = makeGoal({ status: "failed", failureReason: "flake" });
await mkdir(join(repoRoot, ".omo", "ultragoal"), { recursive: true });
await mkdir(join(repoRoot, ".omo", "ulw-loop"), { recursive: true });
await writePlan(repoRoot, makePlan([failed]));
const result = scheduled(await startNextUltragoal(repoRoot, { retryFailed: true }));
const result = scheduled(await startNextUlwLoop(repoRoot, { retryFailed: true }));
expect(result.goal.id).toBe("G001");
expect(result.goal.attempt).toBe(1);
@@ -211,16 +211,16 @@ describe("startNextUltragoal", () => {
it("returns { done: true } when no eligible goals remain", async () => {
const repoRoot = await makeRepo();
await mkdir(join(repoRoot, ".omo", "ultragoal"), { recursive: true });
await mkdir(join(repoRoot, ".omo", "ulw-loop"), { recursive: true });
await writePlan(repoRoot, makePlan([makeGoal({ status: "complete" })]));
const result = await startNextUltragoal(repoRoot, {});
const result = await startNextUlwLoop(repoRoot, {});
expect(result).toMatchObject({ done: true });
});
});
describe("summarizeUltragoalPlan", () => {
describe("summarizeUlwLoopPlan", () => {
it("counts goals by status", () => {
const plan = makePlan([
makeGoal({ id: "G001", status: "pending" }),
@@ -232,7 +232,7 @@ describe("summarizeUltragoalPlan", () => {
makeGoal({ id: "G007", status: "needs_user_decision", steeringStatus: "superseded" }),
]);
expect(summarizeUltragoalPlan(plan)).toMatchObject({
expect(summarizeUlwLoopPlan(plan)).toMatchObject({
total: 7,
pending: 1,
in_progress: 1,
@@ -251,6 +251,6 @@ describe("summarizeUltragoalPlan", () => {
makeGoal({ id: "G002", successCriteria: [criterion("fail"), criterion("blocked"), criterion("pending")] }),
]);
expect(summarizeUltragoalPlan(plan).criteria).toEqual({ total: 5, pass: 1, pending: 2, fail: 1, blocked: 1 });
expect(summarizeUlwLoopPlan(plan).criteria).toEqual({ total: 5, pass: 1, pending: 2, fail: 1, blocked: 1 });
});
});
@@ -2,22 +2,22 @@ import { copyFile, mkdir, mkdtemp, readdir, readFile, writeFile } from "node:fs/
import { tmpdir } from "node:os";
import { join } from "node:path";
import { beforeEach, describe, expect, it } from "vitest";
import { ultragoalDir, ultragoalGoalsPath, ultragoalLedgerPath } from "../src/paths.js";
import { ulwLoopDir, ulwLoopGoalsPath, ulwLoopLedgerPath } from "../src/paths.js";
import {
appendLedger,
readSteeringLedgerEntries,
readUltragoalPlan,
withUltragoalMutationLock,
readUlwLoopPlan,
withUlwLoopMutationLock,
writePlan,
} from "../src/plan-io.js";
import type { UltragoalItem, UltragoalLedgerEntry, UltragoalPlan } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
import type { UlwLoopItem, UlwLoopLedgerEntry, UlwLoopPlan } from "../src/types.js";
import { UlwLoopError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
const STABLE_OBJECTIVE =
"Complete the durable ultragoal plan in .omo/ultragoal/goals.json, including later accepted/appended stories, under the original brief constraints; use .omo/ultragoal/ledger.jsonl as the audit trail.";
"Complete the durable ulw-loop plan in .omo/ulw-loop/goals.json, including later accepted/appended stories, under the original brief constraints; use .omo/ulw-loop/ledger.jsonl as the audit trail.";
function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function makeGoal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Build auth service",
@@ -31,14 +31,14 @@ function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
};
}
function makePlan(overrides: Partial<UltragoalPlan> = {}): UltragoalPlan {
function makePlan(overrides: Partial<UlwLoopPlan> = {}): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
codexGoalMode: "aggregate",
codexObjective: STABLE_OBJECTIVE,
codexObjectiveAliases: [],
@@ -47,7 +47,7 @@ function makePlan(overrides: Partial<UltragoalPlan> = {}): UltragoalPlan {
};
}
function entry(kind: UltragoalLedgerEntry["kind"], goalId = "G001"): UltragoalLedgerEntry {
function entry(kind: UlwLoopLedgerEntry["kind"], goalId = "G001"): UlwLoopLedgerEntry {
return { at: NOW, kind, goalId };
}
@@ -55,17 +55,17 @@ async function makeRepo(): Promise<string> {
return mkdtemp(join(tmpdir(), "ug-io-"));
}
async function writeRawPlan(repoRoot: string, plan: UltragoalPlan): Promise<void> {
await mkdir(ultragoalDir(repoRoot), { recursive: true });
await writeFile(ultragoalGoalsPath(repoRoot), `${JSON.stringify(plan, null, 2)}\n`, "utf8");
async function writeRawPlan(repoRoot: string, plan: UlwLoopPlan): Promise<void> {
await mkdir(ulwLoopDir(repoRoot), { recursive: true });
await writeFile(ulwLoopGoalsPath(repoRoot), `${JSON.stringify(plan, null, 2)}\n`, "utf8");
}
async function readLedgerLines(repoRoot: string): Promise<string[]> {
const raw = await readFile(ultragoalLedgerPath(repoRoot), "utf8");
const raw = await readFile(ulwLoopLedgerPath(repoRoot), "utf8");
return raw.split(/\r?\n/).filter(Boolean);
}
describe("readUltragoalPlan", () => {
describe("readUlwLoopPlan", () => {
let repoRoot = "";
beforeEach(async () => {
@@ -73,19 +73,19 @@ describe("readUltragoalPlan", () => {
repoRoot = await makeRepo();
});
it("throws UltragoalError when goals.json is missing", async () => {
it("throws UlwLoopError when goals.json is missing", async () => {
// when/then
await expect(readUltragoalPlan(repoRoot)).rejects.toThrow(UltragoalError);
await expect(readUltragoalPlan(repoRoot)).rejects.toThrow("omo ultragoal create-goals");
await expect(readUlwLoopPlan(repoRoot)).rejects.toThrow(UlwLoopError);
await expect(readUlwLoopPlan(repoRoot)).rejects.toThrow("omo ulw-loop create-goals");
});
it("returns parsed plan when fixture is present", async () => {
// given
await mkdir(ultragoalDir(repoRoot), { recursive: true });
await copyFile(join(process.cwd(), "test", "fixtures", "sample-plan.json"), ultragoalGoalsPath(repoRoot));
await mkdir(ulwLoopDir(repoRoot), { recursive: true });
await copyFile(join(process.cwd(), "test", "fixtures", "sample-plan.json"), ulwLoopGoalsPath(repoRoot));
// when
const plan = await readUltragoalPlan(repoRoot);
const plan = await readUlwLoopPlan(repoRoot);
// then
expect(plan.version).toBe(1);
@@ -96,16 +96,16 @@ describe("readUltragoalPlan", () => {
it("migrates legacy aggregate objective on read + writes aggregate_objective_migrated ledger entry + retains alias", async () => {
// given
const legacyObjective = "Complete all ultragoal stories in .omo/ultragoal/goals.json: G001 Build auth service";
const legacyObjective = "Complete all ulw-loop stories in .omo/ulw-loop/goals.json: G001 Build auth service";
await writeRawPlan(repoRoot, makePlan({ codexObjective: legacyObjective }));
// when
const plan = await readUltragoalPlan(repoRoot);
const plan = await readUlwLoopPlan(repoRoot);
// then
expect(plan.codexObjective).toBe(STABLE_OBJECTIVE);
expect(plan.codexObjectiveAliases).toContain(legacyObjective);
const persisted = JSON.parse(await readFile(ultragoalGoalsPath(repoRoot), "utf8"));
const persisted = JSON.parse(await readFile(ulwLoopGoalsPath(repoRoot), "utf8"));
expect(persisted).toMatchObject({ codexObjective: STABLE_OBJECTIVE, codexObjectiveAliases: [legacyObjective] });
const lines = await readLedgerLines(repoRoot);
expect(lines).toHaveLength(1);
@@ -125,9 +125,9 @@ describe("writePlan", () => {
await writePlan(repoRoot, makePlan());
// then
const raw = await readFile(ultragoalGoalsPath(repoRoot), "utf8");
const raw = await readFile(ulwLoopGoalsPath(repoRoot), "utf8");
expect(JSON.parse(raw)).toMatchObject({ version: 1, goals: [{ id: "G001" }] });
expect((await readdir(ultragoalDir(repoRoot))).filter((name) => name.endsWith(".tmp"))).toEqual([]);
expect((await readdir(ulwLoopDir(repoRoot))).filter((name) => name.endsWith(".tmp"))).toEqual([]);
});
it("overwrites existing file", async () => {
@@ -139,7 +139,7 @@ describe("writePlan", () => {
await writePlan(repoRoot, makePlan({ codexObjective: "second" }));
// then
expect(JSON.parse(await readFile(ultragoalGoalsPath(repoRoot), "utf8"))).toMatchObject({
expect(JSON.parse(await readFile(ulwLoopGoalsPath(repoRoot), "utf8"))).toMatchObject({
codexObjective: "second",
});
});
@@ -166,7 +166,7 @@ describe("appendLedger", () => {
await appendLedger(repoRoot, entry("goal_completed"));
// then
expect(await readFile(ultragoalLedgerPath(repoRoot), "utf8")).toContain("goal_completed");
expect(await readFile(ulwLoopLedgerPath(repoRoot), "utf8")).toContain("goal_completed");
});
it("preserves prior entries", async () => {
@@ -209,7 +209,7 @@ describe("readSteeringLedgerEntries", () => {
});
});
describe("withUltragoalMutationLock", () => {
describe("withUlwLoopMutationLock", () => {
it("serializes concurrent invocations", async () => {
// given
const repoRoot = await makeRepo();
@@ -221,7 +221,7 @@ describe("withUltragoalMutationLock", () => {
// when
await Promise.all(
[1, 2, 3].map((_) =>
withUltragoalMutationLock(repoRoot, async () => {
withUlwLoopMutationLock(repoRoot, async () => {
active += 1;
maxActive = Math.max(maxActive, active);
const current = Number(await readFile(counterPath, "utf8"));
@@ -9,8 +9,8 @@ import {
sameBlockerOccurrences,
validateQualityGate,
} from "../src/quality-gate.js";
import type { UltragoalItem, UltragoalPlan } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
import type { UlwLoopItem, UlwLoopPlan } from "../src/types.js";
import { UlwLoopError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
const VALID_GATE = {
@@ -20,7 +20,7 @@ const VALID_GATE = {
criteriaCoverage: { totalCriteria: 2, passCount: 2, adversarialClassesCovered: ["malformed_input"] },
} as const;
interface GoalWithBlocker extends UltragoalItem {
interface GoalWithBlocker extends UlwLoopItem {
blocker?: { readonly signature: string };
blockerEvidence?: string;
blockerOccurrences?: number;
@@ -31,17 +31,17 @@ function makeGate(overrides: Record<string, unknown> = {}): Record<string, unkno
return { ...VALID_GATE, ...overrides };
}
function getQualityGateError(input: unknown): UltragoalError {
function getQualityGateError(input: unknown): UlwLoopError {
try {
validateQualityGate(input);
} catch (error) {
if (error instanceof UltragoalError) return error;
if (error instanceof UlwLoopError) return error;
throw error;
}
throw new Error("Expected UltragoalError");
throw new Error("Expected UlwLoopError");
}
function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function makeGoal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Goal one",
@@ -55,14 +55,14 @@ function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
};
}
function makePlan(goals: UltragoalItem[]): UltragoalPlan {
function makePlan(goals: UlwLoopItem[]): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
goals,
};
}
@@ -81,39 +81,39 @@ describe("validateQualityGate", () => {
expect(gate).toMatchObject({ criteriaCoverage: { totalCriteria: 9, passCount: 9 } });
});
it("throws UltragoalError when aiSlopCleaner missing", () => {
it("throws UlwLoopError when aiSlopCleaner missing", () => {
// when
const error = getQualityGateError(makeGate({ aiSlopCleaner: undefined }));
// then
expect(error.code).toBe("ULTRAGOAL_QUALITY_GATE_INVALID");
expect(error.code).toBe("ULW_LOOP_QUALITY_GATE_INVALID");
});
it("throws UltragoalError when verification missing", () => {
it("throws UlwLoopError when verification missing", () => {
// when
const error = getQualityGateError(makeGate({ verification: undefined }));
// then
expect(error.code).toBe("ULTRAGOAL_QUALITY_GATE_INVALID");
expect(error.code).toBe("ULW_LOOP_QUALITY_GATE_INVALID");
});
it("throws UltragoalError when codeReview missing", () => {
it("throws UlwLoopError when codeReview missing", () => {
// when
const error = getQualityGateError(makeGate({ codeReview: undefined }));
// then
expect(error.code).toBe("ULTRAGOAL_QUALITY_GATE_INVALID");
expect(error.code).toBe("ULW_LOOP_QUALITY_GATE_INVALID");
});
it("throws UltragoalError when criteriaCoverage missing (NEW)", () => {
it("throws UlwLoopError when criteriaCoverage missing (NEW)", () => {
// when
const error = getQualityGateError(makeGate({ criteriaCoverage: undefined }));
// then
expect(error.code).toBe("ULTRAGOAL_QUALITY_GATE_INVALID");
expect(error.code).toBe("ULW_LOOP_QUALITY_GATE_INVALID");
});
it("throws UltragoalError when criteriaCoverage.passCount < totalCriteria (NEW)", () => {
it("throws UlwLoopError when criteriaCoverage.passCount < totalCriteria (NEW)", () => {
// when
const error = getQualityGateError(
makeGate({ criteriaCoverage: { totalCriteria: 3, passCount: 2, adversarialClassesCovered: [] } }),
@@ -123,7 +123,7 @@ describe("validateQualityGate", () => {
expect(error.message).toContain("criteriaCoverage.passCount");
});
it("throws UltragoalError when codeReview.recommendation is not APPROVE", () => {
it("throws UlwLoopError when codeReview.recommendation is not APPROVE", () => {
// when
const error = getQualityGateError(
makeGate({ codeReview: { ...VALID_GATE.codeReview, recommendation: "COMMENT" } }),
@@ -133,7 +133,7 @@ describe("validateQualityGate", () => {
expect(error.message).toContain("recommendation");
});
it("throws UltragoalError when architectStatus is not CLEAR", () => {
it("throws UlwLoopError when architectStatus is not CLEAR", () => {
// when
const error = getQualityGateError(
makeGate({ codeReview: { ...VALID_GATE.codeReview, architectStatus: "WATCH" } }),
@@ -3,16 +3,16 @@ import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE } from "../src/goal-status.js";
import { ultragoalDir, ultragoalLedgerPath } from "../src/paths.js";
import { ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE } from "../src/goal-status.js";
import { ulwLoopDir, ulwLoopLedgerPath } from "../src/paths.js";
import { writePlan } from "../src/plan-io.js";
import { recordFinalReviewBlockers } from "../src/review-blockers.js";
import type { UltragoalItem, UltragoalPlan, UltragoalSuccessCriterion } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
import type { UlwLoopItem, UlwLoopPlan, UlwLoopSuccessCriterion } from "../src/types.js";
import { UlwLoopError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
const VALID_SNAPSHOT_JSON = JSON.stringify({
goal: { objective: ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE, status: "active" },
goal: { objective: ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE, status: "active" },
});
const validArgs = {
@@ -23,7 +23,7 @@ const validArgs = {
codexGoalJson: VALID_SNAPSHOT_JSON,
};
function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): UltragoalSuccessCriterion {
function makeCriterion(overrides: Partial<UlwLoopSuccessCriterion> = {}): UlwLoopSuccessCriterion {
return {
id: "C001",
scenario: "happy path",
@@ -35,11 +35,11 @@ function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): Ultr
};
}
function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function makeGoal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Build durable plan",
objective: "Complete one ultragoal story",
objective: "Complete one ulw-loop story",
status: "pending",
successCriteria: [makeCriterion()],
attempt: 1,
@@ -49,49 +49,49 @@ function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
};
}
function makePlan(overrides: Partial<UltragoalPlan> = {}): UltragoalPlan {
function makePlan(overrides: Partial<UlwLoopPlan> = {}): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
codexGoalMode: "aggregate",
codexObjective: ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE,
codexObjective: ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE,
goals: [makeGoal({ status: "in_progress" })],
...overrides,
};
}
async function bootstrapRepo(plan: UltragoalPlan): Promise<string> {
async function bootstrapRepo(plan: UlwLoopPlan): Promise<string> {
const repo = await mkdtemp(join(tmpdir(), "ug-review-blockers-"));
await mkdir(ultragoalDir(repo), { recursive: true });
await mkdir(ulwLoopDir(repo), { recursive: true });
await writePlan(repo, plan);
return repo;
}
async function ledgerKinds(repo: string): Promise<string[]> {
const raw = await readFile(ultragoalLedgerPath(repo), "utf8");
const raw = await readFile(ulwLoopLedgerPath(repo), "utf8");
return raw
.split(/\r?\n/)
.filter(Boolean)
.map((line) => JSON.parse(line).kind);
}
async function expectUltragoalCode(action: () => Promise<unknown>, code: string): Promise<void> {
async function expectUlwLoopCode(action: () => Promise<unknown>, code: string): Promise<void> {
try {
await action();
} catch (error) {
expect(error).toBeInstanceOf(UltragoalError);
if (!(error instanceof UltragoalError)) throw error;
expect(error).toBeInstanceOf(UlwLoopError);
if (!(error instanceof UlwLoopError)) throw error;
expect(error.code).toBe(code);
return;
}
throw new Error("Expected UltragoalError");
throw new Error("Expected UlwLoopError");
}
function finalPlan(): UltragoalPlan {
function finalPlan(): UlwLoopPlan {
return makePlan({
activeGoalId: "G002",
goals: [
@@ -129,42 +129,42 @@ describe("recordFinalReviewBlockers happy path", () => {
});
describe("recordFinalReviewBlockers error cases", () => {
it("throws ultragoal_goal_not_found for unknown goalId", async () => {
it("throws ulw_loop_goal_not_found for unknown goalId", async () => {
const repo = await bootstrapRepo(finalPlan());
await expectUltragoalCode(
await expectUlwLoopCode(
() => recordFinalReviewBlockers(repo, { ...validArgs, goalId: "G999" }),
"ultragoal_goal_not_found",
"ulw_loop_goal_not_found",
);
});
it("throws ultragoal_goal_not_in_progress when goal.status !== in_progress", async () => {
it("throws ulw_loop_goal_not_in_progress when goal.status !== in_progress", async () => {
const repo = await bootstrapRepo(
makePlan({
goals: [makeGoal({ id: "G001", status: "in_progress" }), makeGoal({ id: "G002", status: "pending" })],
}),
);
await expectUltragoalCode(() => recordFinalReviewBlockers(repo, validArgs), "ultragoal_goal_not_in_progress");
await expectUlwLoopCode(() => recordFinalReviewBlockers(repo, validArgs), "ulw_loop_goal_not_in_progress");
});
it("throws ultragoal_not_final_story when other unresolved goals remain", async () => {
it("throws ulw_loop_not_final_story when other unresolved goals remain", async () => {
const repo = await bootstrapRepo(
makePlan({
goals: [makeGoal({ id: "G001", status: "in_progress" }), makeGoal({ id: "G002", status: "pending" })],
}),
);
await expectUltragoalCode(
await expectUlwLoopCode(
() => recordFinalReviewBlockers(repo, { ...validArgs, goalId: "G001" }),
"ultragoal_not_final_story",
"ulw_loop_not_final_story",
);
});
it("throws ultragoal_codex_snapshot_mismatch when objective mismatches", async () => {
it("throws ulw_loop_codex_snapshot_mismatch when objective mismatches", async () => {
const repo = await bootstrapRepo(finalPlan());
const codexGoalJson = JSON.stringify({ goal: { objective: "wrong", status: "active" } });
await expectUltragoalCode(
await expectUlwLoopCode(
() => recordFinalReviewBlockers(repo, { ...validArgs, codexGoalJson }),
"ultragoal_codex_snapshot_mismatch",
"ulw_loop_codex_snapshot_mismatch",
);
});
});
@@ -2,20 +2,20 @@ import { mkdtemp, readFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { ultragoalGoalsPath } from "../src/paths.js";
import { readSteeringLedgerEntries, readUltragoalPlan, writePlan } from "../src/plan-io.js";
import { ulwLoopGoalsPath } from "../src/paths.js";
import { readSteeringLedgerEntries, readUlwLoopPlan, writePlan } from "../src/plan-io.js";
import {
applySteeringMutation,
parseUltragoalSteeringDirective,
steerUltragoal,
validateUltragoalSteeringProposal,
parseUlwLoopSteeringDirective,
steerUlwLoop,
validateUlwLoopSteeringProposal,
} from "../src/steering.js";
import type {
UltragoalItem,
UltragoalPlan,
UltragoalSteeringProposal,
UltragoalSuccessCriterion,
UltragoalSuccessCriterionUserModel,
UlwLoopItem,
UlwLoopPlan,
UlwLoopSteeringProposal,
UlwLoopSuccessCriterion,
UlwLoopSuccessCriterionUserModel,
} from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
@@ -24,11 +24,11 @@ type CriterionSteeringFields = {
readonly goalId?: string;
readonly scenario?: string;
readonly expectedEvidence?: string;
readonly userModel?: UltragoalSuccessCriterionUserModel;
readonly userModel?: UlwLoopSuccessCriterionUserModel;
};
type SteeringInput = UltragoalSteeringProposal & CriterionSteeringFields;
type SteeringInput = UlwLoopSteeringProposal & CriterionSteeringFields;
function criterion(overrides: Partial<UltragoalSuccessCriterion> = {}): UltragoalSuccessCriterion {
function criterion(overrides: Partial<UlwLoopSuccessCriterion> = {}): UlwLoopSuccessCriterion {
return {
id: "C001",
scenario: "old scenario",
@@ -40,7 +40,7 @@ function criterion(overrides: Partial<UltragoalSuccessCriterion> = {}): Ultragoa
};
}
function goal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
function goal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
return {
id: "G001",
title: "Build auth service",
@@ -54,14 +54,14 @@ function goal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
};
}
function plan(overrides: Partial<UltragoalPlan> = {}): UltragoalPlan {
function plan(overrides: Partial<UlwLoopPlan> = {}): UlwLoopPlan {
return {
version: 1,
createdAt: NOW,
updatedAt: NOW,
briefPath: ".omo/ultragoal/brief.md",
goalsPath: ".omo/ultragoal/goals.json",
ledgerPath: ".omo/ultragoal/ledger.jsonl",
briefPath: ".omo/ulw-loop/brief.md",
goalsPath: ".omo/ulw-loop/goals.json",
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
goals: [
goal(),
goal({ id: "G002", title: "Rate limit", objective: "Throttle login" }),
@@ -83,18 +83,18 @@ function steering(overrides: Partial<SteeringInput> = {}): SteeringInput {
};
}
async function repoWithPlan(seed: UltragoalPlan = plan()): Promise<string> {
async function repoWithPlan(seed: UlwLoopPlan = plan()): Promise<string> {
const repoRoot = await mkdtemp(join(tmpdir(), "ug-steer-"));
await writePlan(repoRoot, seed);
return repoRoot;
}
describe("validateUltragoalSteeringProposal", () => {
describe("validateUlwLoopSteeringProposal", () => {
it("accepts valid add_subgoal", async () => {
const proposal: unknown = JSON.parse(
await readFile(join(process.cwd(), "test/fixtures/steering-proposal.json"), "utf8"),
);
expect(validateUltragoalSteeringProposal(plan(), proposal).invariant.accepted).toBe(true);
expect(validateUlwLoopSteeringProposal(plan(), proposal).invariant.accepted).toBe(true);
});
it.each([
@@ -104,26 +104,23 @@ describe("validateUltragoalSteeringProposal", () => {
["protected payload mutations", { after: { codexObjective: "replace", qualityGate: { status: "passed" } } }],
["weakened completion text", { objective: "skip tests and mark complete faster" }],
])("rejects %s", (_name, overrides) => {
const audit = validateUltragoalSteeringProposal(plan(), { ...steering(), ...overrides });
const audit = validateUlwLoopSteeringProposal(plan(), { ...steering(), ...overrides });
expect(audit.invariant.accepted).toBe(false);
expect(audit.invariant.rejectedReasons.length).toBeGreaterThan(0);
});
it("rejects when plan already complete", () => {
const done = plan({ goals: [goal({ status: "complete" }), goal({ id: "G002", status: "complete" })] });
expect(validateUltragoalSteeringProposal(done, steering()).invariant.accepted).toBe(false);
expect(validateUlwLoopSteeringProposal(done, steering()).invariant.accepted).toBe(false);
});
it("rejects split_subgoal without children", () => {
const audit = validateUltragoalSteeringProposal(
plan(),
steering({ kind: "split_subgoal", targetGoalId: "G001" }),
);
const audit = validateUlwLoopSteeringProposal(plan(), steering({ kind: "split_subgoal", targetGoalId: "G001" }));
expect(audit.invariant.accepted).toBe(false);
});
it("rejects reorder_pending with unknown goal id", () => {
const audit = validateUltragoalSteeringProposal(
const audit = validateUlwLoopSteeringProposal(
plan(),
steering({ kind: "reorder_pending", pendingOrder: ["missing"] }),
);
@@ -134,7 +131,7 @@ describe("validateUltragoalSteeringProposal", () => {
["new scenario", { scenario: "new precise scenario" }],
["new expectedEvidence", { expectedEvidence: "specific command output" }],
])("accepts valid revise_criterion with %s", (_name, update) => {
const audit = validateUltragoalSteeringProposal(
const audit = validateUlwLoopSteeringProposal(
plan(),
steering({ kind: "revise_criterion", goalId: "G001", criterionId: "C001", ...update }),
);
@@ -146,16 +143,16 @@ describe("validateUltragoalSteeringProposal", () => {
["unknown criterionId", { goalId: "G001", criterionId: "missing", scenario: "new" }],
["no updates", { goalId: "G001", criterionId: "C001" }],
])("rejects revise_criterion with %s", (_name, overrides) => {
const audit = validateUltragoalSteeringProposal(plan(), steering({ kind: "revise_criterion", ...overrides }));
const audit = validateUlwLoopSteeringProposal(plan(), steering({ kind: "revise_criterion", ...overrides }));
expect(audit.invariant.accepted).toBe(false);
});
});
describe("steerUltragoal", () => {
describe("steerUlwLoop", () => {
it("add_subgoal: appends goal + ledger entry", async () => {
const repoRoot = await repoWithPlan();
const result = await steerUltragoal(repoRoot, steering({ idempotencyKey: "add" }));
const persisted = await readUltragoalPlan(repoRoot);
const result = await steerUlwLoop(repoRoot, steering({ idempotencyKey: "add" }));
const persisted = await readUlwLoopPlan(repoRoot);
expect(result.accepted).toBe(true);
expect(persisted.goals.at(-1)).toMatchObject({ id: "G004", title: "Investigate auth blocker" });
expect((await readSteeringLedgerEntries(repoRoot)).at(-1)).toMatchObject({
@@ -166,7 +163,7 @@ describe("steerUltragoal", () => {
it("split_subgoal: creates children + supersedes parent", async () => {
const repoRoot = await repoWithPlan();
const result = await steerUltragoal(
const result = await steerUlwLoop(
repoRoot,
steering({
kind: "split_subgoal",
@@ -180,7 +177,7 @@ describe("steerUltragoal", () => {
it("reorder_pending: changes goal order", async () => {
const repoRoot = await repoWithPlan();
const result = await steerUltragoal(
const result = await steerUlwLoop(
repoRoot,
steering({ kind: "reorder_pending", pendingOrder: ["G002", "G001"] }),
);
@@ -189,7 +186,7 @@ describe("steerUltragoal", () => {
it("revise_pending_wording: updates title/objective", async () => {
const repoRoot = await repoWithPlan();
const result = await steerUltragoal(
const result = await steerUlwLoop(
repoRoot,
steering({
kind: "revise_pending_wording",
@@ -207,14 +204,14 @@ describe("steerUltragoal", () => {
it("annotate_ledger: ledger-only, no plan mutation", async () => {
const seed = plan();
const repoRoot = await repoWithPlan(seed);
const result = await steerUltragoal(repoRoot, steering({ kind: "annotate_ledger" }));
const result = await steerUlwLoop(repoRoot, steering({ kind: "annotate_ledger" }));
expect(result.plan.goals).toEqual(seed.goals);
expect(await readFile(ultragoalGoalsPath(repoRoot), "utf8")).toBe(`${JSON.stringify(seed, null, 2)}\n`);
expect(await readFile(ulwLoopGoalsPath(repoRoot), "utf8")).toBe(`${JSON.stringify(seed, null, 2)}\n`);
});
it("mark_blocked_superseded with children: supersede + replace", async () => {
const repoRoot = await repoWithPlan();
const result = await steerUltragoal(
const result = await steerUlwLoop(
repoRoot,
steering({
kind: "mark_blocked_superseded",
@@ -228,7 +225,7 @@ describe("steerUltragoal", () => {
it("mark_blocked_superseded without children: blocks goal", async () => {
const repoRoot = await repoWithPlan();
const result = await steerUltragoal(
const result = await steerUlwLoop(
repoRoot,
steering({ kind: "mark_blocked_superseded", targetGoalId: "G001", blockedReason: "external blocker" }),
);
@@ -242,7 +239,7 @@ describe("steerUltragoal", () => {
it.each(["pending", "pass"] as const)("revise_criterion: works on a %s criterion", async (status) => {
const repoRoot = await repoWithPlan();
const criterionId = status === "pending" ? "C001" : "C002";
const result = await steerUltragoal(
const result = await steerUlwLoop(
repoRoot,
steering({
kind: "revise_criterion",
@@ -261,7 +258,7 @@ describe("steerUltragoal", () => {
});
it("revise_criterion: updates the targeted criterion in plan", () => {
const audit = validateUltragoalSteeringProposal(
const audit = validateUlwLoopSteeringProposal(
plan(),
steering({ kind: "revise_criterion", goalId: "G001", criterionId: "C001", scenario: "new value" }),
);
@@ -275,30 +272,30 @@ describe("steerUltragoal", () => {
it("idempotency: same idempotencyKey produces deduped true second time", async () => {
const repoRoot = await repoWithPlan();
await steerUltragoal(repoRoot, steering({ idempotencyKey: "same-key" }));
const second = await steerUltragoal(repoRoot, steering({ idempotencyKey: "same-key" }));
await steerUlwLoop(repoRoot, steering({ idempotencyKey: "same-key" }));
const second = await steerUlwLoop(repoRoot, steering({ idempotencyKey: "same-key" }));
expect(second.deduped).toBe(true);
expect((await readUltragoalPlan(repoRoot)).goals).toHaveLength(4);
expect((await readUlwLoopPlan(repoRoot)).goals).toHaveLength(4);
});
});
describe("parseUltragoalSteeringDirective", () => {
it.each(["OMO_ULTRAGOAL_STEER", "omo.ultragoal.steer", "omo ultragoal steer"])("parses %s pattern", (marker) => {
expect(parseUltragoalSteeringDirective(`${marker}: ${JSON.stringify(steering())}`)).toMatchObject({
describe("parseUlwLoopSteeringDirective", () => {
it.each(["OMO_ULW_LOOP_STEER", "omo.ulw-loop.steer", "omo ulw-loop steer"])("parses %s pattern", (marker) => {
expect(parseUlwLoopSteeringDirective(`${marker}: ${JSON.stringify(steering())}`)).toMatchObject({
kind: "add_subgoal",
});
});
it("returns null when no marker", () => {
expect(parseUltragoalSteeringDirective(JSON.stringify(steering()))).toBeNull();
expect(parseUlwLoopSteeringDirective(JSON.stringify(steering()))).toBeNull();
});
it("returns null when JSON malformed after marker", () => {
expect(parseUltragoalSteeringDirective("OMO_ULTRAGOAL_STEER: {bad json")).toBeNull();
expect(parseUlwLoopSteeringDirective("OMO_ULW_LOOP_STEER: {bad json")).toBeNull();
});
it("returns null for deprecated markers", () => {
const marker = ["OM", "X_ULTRAGOAL_STEER"].join("");
expect(parseUltragoalSteeringDirective(`${marker}: ${JSON.stringify(steering())}`)).toBeNull();
const marker = ["OM", "X_ULW_LOOP_STEER"].join("");
expect(parseUlwLoopSteeringDirective(`${marker}: ${JSON.stringify(steering())}`)).toBeNull();
});
});
@@ -2,56 +2,56 @@ import { describe, expect, it } from "vitest";
import {
iso,
ULTRAGOAL_BRIEF,
ULTRAGOAL_CRITERION_STATUSES,
ULTRAGOAL_DIR,
ULTRAGOAL_GOALS,
ULTRAGOAL_LEDGER,
ULTRAGOAL_STEERING_MUTATION_KINDS,
ULTRAGOAL_SUCCESS_CRITERION_USER_MODELS,
UltragoalError,
ULW_LOOP_BRIEF,
ULW_LOOP_CRITERION_STATUSES,
ULW_LOOP_DIR,
ULW_LOOP_GOALS,
ULW_LOOP_LEDGER,
ULW_LOOP_STEERING_MUTATION_KINDS,
ULW_LOOP_SUCCESS_CRITERION_USER_MODELS,
UlwLoopError,
} from "../src/types.ts";
describe("ultragoal domain constants", () => {
describe("ulw-loop domain constants", () => {
describe("when checking workspace paths", () => {
it("then ULTRAGOAL_DIR points to the omo workspace", () => {
expect(ULTRAGOAL_DIR).toBe(".omo/ultragoal");
it("then ULW_LOOP_DIR points to the omo workspace", () => {
expect(ULW_LOOP_DIR).toBe(".omo/ulw-loop");
});
it("then artifact filenames are stable", () => {
expect(ULTRAGOAL_BRIEF).toBe("brief.md");
expect(ULTRAGOAL_GOALS).toBe("goals.json");
expect(ULTRAGOAL_LEDGER).toBe("ledger.jsonl");
expect(ULW_LOOP_BRIEF).toBe("brief.md");
expect(ULW_LOOP_GOALS).toBe("goals.json");
expect(ULW_LOOP_LEDGER).toBe("ledger.jsonl");
});
});
describe("when checking steering mutation kinds", () => {
it("then includes the new revise_criterion kind", () => {
expect(ULTRAGOAL_STEERING_MUTATION_KINDS).toContain("revise_criterion");
expect(ULW_LOOP_STEERING_MUTATION_KINDS).toContain("revise_criterion");
});
it("then totals 7 kinds", () => {
expect(ULTRAGOAL_STEERING_MUTATION_KINDS).toHaveLength(7);
expect(ULW_LOOP_STEERING_MUTATION_KINDS).toHaveLength(7);
});
});
describe("when checking criterion user models", () => {
it("then exposes 4 user models including adversarial", () => {
expect(ULTRAGOAL_SUCCESS_CRITERION_USER_MODELS).toEqual(["happy", "edge", "regression", "adversarial"]);
expect(ULW_LOOP_SUCCESS_CRITERION_USER_MODELS).toEqual(["happy", "edge", "regression", "adversarial"]);
});
});
describe("when checking criterion statuses", () => {
it("then exposes pending/pass/fail/blocked", () => {
expect(ULTRAGOAL_CRITERION_STATUSES).toEqual(["pending", "pass", "fail", "blocked"]);
expect(ULW_LOOP_CRITERION_STATUSES).toEqual(["pending", "pass", "fail", "blocked"]);
});
});
});
describe("UltragoalError", () => {
describe("UlwLoopError", () => {
describe("when constructed with code", () => {
it("then is an Error instance carrying the code", () => {
const err = new UltragoalError("bad", "TEST_CODE");
const err = new UlwLoopError("bad", "TEST_CODE");
expect(err).toBeInstanceOf(Error);
expect(err.code).toBe("TEST_CODE");
@@ -60,7 +60,7 @@ describe("UltragoalError", () => {
it("then accepts optional cause + details", () => {
const cause = new Error("upstream");
const err = new UltragoalError("wrap", "WRAP", { cause, details: { goalId: "G001" } });
const err = new UlwLoopError("wrap", "WRAP", { cause, details: { goalId: "G001" } });
expect(err.cause).toBe(cause);
expect(err.details).toEqual({ goalId: "G001" });