oh-my-opencode 4.17.1 → 4.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/codex-qa/SKILL.md +2 -0
- package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +3654 -0
- package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +3071 -0
- package/.agents/skills/work-with-pr/SKILL.md +16 -37
- package/.agents/skills/work-with-pr-workspace/evals/evals.json +3 -3
- package/.opencode/skills/work-with-pr/SKILL.md +16 -37
- package/.opencode/skills/work-with-pr-workspace/evals/evals.json +3 -3
- package/dist/cli/get-local-version/types.d.ts +1 -1
- package/dist/cli/index.js +498 -165
- package/dist/cli-node/index.js +498 -165
- package/dist/index.js +425 -392
- package/dist/skills/frontend/SKILL.md +1 -1
- package/dist/skills/frontend/references/design/README.md +9 -0
- package/dist/skills/frontend/references/design/design-system-architecture.md +4 -2
- package/dist/skills/frontend/references/design/layout-skill.md +107 -0
- package/dist/skills/programming/SKILL.md +12 -2
- package/package.json +17 -16
- package/packages/lsp-core/package.json +4 -0
- package/packages/lsp-core/src/index.ts +1 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.ts +12 -3
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +261 -0
- package/packages/lsp-core/src/lsp/client-wrapper.test.ts +63 -0
- package/packages/lsp-core/src/lsp/client-wrapper.ts +35 -5
- package/packages/lsp-core/src/lsp/client.ts +262 -80
- package/packages/lsp-core/src/lsp/config-loader.ts +5 -17
- package/packages/lsp-core/src/lsp/connection.ts +12 -6
- package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +104 -0
- package/packages/lsp-core/src/lsp/directory-diagnostics.ts +60 -27
- package/packages/lsp-core/src/lsp/errors.ts +11 -0
- package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +215 -0
- package/packages/lsp-core/src/lsp/formatters.ts +3 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection.ts +73 -5
- package/packages/lsp-core/src/lsp/server-install-state.ts +3 -6
- package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
- package/packages/lsp-core/src/lsp/transport.ts +96 -70
- package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +214 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +163 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +67 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.ts +368 -0
- package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +113 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
- package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
- package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
- package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
- package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
- package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
- package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
- package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
- package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
- package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
- package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
- package/packages/lsp-core/src/lsp/workspace-edit.ts +49 -200
- package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
- package/packages/lsp-core/src/mcp.ts +18 -7
- package/packages/lsp-core/src/missing-dependency-result.test.ts +105 -0
- package/packages/lsp-core/src/missing-dependency-result.ts +57 -0
- package/packages/lsp-core/src/post-edit/index.ts +1 -0
- package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
- package/packages/lsp-core/src/post-edit/orchestration.ts +178 -0
- package/packages/lsp-core/src/request-context.test.ts +171 -0
- package/packages/lsp-core/src/request-context.ts +222 -9
- package/packages/lsp-core/src/tool-surface.test.ts +4 -1
- package/packages/lsp-core/src/tools/diagnostics.ts +32 -13
- package/packages/lsp-core/src/tools/navigation.ts +12 -12
- package/packages/lsp-core/src/tools/rename.ts +10 -15
- package/packages/lsp-core/src/tools/symbols.ts +11 -11
- package/packages/lsp-core/src/tools/types.ts +2 -1
- package/packages/lsp-daemon/dist/cli.js +3114 -747
- package/packages/lsp-daemon/dist/client.d.ts +105 -0
- package/packages/lsp-daemon/dist/client.js +5851 -0
- package/packages/lsp-daemon/dist/daemon-client.d.ts +11 -6
- package/packages/lsp-daemon/dist/daemon-client.js +113 -30
- package/packages/lsp-daemon/dist/daemon-server.d.ts +1 -0
- package/packages/lsp-daemon/dist/daemon-server.js +40 -15
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +8 -7
- package/packages/lsp-daemon/dist/ensure-daemon.js +67 -44
- package/packages/lsp-daemon/dist/index.d.ts +2 -2
- package/packages/lsp-daemon/dist/index.js +2862 -754
- package/packages/lsp-daemon/dist/ipc-protocol.d.ts +46 -0
- package/packages/lsp-daemon/dist/ipc-protocol.js +187 -0
- package/packages/lsp-daemon/dist/lock.js +14 -4
- package/packages/lsp-daemon/dist/ownership.d.ts +49 -0
- package/packages/lsp-daemon/dist/ownership.js +168 -0
- package/packages/lsp-daemon/dist/paths.d.ts +33 -9
- package/packages/lsp-daemon/dist/paths.js +72 -33
- package/packages/lsp-daemon/dist/proxy.d.ts +3 -0
- package/packages/lsp-daemon/dist/proxy.js +54 -3
- package/packages/lsp-daemon/dist/request-routing.d.ts +7 -2
- package/packages/lsp-daemon/dist/request-routing.js +71 -22
- package/packages/lsp-daemon/dist/run-daemon.js +9 -2
- package/packages/lsp-daemon/dist/runtime-contract.d.ts +21 -0
- package/packages/lsp-daemon/dist/runtime-contract.js +58 -0
- package/packages/lsp-daemon/dist/socket-jsonrpc.js +6 -1
- package/packages/lsp-daemon/package.json +12 -3
- package/packages/lsp-tools-mcp/dist/cli.js +2115 -442
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +1741 -148
- package/packages/lsp-tools-mcp/dist/mcp.js +2127 -454
- package/packages/lsp-tools-mcp/dist/request-context.js +176 -6
- package/packages/lsp-tools-mcp/dist/tools.js +2118 -446
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +55 -0
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +2959 -944
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook-cli.js +0 -4
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.d.ts +5 -2
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +41 -62
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.d.ts +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +24 -15
- package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.d.ts +3 -7
- package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.js +23 -49
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +3 -2
- package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.mjs +31 -1
- package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.test.mjs +76 -0
- package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.mjs +201 -0
- package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.test.mjs +55 -0
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +0 -4
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +49 -71
- package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +26 -15
- package/packages/omo-codex/plugin/components/lsp/src/lsp-session-state.ts +26 -64
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +16 -17
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +30 -4
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +19 -5
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +8 -6
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +37 -10
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +37 -10
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +37 -10
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +10 -9
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +26 -14
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +2 -3
- package/packages/omo-codex/plugin/scripts/build-components.mjs +13 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +9 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +4 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/layout-skill.md +107 -0
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +12 -2
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +37 -10
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +10 -9
- package/packages/omo-codex/plugin/test/aggregate-build.test.mjs +8 -0
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +128 -15
- package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +10 -0
- package/packages/omo-codex/plugin/test/lsp-prebuild-layouts.test.mjs +2 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +351 -74
- package/packages/shared-skills/skills/frontend/SKILL.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/README.md +9 -0
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +4 -2
- package/packages/shared-skills/skills/frontend/references/design/layout-skill.md +107 -0
- package/packages/shared-skills/skills/programming/SKILL.md +12 -2
|
@@ -129,7 +129,7 @@ First survey available skills: read every loosely-relevant skill's description,
|
|
|
129
129
|
Then run tier triage per goal — rigor (LIGHT/HEAVY below) and shape (`delivery` default, or `research` when the deliverable is a cited answer, not an artifact) — and record both in an `annotate_ledger` steering entry. Default is LIGHT — a narrow change inside existing layers. Take HEAVY only on a fact you can point to: a new module / abstraction / domain model; auth, security, or session; an external integration; a DB schema or migration; concurrency, transaction boundaries, or cache invalidation; a cross-domain refactor; or the user signaled care or demanded review. When unsure, take HEAVY; upgrade the moment a HEAVY fact surfaces, never downgrade mid-run.
|
|
130
130
|
Planning depends on unresolved design uncertainty, not the rigor tier: after discovery, spawn the `plan` agent only when unclear boundaries, competing decompositions, or uncertain dependency ordering remain; otherwise plan directly, including for HEAVY goals with a known procedure. HEAVY goals carry 3+ successCriteria covering happy path, edge, regression, and adversarial risk. LIGHT goals carry 1-2 successCriteria (happy path + the riskiest edge) with one real-surface proof of the deliverable.
|
|
131
131
|
Research-shape goals change the cycle: BEFORE each investigation, read this goal's prior ledger findings and open hypotheses, then extend them — never re-investigate an answered question (the ledger is your research notebook). Record findings via `annotate_ledger` with their source (`file:line`, command output, doc URL) as `--evidence`. Track hypotheses as `HYPOTHESIS[id]: <claim> | status: open`, flipped to `confirmed`/`refuted` only on an observed source. A research criterion passes on a cited answer — skip QA-channel, cleanup, and commit, but keep source-observability (never "looks correct"). Keep hypotheses inside the user's stated question; a scope-widening one is an `add_subgoal` proposal you surface, never silent creep. For a `research`-shape goal you MAY load `ulw-research` without hesitation — otherwise explicit-request-only, a research-shape goal IS that explicit demand. Research-only: never for a `delivery` goal. It composes with the librarian routing above — `ulw-research` for saturation (many parallel sources, recursive expansion), a single `librarian` for one lookup.
|
|
132
|
-
For each criterion, define upfront: `id`, exact `scenario` (tool + inputs + binary pass/fail), `expectedEvidence` artifact path, adversarial classes, stop condition, and Manual-QA channel. Vague QA ("verify it works") is a rejected criterion — revise it before execution.
|
|
132
|
+
For each criterion, define upfront: `id`, exact `scenario` (tool + inputs + binary pass/fail), `expectedEvidence` artifact path, adversarial classes, stop condition, and Manual-QA channel. Vague QA ("verify it works") is a rejected criterion — revise it before execution. Every goal also declares, in one line, WHEN TO STOP: "stop right away when <the exact observable state that ends this goal>". A goal without that line is rejected — revise it before execution; the Stop Rules bind to it.
|
|
133
133
|
For optimization work, capture baseline speed before changes plus behavior/regression proof. Every attempt records speed, behavior/regression, and the keep/revert/iterate decision.
|
|
134
134
|
A criterion's adversarial classes are the ultraqa classes a fact about the change triggers: malformed input, prompt injection, cancel/resume, stale state, dirty worktree, hung or long commands, flaky tests, misleading success output, repeated interruptions. Record untriggered classes as not-applicable in one line.
|
|
135
135
|
Use channel-table evidence verbs — not vibes.
|
|
@@ -151,7 +151,7 @@ Loop per goal. Cap at 5 cycles per goal. Cap identical same-criterion failures a
|
|
|
151
151
|
|
|
152
152
|
| get_goal result | action |
|
|
153
153
|
|-----------------|--------|
|
|
154
|
-
| no active goal |
|
|
154
|
+
| no active goal | You MUST call `create_goal` — goal registration goes through the tool, never prose — with objective only from `instruction.json.objective`; do not copy lifecycle fields such as `status`. |
|
|
155
155
|
| same aggregate objective active | Continue the current ulw-loop story. |
|
|
156
156
|
| different goal active | STOP. Checkpoint blocked and surface the conflict. |
|
|
157
157
|
4. If retrying failed work, run `omo ulw-loop complete-goals --retry-failed --json`.
|
|
@@ -160,14 +160,14 @@ Loop per goal. Cap at 5 cycles per goal. Cap identical same-criterion failures a
|
|
|
160
160
|
### Per-Criterion Cycle
|
|
161
161
|
1. PLAN: read `criterion.scenario`, `criterion.expectedEvidence`, prior ledger entries, and safety bounds. Identify which tasks in the current wave are independent.
|
|
162
162
|
2. Register atomic todos via `update_plan` — one ultra-granular step per action, `path: <action> for <criterion> - verify by <check>`. Call `update_plan` on every transition (start → `in_progress`, finish → `completed`); exactly one `in_progress`, mark completed immediately, never batch, never let the rendered plan lag behind reality.
|
|
163
|
-
3. DELEGATE-IN-PARALLEL: dispatch every independent task in the wave at once via right-sized `spawn_agent` workers (Delegation table). Each worker captures evidence failing-first: when the task touches EXISTING behavior, PIN it FIRST — a characterization test that asserts the current observable behavior and PASSES on the unchanged code, as rigorous as the new-behavior scenario (exact inputs, exact observable, exact assertion). Then RED through the cheapest faithful channel — a unit test where a seam exists, an integration/e2e test where the behavior lives in wiring, or the criterion's scenario captured failing when no test seam exists — failing for the RIGHT reason (no syntax/import error). A test that
|
|
163
|
+
3. DELEGATE-IN-PARALLEL: dispatch every independent task in the wave at once via right-sized `spawn_agent` workers (Delegation table). Each worker captures evidence failing-first: when the task touches EXISTING behavior, PIN it FIRST — a characterization test that asserts the current observable behavior and PASSES on the unchanged code, as rigorous as the new-behavior scenario (exact inputs, exact observable, exact assertion). Then RED through the cheapest faithful channel — a unit test where a seam exists, an integration/e2e test where the behavior lives in wiring, or the criterion's scenario captured failing when no test seam exists — failing for the RIGHT reason (no syntax/import error). A test that cannot fail for the regression it names (mock-call assertions, pinned constants, a fixture equal to the default it must override, an expected value re-derived from the output under test) is not evidence; use the scenario as the failing proof instead. TEST-ONLY tasks (regression coverage for behavior that is already correct) have no natural RED — require a mutation proof: temporarily force the exact regression each new assertion names, capture the assertion failing, revert the mutation, capture GREEN; an assertion that stays green under its mutation is not coverage. **When the target is PROSE (a prompt, `SKILL.md`, rule, or markdown/instruction file), the "observable behavior" is NOT the wording** — never pin sentences, phrase presence/absence, or word/char counts. PIN only a value a MACHINE consumes (a parsed frontmatter field, a sentinel token a hook greps, the doc's JSON sample run through its real validator), or guard two shipped copies with one `toBe` equality; a pure-prose change with no machine consumer has NO seam, so ship it on review + Manual-QA-by-read with NO automated test (a text grep there is pretend-coverage, not a RED proof). Then the SMALLEST GREEN change (none for a TEST-ONLY task — reverting the probe is GREEN; go to integration); before GREEN work that depends on external review, PR, issue, or branch state, refresh current branch/PR/issue state, preserve existing ordering/policy, and separate compatibility detection from policy changes unless the goal explicitly asks to change policy. A GREEN far larger than the criterion implies means the proof was too coarse — instruct a split. Serialize only on a NAMED dependency.
|
|
164
164
|
4. INTEGRATE + CRITICAL SELF-QA + GIT CHECKPOINT (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. Once the work unit is verified, use `git-master` before staging: inspect recent repository commits and touched-path history to infer commit language, Conventional Commit scope, message shape, and unit size. Stage only that unit's files and commit in the observed style; do not carry verified work forward into a later omnibus commit. If no git-tracked files changed or committing is unsafe, record the no-commit reason as evidence. Forward every finding/learning to subsequent workers.
|
|
165
165
|
5. EXECUTE-AS-SCENARIO: ACTUALLY run the Manual-QA scenario the criterion named (channel table above). Run it yourself for the orchestrator check; for heavier flows dispatch a dedicated QA execution worker (`lazycodex-worker-medium` by default; `lazycodex-worker-high` when the QA flow itself is hard) whose ONLY job is to drive the channel and write the artifact to the named evidence path. If the scenario FAILS, respawn the implementing worker with the captured failure — do not hand-patch around it.
|
|
166
166
|
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.
|
|
167
167
|
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 every finished worker (v1 `close_agent`; on V2 finished workers end on their own — `interrupt_agent` any still running). Register each teardown as its own todo the moment the QA spawns the resource (scripts, tmux assets, browsers / agent-browser sessions, PIDs, ports) so none is forgotten. 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; interrupt_agent w-3`. Missing receipt → record BLOCKED, not PASS.
|
|
168
|
-
8. RECORD one result immediately from the artifact you just wrote — never from memory or a later turn — stamping the capture
|
|
169
|
-
- PASS: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass --evidence "<observable>
|
|
170
|
-
- FAIL: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status fail --evidence "<observable>
|
|
168
|
+
8. RECORD one result immediately from the artifact you just wrote — never from memory or a later turn — stamping the capture tree `$(git rev-parse --short "HEAD^{tree}")` into the evidence:
|
|
169
|
+
- PASS: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass --evidence "<observable> @tree:<short-tree> | <cleanup receipt>" --json`
|
|
170
|
+
- FAIL: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status fail --evidence "<observable> @tree:<short-tree> | <cleanup receipt>" --notes "<diagnosis>" --json`
|
|
171
171
|
- BLOCKED: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status blocked --evidence "<observable>" --notes "<safety/blocker/leftover-state>" --json`
|
|
172
172
|
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).
|
|
173
173
|
10. After 3 same-criterion failures, exit the goal with diagnosis.
|
|
@@ -184,9 +184,10 @@ Loop per goal. Cap at 5 cycles per goal. Cap identical same-criterion failures a
|
|
|
184
184
|
## Final Quality Gate
|
|
185
185
|
Trigger only for the final aggregate goal after every criterion in every goal is `pass`.
|
|
186
186
|
1. Run targeted verification for changed behavior.
|
|
187
|
-
2. FREEZE first — no more edits or rebases. At the frozen
|
|
187
|
+
2. FREEZE first — no more edits or rebases. At the frozen HEAD, re-run Manual-QA for any PASS criterion whose stamped tree differs from `git rev-parse --short "HEAD^{tree}"`, so every criterion is proven on the frozen tree; each artifact exists and is non-empty.
|
|
188
188
|
3a. Spawn lazycodex-code-reviewer and lazycodex-qa-executor in parallel (`fork_context: false` on v1; `fork_turns: "none"` on v2) with brief, goals, desired outcome, diff, evidence; wait for BOTH and confirm their report artifacts exist on disk.
|
|
189
189
|
3b. Only then spawn lazycodex-gate-reviewer with those artifact paths.
|
|
190
|
+
3c. The gate's approval binds to the frozen tree and covers its three lanes — code quality, hands-on QA, and goal verification. A later rebase or amend that keeps the tree identical keeps the approval; changed content needs fresh review of the delta.
|
|
190
191
|
4. Treat timeout, missing deliverable, ack-only, `BLOCKED:`, or inconclusive review as a blocker. Any fix restarts the freeze at the new HEAD: re-run ONLY the proofs it invalidated and stamp the fresh output — never regenerate all evidence or relabel stale output to HEAD — re-review the delta at most TWICE; then record-review-blockers (step 5) and surface to the user.
|
|
191
192
|
5. If review remains blocked, run `omo ulw-loop record-review-blockers --goal-id <id> --title "<...>" --objective "<...>" --evidence "<review findings>" --codex-goal-json <snapshot> --json`.
|
|
192
193
|
6. If clean, checkpoint final completion:
|
|
@@ -224,7 +225,7 @@ Structured prompt directives accepted: `OMO_ULW_LOOP_STEER: { ... }`, `omo.ulw-l
|
|
|
224
225
|
## Constraints
|
|
225
226
|
1. NEVER call `update_goal` mid-aggregate; only on final story after the quality gate passes.
|
|
226
227
|
2. NEVER call `create_goal` when `get_goal` shows a different active goal.
|
|
227
|
-
3. Evidence is bound to the
|
|
228
|
+
3. Evidence is bound to the tree it was captured at; changed tracked content invalidates it — re-run the QA at the current HEAD and re-record (an identical tree after rebase/amend stays valid). NEVER mark PASS from memory, and NEVER relabel, pin, refresh, or regenerate prior output to a moved HEAD.
|
|
228
229
|
4. NEVER bypass the criteria gate: non-final aggregate completion requires all essential criteria; final aggregate completion requires all criteria across the whole plan.
|
|
229
230
|
5. Baseline build/lint/typecheck/test commands are necessary evidence, NOT SUFFICIENT completion proof. Criteria coverage with observable evidence is the gate.
|
|
230
231
|
6. Treat `.omo/ulw-loop/ledger.jsonl` as the durable audit trail; checkpoint after every success or failure.
|
|
@@ -239,7 +240,7 @@ Structured prompt directives accepted: `OMO_ULW_LOOP_STEER: { ... }`, `omo.ulw-l
|
|
|
239
240
|
15. Every verified work unit that touched git-tracked files must leave either an atomic `git-master`-style commit hash or explicit no-commit blocker evidence before the next unit starts.
|
|
240
241
|
|
|
241
242
|
## Stop Rules
|
|
242
|
-
-
|
|
243
|
+
- STOP GOAL: all goals complete plus every plan criterion `pass` plus final quality gate clean. The decisive test — outranking every other consideration — is whether the completion conditions are FUNDAMENTALLY fulfilled and the user's problem ACTUALLY SOLVED in observable behavior; a `pass` ledger never substitutes for it. The moment both hold, checkpoint, report, and STOP — no extra review cycles, no evidence regeneration, no polish.
|
|
243
244
|
- 3x same criterion failure: checkpoint failed, surface diagnosis.
|
|
244
245
|
- 5 cycles on one goal without required criteria passing: checkpoint failed, surface.
|
|
245
246
|
- Safety boundary such as destructive command, secret exfiltration, or production write: block and surface a safe substitute.
|
|
@@ -36,3 +36,11 @@ test("#given omo-codex package build script #when inspected #then delegates to t
|
|
|
36
36
|
// then
|
|
37
37
|
assert.equal(buildPluginScript, "bun run --cwd plugin build");
|
|
38
38
|
});
|
|
39
|
+
|
|
40
|
+
test("#given a component-owned runtime manifest #when aggregate component build script is inspected #then it preserves bundled bytes", async () => {
|
|
41
|
+
const buildScript = await readFile(join(root, "scripts", "build-components.mjs"), "utf8");
|
|
42
|
+
|
|
43
|
+
assert.match(buildScript, /hasComponentOwnedBundle/u);
|
|
44
|
+
assert.match(buildScript, /"dist", "\.omo-runtime-manifest\.json"/u);
|
|
45
|
+
assert.match(buildScript, /if \(await hasComponentOwnedBundle\(task\.componentPath\)\) return/u);
|
|
46
|
+
});
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
chmodSync,
|
|
4
|
+
cpSync,
|
|
5
|
+
existsSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
mkdtempSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
readdirSync,
|
|
10
|
+
rmSync,
|
|
11
|
+
writeFileSync,
|
|
12
|
+
} from "node:fs";
|
|
3
13
|
import { readFile } from "node:fs/promises";
|
|
4
14
|
import { tmpdir } from "node:os";
|
|
5
15
|
import { join } from "node:path";
|
|
@@ -23,6 +33,7 @@ const HOOK_EVENTS_BY_COMPONENT = {
|
|
|
23
33
|
};
|
|
24
34
|
const MCP_ONLY_COMPONENTS = new Set(["codegraph"]);
|
|
25
35
|
const HOOK_CLI_TEST_TIMEOUT_MS = 45_000;
|
|
36
|
+
const DAEMON_EXIT_TIMEOUT_MS = 5_000;
|
|
26
37
|
|
|
27
38
|
test("#given required component CLI contracts #when workspaces are inspected #then every contract component is covered", async () => {
|
|
28
39
|
// given
|
|
@@ -125,29 +136,84 @@ test("#given representative component hook payloads #when executed through dist
|
|
|
125
136
|
}
|
|
126
137
|
});
|
|
127
138
|
|
|
128
|
-
test("#given bundled LSP hook CLI in installed layout #when diagnostics run #then it spawns sibling daemon target", () => {
|
|
139
|
+
test("#given bundled LSP hook CLI in installed layout #when diagnostics run #then it spawns sibling daemon target", async () => {
|
|
129
140
|
const tempRoot = mkdtempSync(join(tmpdir(), "omo-codex-lsp-installed-"));
|
|
130
141
|
try {
|
|
131
142
|
const lspDist = join(tempRoot, "components", "lsp", "dist");
|
|
132
143
|
const daemonDist = join(tempRoot, "components", "lsp-daemon", "dist");
|
|
133
144
|
const daemonDir = join(tempRoot, "daemon");
|
|
134
|
-
const invocationLog = join(tempRoot, "fake-daemon-invocations.jsonl");
|
|
135
145
|
mkdirSync(lspDist, { recursive: true });
|
|
136
146
|
mkdirSync(daemonDist, { recursive: true });
|
|
137
147
|
mkdirSync(join(tempRoot, "src"), { recursive: true });
|
|
138
148
|
writeFileSync(join(tempRoot, "package.json"), JSON.stringify({ type: "module" }));
|
|
139
149
|
writeFileSync(join(lspDist, "cli.js"), readFileSync(componentCliPath("lsp"), "utf8"));
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
150
|
+
cpSync(join(root, "..", "..", "lsp-daemon", "dist"), daemonDist, { recursive: true });
|
|
151
|
+
const editedFile = join(tempRoot, "src", "broken.ts");
|
|
152
|
+
const scenarioPath = join(tempRoot, "scenario.json");
|
|
153
|
+
const eventsPath = join(tempRoot, "lsp-events.jsonl");
|
|
154
|
+
const codexHome = join(tempRoot, "codex-home");
|
|
155
|
+
mkdirSync(codexHome, { recursive: true });
|
|
156
|
+
writeFileSync(editedFile, "const value: string = 1;\n");
|
|
157
|
+
writeFileSync(eventsPath, "");
|
|
158
|
+
writeFileSync(
|
|
159
|
+
scenarioPath,
|
|
160
|
+
JSON.stringify({
|
|
161
|
+
publishDiagnostics: [
|
|
162
|
+
{
|
|
163
|
+
trigger: "didOpen",
|
|
164
|
+
version: 1,
|
|
165
|
+
diagnostics: [
|
|
166
|
+
{
|
|
167
|
+
range: { start: { line: 0, character: 6 }, end: { line: 0, character: 11 } },
|
|
168
|
+
severity: 1,
|
|
169
|
+
code: "fake",
|
|
170
|
+
source: "fake",
|
|
171
|
+
message: "Missing fake symbol.",
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
diagnosticResponses: [
|
|
177
|
+
{
|
|
178
|
+
report: {
|
|
179
|
+
items: [
|
|
180
|
+
{
|
|
181
|
+
range: { start: { line: 0, character: 6 }, end: { line: 0, character: 11 } },
|
|
182
|
+
severity: 1,
|
|
183
|
+
code: "fake",
|
|
184
|
+
source: "fake",
|
|
185
|
+
message: "Missing fake symbol.",
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
writeFileSync(
|
|
194
|
+
join(codexHome, "lsp-client.json"),
|
|
195
|
+
JSON.stringify({
|
|
196
|
+
lsp: {
|
|
197
|
+
typescript: {
|
|
198
|
+
command: [
|
|
199
|
+
process.execPath,
|
|
200
|
+
join(root, "..", "..", "lsp-core", "src", "lsp", "fixtures", "workspace-edit-server.mjs"),
|
|
201
|
+
scenarioPath,
|
|
202
|
+
eventsPath,
|
|
203
|
+
],
|
|
204
|
+
extensions: [".ts"],
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
}),
|
|
208
|
+
);
|
|
144
209
|
|
|
145
210
|
const result = spawnSync(process.execPath, [join(lspDist, "cli.js"), "hook", "post-tool-use"], {
|
|
146
211
|
cwd: tempRoot,
|
|
147
212
|
encoding: "utf8",
|
|
148
213
|
env: hookEnv(tempRoot, {
|
|
149
|
-
|
|
150
|
-
|
|
214
|
+
CODEX_HOME: codexHome,
|
|
215
|
+
OMO_LSP_DAEMON_DIR: daemonDir,
|
|
216
|
+
NODE_PATH: "",
|
|
151
217
|
}),
|
|
152
218
|
input: JSON.stringify({
|
|
153
219
|
session_id: "bundled-lsp-hook",
|
|
@@ -158,17 +224,17 @@ test("#given bundled LSP hook CLI in installed layout #when diagnostics run #the
|
|
|
158
224
|
timeout: HOOK_CLI_TEST_TIMEOUT_MS,
|
|
159
225
|
});
|
|
160
226
|
|
|
161
|
-
const
|
|
162
|
-
const failureContext = `stdout: ${result.stdout}\nstderr: ${result.stderr}\ndaemon log: ${daemonInvocations}`;
|
|
227
|
+
const failureContext = `stdout: ${result.stdout}\nstderr: ${result.stderr}`;
|
|
163
228
|
assert.equal(result.status, 0, failureContext);
|
|
164
229
|
assert.equal(result.stderr, "", failureContext);
|
|
165
230
|
assert.notEqual(result.stdout, "", failureContext);
|
|
166
231
|
const parsed = JSON.parse(result.stdout);
|
|
167
232
|
assert.equal(parsed.decision, "block");
|
|
168
|
-
assert.match(parsed.reason, /
|
|
169
|
-
assert.
|
|
170
|
-
assert.equal(existsSync(join(daemonDir, "
|
|
233
|
+
assert.match(parsed.reason, /Missing fake symbol\./);
|
|
234
|
+
assert.match(readFileSync(eventsPath, "utf8"), /textDocument\/publishDiagnostics/);
|
|
235
|
+
assert.equal(existsSync(join(daemonDir, `v${JSON.parse(readFileSync(join(daemonDist, "package.json"), "utf8")).version}`, "daemon.log")), true);
|
|
171
236
|
} finally {
|
|
237
|
+
await stopTestDaemons(join(tempRoot, "daemon"));
|
|
172
238
|
rmSync(tempRoot, { recursive: true, force: true });
|
|
173
239
|
}
|
|
174
240
|
});
|
|
@@ -336,7 +402,7 @@ function writeFakeLspDaemonCli(path) {
|
|
|
336
402
|
'import { createServer } from "node:net";',
|
|
337
403
|
"",
|
|
338
404
|
"appendFileSync(process.env.FAKE_LSP_DAEMON_LOG, `${JSON.stringify(process.argv.slice(2))}\\n`);",
|
|
339
|
-
"const baseDir = process.env.
|
|
405
|
+
"const baseDir = process.env.OMO_LSP_DAEMON_DIR;",
|
|
340
406
|
'const versionDirName = readdirSync(baseDir).find((entry) => entry.startsWith("v")) ?? "v0";',
|
|
341
407
|
"const version = versionDirName.slice(1);",
|
|
342
408
|
"const dir = join(baseDir, versionDirName);",
|
|
@@ -374,6 +440,53 @@ function writeFakeLspDaemonCli(path) {
|
|
|
374
440
|
);
|
|
375
441
|
}
|
|
376
442
|
|
|
443
|
+
async function stopTestDaemons(daemonRoot) {
|
|
444
|
+
if (!existsSync(daemonRoot)) return;
|
|
445
|
+
for (const versionDir of readdirSync(daemonRoot)) {
|
|
446
|
+
const pidPath = join(daemonRoot, versionDir, "daemon.pid");
|
|
447
|
+
if (!existsSync(pidPath)) continue;
|
|
448
|
+
const pid = Number(readFileSync(pidPath, "utf8").trim());
|
|
449
|
+
if (!Number.isInteger(pid) || pid <= 0) continue;
|
|
450
|
+
if (process.platform === "win32") {
|
|
451
|
+
const result = spawnSync("taskkill", ["/pid", String(pid), "/f", "/t"], {
|
|
452
|
+
encoding: "utf8",
|
|
453
|
+
windowsHide: true,
|
|
454
|
+
});
|
|
455
|
+
if (result.error) throw result.error;
|
|
456
|
+
if (result.status !== 0 && processIsRunning(pid)) {
|
|
457
|
+
throw new Error(
|
|
458
|
+
`taskkill failed for test daemon ${pid}: exit=${result.status} stderr=${result.stderr.trim()}`,
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
} else {
|
|
462
|
+
try {
|
|
463
|
+
process.kill(pid, "SIGTERM");
|
|
464
|
+
} catch (error) {
|
|
465
|
+
if (error instanceof Error && "code" in error && error.code === "ESRCH") continue;
|
|
466
|
+
throw error;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
await waitForProcessExit(pid);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
async function waitForProcessExit(pid) {
|
|
474
|
+
const deadline = Date.now() + DAEMON_EXIT_TIMEOUT_MS;
|
|
475
|
+
while (processIsRunning(pid)) {
|
|
476
|
+
if (Date.now() >= deadline) throw new Error(`Timed out waiting for test daemon ${pid} to exit`);
|
|
477
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function processIsRunning(pid) {
|
|
482
|
+
try {
|
|
483
|
+
process.kill(pid, 0);
|
|
484
|
+
return true;
|
|
485
|
+
} catch {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
377
490
|
function hookEnv(tempRoot, extraEnv = {}) {
|
|
378
491
|
return {
|
|
379
492
|
...process.env,
|
|
@@ -31,3 +31,13 @@ test("#given aggregate build scripts #when inspected #then npm subprocesses reso
|
|
|
31
31
|
assert.match(installTimeBuildScripts, /shell: process\.platform === "win32"/);
|
|
32
32
|
assert.doesNotMatch(installTimeBuildScripts, /npm\.cmd/);
|
|
33
33
|
});
|
|
34
|
+
|
|
35
|
+
test("#given bundled MCP runtime builds #when a locked runtime has no node_modules #then npm ci bootstraps it before build", async () => {
|
|
36
|
+
// given
|
|
37
|
+
const buildBundledMcpRuntimesScript = await readFile(join(root, "scripts", "build-bundled-mcp-runtimes.mjs"), "utf8");
|
|
38
|
+
|
|
39
|
+
// then
|
|
40
|
+
assert.match(buildBundledMcpRuntimesScript, /package-lock\.json/);
|
|
41
|
+
assert.match(buildBundledMcpRuntimesScript, /spawnSync\("npm", \["ci"\]/);
|
|
42
|
+
assert.match(buildBundledMcpRuntimesScript, /!existsSync\(join\(runtime\.packageRoot, "node_modules"\)\)/);
|
|
43
|
+
});
|
|
@@ -64,6 +64,8 @@ test("#given the installed cache layout #when running build-lsp-daemon #then use
|
|
|
64
64
|
|
|
65
65
|
await mkdir(join(root, "components", "lsp-daemon", "dist"), { recursive: true });
|
|
66
66
|
await writeFile(join(root, "components", "lsp-daemon", "dist", "cli.js"), "");
|
|
67
|
+
await writeFile(join(root, "components", "lsp-daemon", "dist", "client.js"), "");
|
|
68
|
+
await writeFile(join(root, "components", "lsp-daemon", "dist", "client.d.ts"), "");
|
|
67
69
|
await writeFile(join(root, "components", "lsp-daemon", "dist", "index.js"), "");
|
|
68
70
|
await writeFile(join(root, "components", "lsp-daemon", "dist", "index.d.ts"), "");
|
|
69
71
|
|
|
@@ -77,7 +77,7 @@ const startWorkOriginalCompletion = `When all top-level checkboxes in \`## TODOs
|
|
|
77
77
|
const startWorkCodexCompletion = `When all top-level checkboxes in \`## TODOs\` and \`## Final Verification Wave\` are complete:
|
|
78
78
|
|
|
79
79
|
1. Run the plan's final verification commands.
|
|
80
|
-
2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge:
|
|
80
|
+
2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge. The gate's pass binds to the commit SHA it reviewed and covers every later checkpoint at that same SHA — never re-run it on an already-passed SHA; re-run only when new commits land:
|
|
81
81
|
- Invoke the \`review-work\` skill with the final diff, changed files, user goal, constraints, run command, and verification evidence. All five review lanes must return PASS. A timeout, missing deliverable, ack-only child, \`BLOCKED:\`, or inconclusive lane is a gate failure, not approval.
|
|
82
82
|
- Run a debugging-oriented runtime audit even when the review passes: name at least three plausible failure hypotheses for the changed surface, run the distinguishing checks against the actual artifact, and append the ruled-out or confirmed result to \`.omo/start-work/ledger.jsonl\`.
|
|
83
83
|
- If any review lane or debugging hypothesis fails, invoke the \`debugging\` skill, confirm root cause with runtime evidence, add the minimal failing test or reproduction, fix it, rerun the affected verification, then rerun the Global Review and Debugging Gate.
|