Commit Graph

408 Commits

Author SHA1 Message Date
YeonGyu-Kim 27f956ecec fix(delegate-task): start sync prompts asynchronously 2026-05-27 14:22:14 +09:00
bellman 779e2d2f10 fix(task): capture late-arriving sessionId so TUI subagent entry is clickable (#4252)
The OpenCode TUI renders background subagent session entries using
`props.metadata.sessionId` as the navigation target. When the wait-loop
in delegate-task and background-task tools exits before the session is
assigned, but the session is created moments later (before metadata
publish), the published metadata had `sessionId: undefined`, leaving
the TUI entry stuck spinning with no clickable target.

Add a single late-fallback `manager.getTask(task.id)?.sessionId` check
between the wait-loop exit and metadata publish in both paths. This
closes the narrow race window that produced the symptom in #4252.

Regression test: `late-session-id-capture.test.ts` mocks the exact race
(launch returns no sessionId; getTask returns it after the wait loop).

Verified:
- npm run build: PASS
- npm test: exit code 0 (one unrelated pre-existing failure in
  sisyphus-task > browserProvider propagation re: agent-browser skill)
2026-05-24 02:04:38 +09:00
YeonGyu-Kim 11c3da752c fix(default-mode,multimodal-looker,delegate-task): preserve user-expected behavior
default-mode (system-transform):
- e5463e2db introduced auto-activation of ultrawork+ralph-loop, and
  dc2e082ac then skipped the ultrawork system prompt whenever ralph_loop
  was also enabled. Net effect: the keyword-detector still showed
  'Default ultrawork mode enabled' to the user, but the first turn had
  none of the ultrawork behavior. Loop continuation kept the ultrawork
  prefix, so the contract was honored only on later iterations.
- Drop the skip so the initial turn matches what the toast advertises.
  New matrix test pins all four (ultrawork, ralph_loop) combinations.

multimodal-looker:
- Prompt claimed 'read' and 'call_omo_agent' were available, but the
  look_at invocation runtime explicitly disables both via READ_ENABLED
  and createAgentToolAllowlist([]). Small VL models trusted the prompt
  and looped on rejected tool calls (#4116).
- Rewrite the agent prompt to describe direct-attachment analysis and
  forbid tool/agent calls. Add a consistency test that extracts the
  prompt's 'available tools' claim and compares it against the
  configured allowlist.

delegate-task (skill-resolver):
- 088693697 filtered per-agent restricted skills at the skill tool and
  builtin agent prompt layers, but delegate-task itself happily injected
  whatever skill name a caller passed. A target agent could be force-fed
  a skill marked agent: oracle just by listing it in load_skills.
- Thread the target agent through resolveSkills and silently filter
  skills whose definition.agent does not include it. Public skills with
  no restriction are unaffected. Regression test pins the bypass.
2026-05-22 00:07:46 +09:00
YeonGyu-Kim bc0da0fad3 test: fix prometheus-prompt syntax + sync display name casing to lowercase
- prometheus-prompt.test.ts: close missing }) on the OpenSpec expanded
  commands describe block (introduced by d66b6bcbf, parse error).
- agent-sort-shim/agent-config-integration/continuation-injection/
  unstable-agent-babysitter/subagent-resolver/sync-executor/
  resolve-caller-team-lead tests: expect 'Sisyphus - ultraworker'
  (lowercase) to match production after cd39f8858, which lowercased the
  display name to dodge a TUI ZWSP rendering glitch. Legacy uppercase
  inputs that exercise the normalization path are preserved.
- sync-executor.ts + resolve-caller-team-lead.ts: route legacy display
  name inputs through normalizeAgentForPrompt so prompt agent names and
  caller team lead lookups produce the canonical lowercase form.
