Files
openprose__prose/packages/std/patterns/fallback-chain.prose.md
irl-dan 4bc41a93bb launch readiness: green CI publish path, front-door, taxonomy migration
Get the Reactor packages mergeable + publishable and the launch surfaces coherent.

CI / publish (ci-reactor-package.yml):
- Drop the deleted reactor-cradle from the workflow and remove the obsolete .mjs
  release-gate suite (.github/scripts/*reactor*.mjs + tests) entirely.
- Add per-package pack + publish jobs for @openprose/reactor, @openprose/reactor-cli,
  and @openprose/reactor-devtools (idempotent, version-from-package.json,
  reactor-v* tag-gated, provenance). The two CLI packages now have a release path.
- Fix the dangling cradle reference in tools/cli build-release-tarball.mjs;
  regenerate pnpm-lock.yaml.

Install / first-run:
- reactor-cli: @openprose/reactor moved peer -> dependency (a global install now
  pulls the SDK); @openai/agents + zod become optional peers (keyless install stays light).
- SDK README: replace non-existent *V0 imports with the real exports
  (verifyReceipt / LedgerReceipt / inspectReceiptProof / projectReceiptProof).
- CLI README + http-server comment: correct the trigger route to POST /trigger/<node>.

Front-door + taxonomy:
- Promote the Reactor-forward launch README; add the technical report at
  docs/reactor/v0.1/report.md (replacing the stale v0.1).
- Migrate SKILL.md and all packages/std + packages/co contracts off the retired
  taxonomy (kind: service -> function, kind: system deleted, ### Ensures -> ### Maintains,
  ### Criteria/### Services folded) onto the Reactor model.

Prune the dead cradle-importing examples: drop flat-tokens and
release-readiness/reactor-package-example (keeping release-readiness/src, which is tested).

Gates: build, test:reactor:offline, test:examples (10/0), test:skill (252/252) all green offline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:45:39 -07:00

3.6 KiB

name, kind
name kind
fallback-chain pattern

Fallback Chain

Try delegate A. If it fails, try B. If B fails, try C. Ordered list of fallbacks with decreasing preference.

Metadata

  • version: 0.1.0
  • role: coordinator

Slots

  • chain

Config

  • failure_criteria (string, default: none): Optional description of result-level failure conditions

Invariants

  • Chain entries run sequentially in declared preference order
  • Each delegate receives the original brief, not failure context from earlier attempts
  • The pattern stops immediately on the first success
  • If every delegate fails, the result is null and failure history includes every attempt

Shape

  • self: try each delegate in order, return first success, stop on success
  • delegates:
    • fallback_1..fallback_N: attempt the task
  • prohibited: trying the next fallback when the current one succeeded

Parameters

  • Pattern instance receives: chain: string[] -- ordered list of delegate names (first = most preferred) task_brief: string -- the task (same brief goes to each attempt) failure_criteria: string -- (optional) declarative description of what constitutes failure. Default: only thrown errors count as failure.

Returns

  • result: the winning result, or null
  • winner: the winning delegate name, or null
  • attempts: number of delegates tried
  • failure_history: reasons for each failed attempt

Delegates were tried sequentially in chain order, each receiving the ORIGINAL brief with no failure context from prior attempts. The returned result is the first successful result, returned immediately with no further delegates tried; if every delegate failed, result and winner are null and failure_history records the reason for every attempt.

Delegation

let failure_history = []

for delegate in chain:
  try:
    let candidate_result = call delegate
      task_brief: task_brief

    if failure_criteria says candidate_result is a failure:
      record { delegate: delegate, reason: "matched failure_criteria" } in failure_history
      continue

    return {
      result: candidate_result,
      winner: delegate,
      attempts: "number of attempted delegates",
      failure_history: failure_history
    }
  catch as error:
    record { delegate: delegate, reason: error } in failure_history

return {
  result: null,
  winner: null,
  attempts: chain.length,
  failure_history: failure_history
}

Notes

Each delegate receives the original brief with no modification. Unlike retry-with-learning, fallback-chain does not pass failure context between attempts — each delegate gets a clean start. The assumption is that different delegates have different capabilities, not that the same delegate needs better instructions.

The chain order expresses preference. Put the best, most capable, or cheapest delegate first. Later delegates are fallbacks for when preferred options fail.

Different from retry-with-learning: retry retries the SAME service with enriched failure context. Fallback-chain tries DIFFERENT services with the original brief. A search service that returned no results should be retried with broader terms (retry-with-learning). A search service that is down should be replaced with an alternative (fallback-chain).

Different from race: race tries all candidates simultaneously. Fallback-chain tries them sequentially, only advancing on failure. Use fallback-chain when later candidates are expensive and should only run if cheaper ones fail. Use race when all candidates are worth trying in parallel.