2026-05-22 00:07:46 +09:00
YeonGyu-Kim 6e1e01ebe0 Merge pull request #4219 from sjawhar/fix/skill-discovery-opencode-config
fix(skill-discovery): load native OpenCode skills in task delegation
2026-05-21 15:07:39 +09:00
ZeyuFu 860c663c80 fix-up(#4027): narrow coordinator guard to registry hard-reject set
Maintainer feedback (#4071 review): the original guard rejected
sisyphus and atlas as subagent targets even from team-mode where
resolveMember() intentionally calls resolveSubagentExecution with
allowPrimaryAgentDelegation: true. Per AGENT_ELIGIBILITY_REGISTRY
(src/features/team-mode/types.ts), only prometheus is hard-reject;
sisyphus and atlas are explicitly verdict: 'eligible' for team
membership.

Shrink COORDINATOR_AGENT_NAMES to ['prometheus'] so the guard
aligns with the registry's authoritative classification, document
the scoping rule in a comment, and add regression tests covering:

- sisyphus is NOT blocked by the coordinator guard (registry eligible)
- atlas is NOT blocked by the coordinator guard (registry eligible)
- prometheus IS blocked even when allowPrimaryAgentDelegation: true
  (registry hard-reject is authoritative)

Fixes the 5 zauc-mocks resolver tests that were locking in the
wrong rejection set (including 'allows delegating to a primary
agent when allowPrimaryAgentDelegation is enabled'). The one test
asserting the literal primary-agent error string for Prometheus
display-name was loosened to a regex that accepts either guard's
message, since prometheus is now caught by the coordinator path
which fires before the primary-agent lookup.
2026-05-20 22:05:47 -04:00
ZeyuFu 7af3007e67 fix(team-mode): reject coordinator agents as subagent targets (#4027)
Agents could select coordinator/meta agents (Prometheus, Atlas,
Sisyphus/Ultraworker) as subagent targets via task() / delegation,
producing duplicate orchestration loops and conflicting team state.
This is the inverse of #3987 / #4065 — symmetric guard on the
delegation TARGET side, using the same AGENT_ELIGIBILITY_REGISTRY
classification.

Add a runtime guard at the delegation entry point that rejects
task() calls whose subagent_type resolves to an agent marked as
hard-reject / coordinator-only in the eligibility registry, with
an actionable error naming the agent. Regression test asserts a
prometheus-targeted delegation is rejected before any subagent
session spawns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 22:05:47 -04:00
Sami Jawhar 9c4ae26945 fix(skill-discovery): load native OpenCode skills in task delegation 2026-05-20 16:22:01 +00:00
YeonGyu-Kim 8276eb6c53 Merge pull request #4121 from mguttmann/fix-4119
fix(delegate-task): default run_in_background and load_skills instead of throwing (fixes #4119)
2026-05-21 00:01:12 +09:00
YeonGyu-Kim 3e9c3f8ada Merge pull request #4146 from LYY/fix/skill-shortname-fallback
fix: support unambiguous short skill names in delegated skill loading
2026-05-20 23:42:44 +09:00
YeonGyu-Kim 791825fc20 Merge pull request #4153 from MoerAI/fix/fallback-model-string-guard
fix(shared,delegate-task,claude-code-agent-loader): guard model parsers against non-string input (fixes #4145)
2026-05-20 23:40:33 +09:00
YeonGyu-Kim d3e218f912 fix(prompt): treat post-dispatch failures as accepted 2026-05-20 11:42:32 +09:00
YeonGyu-Kim bcea4a9d28 fix(prompt-gate): harden sync and team prompt dispatch 2026-05-19 19:18:13 +09:00
YeonGyu-Kim 1492bffd20 fix(prompt-gate): harden internal prompt dispatch 2026-05-19 19:18:13 +09:00
Claude Agent 9b151a2551 fix(delegate-task): address Oracle review on PR #4121 — preserve explicit-null reject + rewrite continuation test
Two blockers from the maintainer's Oracle review on PR #4121:

Blocker 1 — load_skills=null should still throw, omitted should default

The previous PR collapsed both `loadSkills === undefined` and
`loadSkills === null` into a silent default of `[]`. The closing
rationale of PR #1663 (which reverted PR #1493) and the maintainer's
review both call out the importance of preserving the distinct
"omitted -> default, explicit invalid -> throw" contract. `null`
strongly signals "I tried to pass something and it was wrong";
silently coercing it hides bugs upstream.

Restored the split: `undefined` -> default `[]` + log,
`null` -> throw with the historical error string.

Blocker 2 — task_id continuation test rewritten, not deleted

The original PR removed the `task_id without run_in_background ->
throws` test entirely. The behavior IS preserved (default false ->
`isExplicitSyncRun` true -> `executeSyncContinuation`), but with the
test gone the new contract was unprotected.

Added a regression test that asserts the new contract: when
`task_id` is present and `run_in_background` is omitted,
`tool.execute` must route through sync continuation without throwing
the legacy required-parameter error. Mocks include `session.abort`
because the sync poller calls it during shutdown.

Also flipped the existing `load_skills=null` regression test from
"normalizes to []" back to "throws with the legacy error string" to
match the restored contract.

Tests:
- bun test src/tools/delegate-task/tools.test.ts -> 132/132 pass
- bun test src/tools/delegate-task/ -> 406/406 pass
- bun run typecheck -> clean
2026-05-19 09:13:08 +02:00
Claude Agent 2f16a7da9f fix(delegate-task): default run_in_background and load_skills instead of throwing (fixes #4119)
Sisyphus and other delegators occasionally invoke the task() tool without
an explicit run_in_background or load_skills argument. The runtime
validators in tool-argument-preparation.ts threw a hard Error in that
case, which short-circuited tool.execute() entirely. Because OpenCode's
tool.execute.after hook only runs on returned results, the
delegate-task-retry hook never had a chance to attach corrective
guidance — so the model saw a raw failure and either burned several
retries or fell back to a synchronous Explore call, silently losing
parallel execution.

Behavior change:
- run_in_background omitted -> defaults to false (sync delegation), with
  a log entry for observability.
- load_skills omitted or null -> normalized to [] with a log entry on
  the explicit-null path.
- The Zod schema entries are now .optional() and their .describe()
  strings declare the defaults honestly; the markdown tool description
  was updated to match (no more 'REQUIRED' lie).

The orthogonal validation 'Must provide either category or
subagent_type.' is unchanged and still surfaces as a returned error.

Tests:
- The five throw-on-missing tests in tools.test.ts are rewritten to
  assert the new default-and-proceed contract.
- The 'no category, no subagent_type' test now asserts the
  missing-target error remains intact.

Refs the workaround the reporter validated in the original issue body;
matches the design from PR #2375 which was previously reverted by
566031f4.
2026-05-19 09:13:08 +02:00
YeonGyu-Kim e57bac3b6b fix(prompt-retry): preserve async holds without blocking validation fallbacks 2026-05-19 13:48:33 +09:00
MoerAI ae0c106ed4 fix(shared,delegate-task,claude-code-agent-loader): guard model parsers against non-string input (fixes #4145)
After the 4.2.0 unified-dispatch refactor (a42f894f / df198d8b / fee515c5 / 989ab717 / dd3fecaf / 1bbe065c / 12bd6580), at least one caller in the new prompt-async-gate path forwards a FallbackModelObject (or some other non-string shape) into parsers that statically claim 'model: string'. The downstream .trim() call then throws 'model.trim is not a function', which rejects the session.processor promise and surfaces as 'Aborted process' + UI 'interrupted'. The issue (#4145) reports this aborts 90% of subagent dispatches across every provider on 4.2.0 + opencode 1.15.4.

This patch adds a 'typeof x !== "string"' runtime guard at the four parser entrypoints called from the dispatch path:

- src/shared/fallback-chain-from-models.ts :: parseVariantFromModel, parseFallbackModelEntry

- src/tools/delegate-task/model-string-parser.ts :: parseVariantFromModelID, parseModelString

- src/shared/model-string-parser.ts (duplicate file with same API) :: parseVariantFromModelID, parseModelString

- src/features/claude-code-agent-loader/claude-model-mapper.ts :: mapClaudeModelString

Each parser now returns undefined / { modelID: "" } for non-string input instead of throwing. This unblocks subagent dispatch and leaves the underlying caller bug for a follow-up.

Regression coverage: three new tests in src/shared/fallback-chain-from-models.test.ts pin the non-string behavior (object, null/undefined, number). Existing 38 tests still pass. Total: 41/41 green, typecheck clean.
2026-05-18 19:22:33 +09:00
LYY 47fced7473 fix: address review findings - git-master identity check, test fixtures, regression strength 2026-05-18 17:17:31 +08:00
LYY 77997d8e74 fix(skill-loader): support unambiguous short skill names 2026-05-18 17:17:31 +08:00
ririnto a163068507 fix(delegate-task): restore hidden plan delegation 2026-05-18 00:53:40 +09:00
YeonGyu-Kim 791fbf3e55 refactor(delegate-task): share buildSyncPromptTools between bootstrap and prompt dispatch
Two call sites built the sync delegate tool gate independently:
sync-prompt-sender's prompt body construction and sync-task's bootstrap
registration. Drift between them would let bootstrap claim one tool set
while the actual prompt sent a different one. Extract buildSyncPromptTools
and route both call sites through it so the registered bootstrap and the
dispatched prompt always agree.
2026-05-17 00:09:11 +09:00
YeonGyu-Kim 982fa81367 fix(delegate-task): start child prompts reliably
Preserve delegated child prompt/bootstrap metadata for early runtime fallback before OpenCode has persisted the first user turn. Bind prompt gate calls to the SDK session receiver and keep completed background task lookup visible across plugin manager instances.
2026-05-16 16:27:56 +09:00
YeonGyu-Kim 5cda8b8fe8 Merge pull request #3330 from codeg-dev/fix/isplan-display-name-getAgentConfigKey
fix(delegate-task): apply getAgentConfigKey normalization to isPlanAgent
2026-05-15 19:57:41 +09:00
YeonGyu-Kim c6054af9fa Merge pull request #3872 from x-x-gpu/dev
fix: pass resolved model to session.create so sub-agent sessions use the correct model
2026-05-15 19:56:09 +09:00
YeonGyu-Kim 5e7ee9418a Merge pull request #3982 from jas32096/fix/category-fallback-ignored-when-primary-set
fix(delegate-task): honor user fallback_models when category primary is unreachable
2026-05-15 19:26:37 +09:00
YeonGyu-Kim 3c7d1299a7 Revert "Merge pull request #3825 from tw-yshuang/fix/delegated-child-session-early-failure-fallback"
This reverts commit cd33f3a397, reversing
changes made to 521c99cf0b.
2026-05-15 19:13:48 +09:00
YeonGyu-Kim cd33f3a397 Merge pull request #3825 from tw-yshuang/fix/delegated-child-session-early-failure-fallback
fix(delegate-task): harden child-session first-prompt fallback recovery
2026-05-15 19:06:43 +09:00
YeonGyu-Kim a02686e729 test(ci): remove suite-order mock coupling 2026-05-15 18:21:04 +09:00
YeonGyu-Kim 462b55efc7 Merge pull request #4040 from code-yeongyu/cleanup/typescript-ai-slop-20260515
Refactor TypeScript cleanup patterns
2026-05-15 16:42:10 +09:00
YeonGyu-Kim b6a0be562d test: remove decorative dividers
Drop section-divider comments that duplicated test group labels without adding behavior context.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-15 16:31:13 +09:00
YeonGyu-Kim 150ccefa05 fix(delegate-task): allow hidden plan task 2026-05-15 16:03:31 +09:00
YeonGyu-Kim c25cb8dcef fix(background-task): clarify task id contracts 2026-05-15 15:41:30 +09:00
YeonGyu-Kim 9f6d0d2281 docs(agents-md): refresh hierarchical knowledge base for v4.1.2
- Bump root AGENTS.md header: 2026-05-14 → 2026-05-15, commit 5ffbe0e2453a740636, release v4.1.1 → v4.1.2
- Update file counts: 2034 (1337+697) → 2041 (1340+701), LOC ~292k → ~294k
- Fix STRUCTURE: openclaw lives at src/openclaw/ (not src/features/); list more accurate feature modules in the parenthetical
- Clarify interactive_bash gate: tmux binary on PATH via isInteractiveBashEnabled() (not 'tmux enabled')
- Fix docs/reference/features.md hook counts: Tool Guard 14→16, Total base 52→54, total with team-mode 59→61
- Bump 'Generated' date on all 43 subdir AGENTS.md files to 2026-05-15
- Preserve promptAsync injection cautions verbatim (per request)
2026-05-15 13:48:11 +09:00
YeonGyu-Kim 1e7a7600a2 docs(agents-md): regenerate hierarchical AGENTS.md knowledge base for v4.1.1
Refresh all AGENTS.md files to reflect codebase state at 5ffbe0e24 (was cd31d2a1a, 197 commits behind).

Key drift corrections across 45 modified + 1 new file:

Root AGENTS.md:
- TS file counts: 1967 -> 2034 in src/ (1337 source + 697 test)
- LOC: 278k -> 292k
- Barrel index.ts: 120 -> 122
- Hook tier composition: 52/59 -> 54/61 (base/with team-mode)
- Tool Guard hooks: 14 -> 16 (add fsync-skip-warning, bash-file-read-guard)
- Add boulder feature, agent-ordering schema, .agents/ directory, v4.1.1 release tag
- Add generated/ directory entry

src/AGENTS.md:
- Subsystem inventory: agents 96->102, hooks 570->581, tools 306->314,
  features 389->400, shared 258->278, cli 150->158, plugin 55->56
- LOC totals refreshed for every subsystem
- Schema files: 32 -> 30

src/hooks/AGENTS.md:
- Tier 2 (Tool Guard): 14 -> 16 hooks, add fsyncSkipWarning row
- Total: 52 base / 59 team-mode -> 54 base / 61 team-mode
- zauc-mocks count: 7 -> 5

src/features/AGENTS.md:
- background-agent: 47 -> 57 files, mention archive fallback
- opencode-skill-loader: 33 -> 30
- tmux-subagent: 34 -> 32

src/plugin/AGENTS.md:
- Tool Guard composer count: 14 -> 16
- Aggregator total: 43 -> 45

src/cli/AGENTS.md:
- Add new boulder subcommand (BoulderState inspector)
- Command count: 6 -> 7

NEW: src/features/boulder-state/AGENTS.md
- Document the new Boulder work tracking feature
- Schema v2 with BoulderState/BoulderWorkState/TaskSessionState
- Lifecycle, storage, integration points with atlas/ralph-loop hooks

All other AGENTS.md files: Generated date 2026-05-08 -> 2026-05-14.
2026-05-14 12:57:46 +09:00
YeonGyu-Kim 95cc9e2d28 [sisyphus-dev] fix(delegate-task): canonicalize agent dedup key to close hidden filter bypass
mergeWithClaudeCodeAgents deduplicated by raw agent.name.toLowerCase() while
matchesRequestedAgent strips invisible characters, the numeric sort prefix,
and wrapper characters via stripAgentListSortPrefix. A project or user agent
named with a zero-width prefix, quote wrappers, or a sort prefix survived as
a visible duplicate of the hidden native build or demoted plan agent and
matched subagent_type="build" or "plan", which let an OMO orchestrator reach
the hidden execution agent the previous filter was meant to block.

Apply the same canonicalization to the dedup key so visible aliases of hidden
server agents collapse onto the hidden entry instead of bypassing the filter.

Adds three regression tests covering ZWSP, quote-wrapper, and sort-prefix
bypass paths.

bun.lock: refresh platform optionalDependencies to 4.1.1 so frozen-lockfile
install succeeds in CI.
2026-05-13 20:31:17 +09:00
MoerAI 4bd81d2cdd fix(delegate-task): exclude hidden agents from task delegation discovery (fixes #3957)
OpenCode injects native execution agents like build (and a demoted plan in OMO mode) as { mode: 'subagent', hidden: true }. The dynamic agent discovery in subagent-discovery.ts only filtered by mode, so a hidden agent still resolved as a callable target via task(). This created a boundary leak: an OMO orchestrator (sisyphus, prometheus, etc.) could delegate work into the hidden native build/plan path instead of the OMO category/skill pipeline.

Add hidden?: boolean to AgentInfo, plumb it through mergeWithClaudeCodeAgents, and skip hidden agents in both findCallableAgentMatch and listCallableAgentNames so hidden natives are neither matched nor advertised in 'Available agents' error messages. The OpenCode SDK Agent type already exposes hidden?: boolean, so no schema work is required.

Verified by adding three regression tests in zauc-mocks-subagent-resolver/subagent-resolver.test.ts: hidden 'build' is rejected, hidden 'plan' is rejected, and hidden agents are excluded from the Available agents list. Full delegate-task suite (395 tests) and call-omo-agent suite (57 tests) pass; bun run typecheck is clean.
2026-05-13 19:37:54 +09:00
Jacob Schechter 711b75345b fix(delegate-task): honor user fallback_models when category primary is unreachable
resolveModelForDelegateTask returned input.userModel immediately without
availability checking when it was set, silently ignoring the user's
configured fallback_models. Effect: a team-mode category member
(e.g. hyperplan's 'artistry' category) configured with

  { model: "opencode/gemini-3.1-pro", fallback_models: [...] }

spawned with the unreachable primary even though a listed fallback was
reachable, leading to a dropped/broken team member instead of graceful
degradation.

Now, when the provider-models cache is warm AND userFallbackModels is
non-empty, the function verifies userModel is reachable via
fuzzyMatchModel. If not, it iterates userFallbackModels and promotes the
first reachable entry. Cold-cache (first-run) behavior is preserved -
the userModel is returned as-is when availability data is unavailable,
matching the existing 'trust the user' contract covered by the
pre-cache test fixtures.

Adds three regression tests covering: (1) unreachable primary + reachable
fallback -> fallback promoted, (2) reachable primary + reachable fallback
-> primary kept (fast path), (3) unreachable primary + unreachable
fallback -> legacy trust-user behavior preserved.
2026-05-12 19:07:54 -05:00
tw-yshuang 12f5233877 merge(dev): resolve latest manager and runtime-fallback conflicts
Sync the PR branch with the newest dev branch and resolve the new import-level conflicts in background-agent manager and runtime-fallback tests. Preserve both the delegated bootstrap coverage from this branch and the newer upstream test utilities and runtime wiring changes, then re-verify the affected delegated fallback suites and typecheck.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-12 22:49:57 +08:00
YeonGyu-Kim c740ed8aca fix(delegate-task): route sync prompts by directory 2026-05-12 18:14:17 +09:00
YeonGyu-Kim d5fbada13d test: make unsafe test coercion explicit
Move test coercion out of a hidden global and require each test to import the helper so review tools and runtime scripts can see the unsafe boundary.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-12 15:51:31 +09:00
YeonGyu-Kim fb135d047c test(tools): remove unsafe test assertions
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-12 15:48:46 +09:00
tw-yshuang 1e1f574b95 merge(dev): resolve latest sync-task conflict for delegated fallback PR
Sync the PR branch with the latest dev branch and resolve the remaining conflict in sync-task.test.ts while preserving both the new upstream poll-recovery coverage and this branch's delegated bootstrap cleanup and isolation coverage. Re-verified the affected delegated fallback suites and typecheck after the merge resolution.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-12 00:37:01 +08:00
YeonGyu-Kim ac9e375d85 fix(delegate-task): align continuation task metadata titles 2026-05-11 12:21:37 +09:00
YeonGyu-Kim 1dc2664e51 Merge pull request #3912 from code-yeongyu/fix/sync-poller-abort-handling
fix(delegate-task): handle abort race in sync session polling
2026-05-11 09:22:35 +09:00
YeonGyu-Kim 8b1696f5e5 fix(delegate-task): prevent stale-text abort recovery 2026-05-11 09:20:14 +09:00
YeonGyu-Kim 8e47d3a166 fix(delegate-task): require anchored text for abort recovery 2026-05-11 09:10:47 +09:00
YeonGyu-Kim e018739d2c fix(delegate-task): recover aborted-operation messages in sync flows 2026-05-11 09:01:17 +09:00
YeonGyu-Kim 468bf25dcb fix(delegate-task): gate continuation recovery to canonical abort errors 2026-05-11 08:53:21 +09:00
YeonGyu-Kim 65913023c5 fix(delegate-task): narrow abort recovery to canonical abort errors 2026-05-11 08:46:14 +09:00