OpenProgram / Provider design / implementation handoff

Request recording and strict offline replay

Design audit baseline: 990bfe36e625579443e1cb01a1b3266c8dbd0e87; lifecycle implementation review: 99252205957a2850e1203a888a0fa0b403b0c3f7. This page defines product entry points, the provider runtime lifecycle, registry wrappers, file safety, strict offline behavior, and verification contracts, with separate design and implementation evidence.

Selected design. Retain the existing RecordingProvider, ReplayProvider and registry transform; add an explicit, thread-safe, process-wide provider runtime lifecycle. Importing openprogram.providers does not register vendor providers, read record_replay settings, open recording files, or install a transform. Registration and activation finish before the first actual provider lookup; openprogram recordings performs management operations only, without entering the runtime lifecycle. Recording is disabled by default; redaction cannot be disabled. Replay never reads credentials, delegates to a live provider, or uses provider fallback.

01 · Goals, non-goals, and security boundaries

Goals

  • Enable complete provider request recording through the product CLI/config.
  • Reproduce multiple provider calls across APIs offline from one file.
  • Write files safely under concurrency, with owner-only permissions and mandatory redaction.
  • Provide scriptable list/show/delete/prune operations.
  • Identify errors by file, line, call, event, or field.
  • Separate provider registration, runtime activation, and recording management into independently callable and verifiable boundaries.

Non-goals

  • Do not record tools, MCP, browser operations, or arbitrary HTTP traffic.
  • Do not define, persist, or restore workflows, Agent DAGs, Sessions, or tool side effects; replay replaces only the LLM provider request/event boundary.
  • Do not define JSONL as a permanently stable public interchange format.
  • Do not perform fuzzy matching across models or prompts.
  • No Web UI entry point in this phase; CLI/config cover the worker first.
  • Do not automatically upload, share, or commit recording files.
  • Do not rewrite the provider plugin protocol, change the recording format, or support runtime hot switching.

Security boundaries

  • “Strict offline” guarantees no network access only at the LLM provider layer.
  • Tools still run under their own permissions during replay; use sandbox/network policy when the entire process must be offline.
  • Redaction handles credentials only; prompts, responses, and tool results may contain private business data.
  • show shows metadata by default; content requires an explicit request.

02 · Current baseline implementation and gaps

CapabilityCurrent evidenceStatusGap
Recording, replay, and redactionrecording.py, replay.pyImplementedTests cover strict v1 JSONL, concurrent writes, mandatory redaction, offline mismatches, and the legacy reader.
Registry transformapi_registry.py::configure_provider_transform()ImplementedCovers existing and subsequently registered providers; permits only one transform per process.
CLI/config and file managementopenprogram recordingsImplementedstatus/record/replay/off/list/show/delete/prune and next-start settings are implemented.
Management-command recoverye8c9f645ImplementedRecording management does not initialize the provider runtime; recovery from a corrupt replay file no longer requires an environment-variable sentinel.
Provider runtime lifecycleinitialization.py, register.pyImplementedVerified explicit NEW/INITIALIZING/READY/FAILED states, concurrent first initialization, redacted failures, atomic auth/API publication, and startup fail-fast behavior.
Concise Markdown referencerecord-replay.md/.zh.mdSynchronizedDocuments the current CLI, strict offline guarantees, and lifecycle implementation evidence.
Implemented lifecycle boundary: providers/__init__.py does not register built-ins, read settings, open recording files, or install a transform. Public provider lookup and Web/worker startup explicitly call initialize_provider_runtime(); recording management operates directly on settings and files, without an environment-variable protocol.

03 · Corresponding design in the reference corpus

The repository reference snapshot contains only references/pi-ai. This section describes that snapshot alone, without claiming coverage of other versions or the entire open-source ecosystem.

ObjectActual mechanismRecording/replay supportOpenProgram decision
references/pi-ai/src/stream.ts stream()/streamSimple() resolves a provider by model.api and calls its methods directly. Absent from the snapshot. The snapshot has no recording/replay module, configuration entry, or recording-file management; stream.ts also has no wrapper hook. Adopt one registry dispatch point; transform providers centrally in the registry instead of editing each vendor module.
references/pi-ai/src/types.ts Shares Model, Context, stream options, and event types. Absent from the snapshot. No recording manifest or replay mismatch type exists. Serialize the existing corresponding Pydantic types; do not create a second request/event domain model.

Rejected approaches: per-vendor recorders, raw HTTP proxy capture, and test mocks as substitutes for product entry points. These duplicate implementation, expose unredacted wire data, or fail to cover actual worker configuration.

04 · Architecture

Module import import openprogram.providers Define and export APIs only; no vendor registration, settings reads, recording-file access, or transform installation Normal execution Actual provider lookup get_api_provider(api) initialize_provider_runtime() NEW → INITIALIZING → READY / FAILED Built-ins → config snapshot → atomic transform Final registry provider Original provider / RecordingProvider / ReplayProvider Management execution openprogram recordings ... Call inspection/config functions directly No provider runtime initialization Diagnose or disable corrupt settings/files next_start Current process lifecycle stays unchanged

Retain

Existing JSONL, strict parser, shared sink/replay, registry transform, next-start settings, management functions, and direct RecordingProvider/ReplayProvider construction in the library API.

Separate

register_builtins() handles provider/auth adapter registration only; initialize_provider_runtime() owns the once-only configuration snapshot and transform. Management commands call neither. They can diagnose corrupt settings or replay files and disable them. Management changes take effect on the next start and do not reset the current process lifecycle.

Add

A shared lifecycle state, concurrent first initialization, cached failures, mandatory initialization before public provider lookup, and explicit startup fail-fast calls in Web/worker.

Reject

No environment-controlled import, per-vendor initialization branches, configuration hot reload, format changes, or provider-runtime dependency in recording management.

05 · CLI and configuration contracts

CLI syntax

openprogram recordings status [--json]
openprogram recordings record [--name NAME]
openprogram recordings replay <ID-or-PATH>
openprogram recordings off
openprogram recordings list [--json]
openprogram recordings show <ID-or-PATH> [--json] [--content]
openprogram recordings delete <ID> [--yes]
openprogram recordings prune --older-than-days N [--dry-run] [--yes]
CommandDefined behaviorExit code
statusShow effective mode, selected file, configuration source, file availability, and restart requirement. Do not read recording content.0 when valid; 1 for invalid configuration.
recordCreate and validate a managed ID; precreate a header-only file with mode 0600, then atomically write mode=record and the selector. If any step fails, remove the newly created empty recording and preserve old settings. Do not restart the worker immediately. When no name is supplied, generate a UTC timestamp with a random suffix.0 only after both file and configuration succeed.
replayStrictly parse the selected file first; on success, atomically write mode=replay and the selector.1 for an invalid file; configuration remains unchanged.
offSet mode to off only; retain the last selector for explicit reuse.0 on success.
list/show/delete/pruneSee §10. Management commands do not change mode.2 for argument errors; 1 for operational errors.

Configuration schema

{
  "record_replay": {
    "mode": "off",          // off | record | replay
    "file": ""              // managed ID or explicit filesystem path
  }
}
SettingSpecType and defaultapplyValidation
record_replay.modeenum, default offnext_startOnly off/record/replay.
record_replay.filetext, empty by defaultnext_startMay be empty when off; empty record selection fails at startup (CLI record generates it first); replay requires a strictly readable file.

openprogram config set can still edit each setting separately; the recommended recordings record/replay/off uses setup.update_config() to write both fields at once, avoiding intermediate states. Settings are read only when initialize_provider_runtime() moves from NEW to INITIALIZING, never after READY or FAILED. Changes require restarting the affected process, which command output must state explicitly. Management commands inspect/update settings without runtime initialization.

Path rules: A selector without path separators is a managed ID in the current profile; a selector containing separators or an absolute path is an explicit path. Recording permits only paths under the managed root, preventing a persistent worker from overwriting project files. replay/show may read explicit files. delete/prune always operate only within the managed root.

06 · Registry wrappers and lifecycle

Import contract

import openprogram.providers only defines Python APIs, exports model APIs, and loads existing static model modules. It must not call register_builtins(), read record_replay settings, open recording files, install a transform, or mutate the credential registry through auth-adapter imports. Isolated subprocess tests verify this contract; comments are insufficient. Removing other existing read-only initialization in model catalog modules is outside this task.

Responsibilities and interfaces

InterfaceResponsibilityProhibited behavior
register_builtins()Resolve built-in providers idempotently and thread-safely; publish API providers in one atomic registry batch; explicitly load existing auth adapters.Do not read record/replay settings, access recording files, or install transforms. Do not silently treat internal import errors as missing optional SDKs.
initialize_provider_runtime()Serialize built-in registration, configuration snapshotting, record/replay preconstruction, and transform publication.Do not resolve credentials, construct vendor clients, or make network requests.
get_api_provider(api)At the public provider lookup boundary, ensure runtime READY before returning the final registry provider.When FAILED, do not return the original provider or bypass recording/replay settings.
create_runtime(...)Ensure provider runtime READY first; off/record retain existing routing, while replay builds a base Runtime from an explicit or non-credential default provider/model.In replay, do not perform CLI/AuthStore detection or construct a subscription runtime that reads credentials.
recordings managementRead/validate files and update next-start settings.Do not call initialize_provider_runtime() or depend on the provider registry.

api_registry retains register_api_provider(api, provider), get_api_provider(api) and a once-only transform. The transform covers registrations made both before and after initialization.

configure_provider_transform(transform)
  - Set once per process; the same value is a no-op, conflicts raise RuntimeError
  - Retain the original provider; do not wrap an already transformed provider again
  - Atomically replace all current registry values
  - Later register_api_provider(api, original) stores transform(api, original) automatically

record:
  shared_sink = RecordingSink(path)
  transform(api, original) -> RecordingProvider(original, shared_sink)

replay:
  shared_replay = ReplayProvider(path)
  transform(api, original) -> shared_replay
  original only confirms that the API is registered; ReplayProvider neither retains it nor delegates to it

All recording wrappers share one sink; all replay APIs share one ReplayProvider, so call_index represents the total order of provider API calls in the process, rather than a separate sequence starting at 0 for each API. Direct library use still supports independent constructors; product activation must not require callers to enumerate APIs.

Process-wide state

NEW
  └─ initialize_provider_runtime() ─→ INITIALIZING
       ├─ success ─→ READY
       └─ any incomplete exit ─→ FAILED (immutable failure descriptor)

Visibility of built-in registration

register_builtins() imports and validates built-in modules under its own lock, builds a local API-provider batch, and publishes it once through the registry. Failure before publication leaves the API registry unchanged; mark registered only after complete success. Anthropic/Codex/Gemini auth adapters retain their idempotent registration functions, moved from package import to this explicit phase. If an auth adapter fails, the provider runtime enters FAILED; public get_api_provider() cannot observe or use published providers because of the lifecycle gate. A process restart rebuilds them. Anthropic/OpenAI/Google SDKs are core dependencies, so wrapping the entire provider import in except ImportError must no longer hide internal defects.

1
Resolve profile
Reuse existing CLI/worker profile resolution; the lifecycle does not reinterpret it.
2
Public entry requests a provider
get_api_provider(api) first calls initialize_provider_runtime(); Web/worker may call it explicitly before starting threads to report failures early.
3
Register built-ins
register_builtins() is itself thread-safe; mark registration successful only when complete, and do not permanently retain partial state after errors.
4
Read settings once and preconstruct
off installs no transform; record creates a shared sink; replay fully parses the file and creates a shared replay provider.
5
Publish atomically and handle calls
The registry returns the final provider; resolve credentials only when requires_credentials != False.

Explicit startup and shared guarantees

Web and worker explicitly call initialize_provider_runtime() before starting recovery threads, dispatchers, or provider warm-up threads, so invalid replay is reported during single-threaded startup. Public get_api_provider() still performs an idempotent check, covering Python library calls and future entry points. Lazy auth-adapter registration calls only register_builtins(); a corrupt replay file cannot cause it to fail.

Runtime construction and credential boundary

Strict offline behavior must cover create_runtime(), not just stream.py. The current factory and subscription constructors read API keys/OAuth before get_api_provider(). The target does not refactor live runtimes: off/record retain the existing factory; replay adds a credential-free branch accepting explicit provider/model choices, or AGENTIC_PROVIDER/AGENTIC_MODEL and the existing non-credential selection in configuration default_provider/default_model. Without a selection, immediately return a replay configuration error; do not proceed to CLI or AuthStore detection.

The replay factory does not construct a subscription runtime. It uses pure provider-to-model-namespace metadata from PROVIDERS to construct a base Runtime. Plain providers already have this field; add model_namespace: openai-codex→openai-codex, gemini-cli→gemini-subscription to the subscription entries. API-routed providers retain their model-catalog namespace. This branch does not infer the original factory provider from the recording: v1 requests store only the wire-level Model, which does not encode the original runtime factory choice. Nor can the first model in a multi-API file define all subsequent runtime identities. Once a request enters ReplayProvider, existing full request comparison validates the final Model, context, tools, and options; mismatches use the existing ReplayMismatch diagnostic.

Scope isolation: A parallel auth-account-management refactor exists in the main workspace. This task does not modify the three subscription runtimes or credential APIs; the replay factory bypasses them. Implementation uses an isolated worktree; integration must recheck the final registry call locations.

Relationship to the OpenProgram execution model

record/replay supports provider testing and failure reproduction, not workflow definition. Agent loops, Runtime retries, tools, Session persistence, and DAG state execute normally; only the registry provider changes from live/record to ReplayProvider. Replay can therefore verify upper-layer behavior against the same model-event sequence, but it does not restore historical Sessions, replay tool side effects, roll back files, or define execution steps.

07 · Recording files, strict parsing, and concurrent writes

Format policy

New writers continue to emit format_version=1 and the existing four line types.call_end.outcome is optional diagnostic metadata: absence means complete, preserving compatibility with old v1 files and readers. It does not change event models or request matching. Headers may gain optional metadata; v1 readers must ignore unknown header fields. Bump the version only when required request/event fields or semantics change.

{"type":"header","format_version":1,
 "recording_id":"20260811T134502Z-f7a29c1d",
 "created_at":"2026-08-11T13:45:02Z","redaction_version":1}
{"type":"request","call_index":0,"model":{...},"context":{...},"options":{...}}
{"type":"event","call_index":0,"event_index":0,"event":{...}}
{"type":"call_end","call_index":0,"event_count":1,"outcome":"complete"}

recording_id, created_at and redaction_version support management and diagnostics only, not request comparison. Old v1 files without these fields remain replayable; list/show derive missing information from stat and content.

Strict-reader invariants

File level

  • The first nonempty line must be the only header.
  • Every line must be a JSON object; errors include the line number.
  • format_version must be a supported integer.
  • Accept only header/request/event/call_end.

Call level

  • Each request has a unique call_index, consecutive from 0.
  • Events must reference an existing, unfinished call.
  • event_index is consecutive from 0.
  • Each request has exactly one call_end.

Completion level

  • event_count equals the actual event count.
  • outcome accepts only complete/error/cancelled/abandoned; missing values default to complete for compatibility.
  • No more events for a call after call_end.
  • Unknown event types fail during provider construction, not midway through replay.
  • Reject empty files, truncated final lines, and orphan lines.

Request level

  • Apply the same redaction version to incoming requests before comparison.
  • Compare model/context/options in that order.
  • Preserve call, field, recorded, and incoming in differences.
  • Reject calls beyond the recording; never fall back to a live provider.

Concurrent-write contract

  1. RecordingSink holds a process-local threading.RLock; serialize and append each JSONL line within the same critical section.
  2. Each append opens the data file with os.open(O_WRONLY | O_CREAT | O_APPEND, 0o600) and uses openprogram._compat.flock(fd, LOCK_EX) for interprocess exclusion.
  3. Create the initial header and allocate the next call_index under the file lock. The minimal implementation may scan the maximum request index at begin_call: accept O(n) allocation on this diagnostic path, adding a sidecar counter only if measurements show large files are a bottleneck.
  4. Write a complete UTF-8 JSON record plus newline using a os.write loop; do not assume one write completes it.
  5. Do not force fsync after each request/event append; fsync after call_end. A crash may leave an incomplete call that the strict parser detects.
  6. Events may interleave across threads/processes; call_index from event_index groups each call completely. Replay order follows request call_index.
Known limit: Concurrent request start order depends on scheduling. Recording guarantees file integrity, not deterministic scheduling. Tests requiring deterministic replay should issue provider calls serially. Add explicit request correlation only if reproducing concurrent scheduling becomes necessary.

08 · 0700/0600, path constraints, and redaction

Filesystem

Redaction contract

Content risk: Credential redaction is not content anonymization. Prompts, responses, tool results, file excerpts, and personal information remain. Documentation, CLI help, and the notice before show --content must explain this.

09 · Strict offline replay contract

Structural constraints enforce replay isolation; it does not depend on callers voluntarily avoiding network access.

  1. The replay transform returns the same ReplayProvider.
  2. ReplayProvider retains no original provider, imports no vendor transport, and offers no fallback.
  3. stream.py must obtain the provider first; when the provider declares requires_credentials = False, do not call resolve_provider_key().
  4. Fully parse and validate the file before transform installation; corrupt files block worker startup rather than failing midway through startup.
  5. Unknown APIs still produce the registry missing-provider error; never dynamically load live providers for replay.
  6. Request mismatches, exhausted recordings, unknown events, and event-validation failures raise directly; no failure may switch to a live provider.

Tests replace both socket.socket.connect, socket.create_connection and shared HTTP-client constructors with failing sentinels, asserting no network attempt on successful replay, mismatch, corrupt-file, and exhaustion paths.

10 · Recording-file management

CommandDefault output/behaviorSafety rules
listID, created_at, format version, call/event counts, integrity, bytes, and active marker; newest first.--json emits stable fields.A corrupt file shows invalid and a brief error without blocking other entries; no request content is printed.
showBy default, parse and show header, statistics, each call’s model provider/api/id, event count, and completion status.--content is required to print the complete redacted JSONL.Print a risk notice to stderr before content reaches stdout; do not mix notices into JSON output.
deleteDelete one managed ID. A TTY requires typing the complete ID by default; without a TTY or --yes, exit 2.Reject active selectors, external paths, directories, and symlinks; deletion is irreversible.
pruneDelete managed files older than N days using stat mtime; --dry-run lists candidates only. Output matched/deleted/failed/bytes.N must be a positive integer; skip active files, invalid symlinks, and files holding an exclusive lock. Without --yes, request TTY confirmation or exit 2 in non-TTY mode.

list/show use the same pure inspect_recording(path) function, and replay activation uses the same strict parser. Do not add a permissive management parser. prune uses stat mtime for age; header created_at is display-only, preventing header edits from changing retention.

11 · Failure semantics

PhaseConditionException/CLI behaviorMay continue?
Built-in registrationVendor import failure, auth-adapter registration failure, or aborted batch publicationRuntime enters FAILED and stores an immutable failure descriptor (stage="builtins"); each caller receives a fresh ProviderRuntimeInitializationError with consistent fields; wake every waiter; never return the original provider.Management commands may continue
Record/replay activationUnknown mode, empty file, external record path, or missing/corrupt/unsupported replay fileStructured error log; atomically replace the registry transform with a fail-closed _BlockedRecordReplayProvider; runtime READY with snapshot.mode == "blocked". Every provider call raises the same diagnostic, directing the user to openprogram recordings status/off; no credential resolution or network access occurs.Diagnostics only
Control-flow exitInitializing thread receives KeyboardInterrupt/SystemExitEnter FAILED and wake waiters; initializer rethrows the original control exception, other callers receive initialization_interrupted; only a process restart permits retry.Management commands may continue
CreationExisting filename, symlink, unwritable directory, or permissions that cannot be tightenedRecordingFileError; do not overwrite existing files.No
WritingLock failure, full disk, or serialization failureStop the current provider call and retain written data; do not merely log and continue live execution.No
Live providerStartup/midstream failure, cancellation, or consumer closing the generator earlyIn finally, write call_end with outcome and close the source generator, then preserve the original exception/cancellation semantics. The whole file remains parseable. Replay validates the request first and reports interruption only when that call is consumed; counting then allows retry against the next recorded call.Per call
ParsingInvalid JSON, version, ordering, count, or event typeRecordingFileError(path, line, call_index, reason).No
MatchingIncoming differs from recordedRetain existing ReplayMismatch fields; CLI/Web error chains show call and field.No
ExhaustionIncoming call exceeds recorded callsReplayMismatch(field_path="call_index").No
UnderconsumptionProcess/test ends with unconsumed recorded callsRetain assert_consumed(); one-shot/program/test entry points call it at normal completion and fail if needed. A long-lived worker shows consumed/total in status without declaring an error prematurely.Per entry point
Management deletionSome file deletions failReport each file; prune continues with the remainder, then exits 1.Yes

12 · Compatibility and migration rules

13 · Minimal implementation files

FileMinimal changeReason for reuse
openprogram/providers/initialization.pyAdd runtime state, Condition, once-only built-in registration, configuration snapshot, transform activation, and failure propagation.Lifecycle coordination stays separate from recording format and registry storage.
openprogram/providers/register.pyMake register_builtins() thread-safe and mark success only after complete execution.Keep the existing vendor-registration list; do not duplicate it in the lifecycle module.
openprogram/providers/api_registry.pyget_api_provider() ensures runtime READY before registry lookup; retain existing atomic transform publication.The common boundary for every actual API-provider lookup.
openprogram/providers/registry.pyAdd pure model_namespace metadata to the subscription entries; create_runtime() obtains a lifecycle snapshot first and adds a credential-free base Runtime branch only for replay.Retain live factory, subscription runtime, and credential behavior for off/record.
openprogram/providers/__init__.pyRemove built-in registration and record/replay activation calls; retain exports only.Eliminate package-import effects on runtime state and the filesystem.
openprogram/providers/recording.pyKeep format and management functions; invoke activation explicitly through the lifecycle, no longer during import.Do not relocate stable recording/replay logic.
openprogram/auth/credential_provider.pyReplace side-effect provider imports with explicit register_builtins().Auth needs adapter registration only, not replay activation.
apps/server/openprogram_server/server.pyExplicitly initialize provider runtime before starting threads.Preserve single-threaded preloading and expose its failure boundary as an explicit API.
openprogram/worker/runner.pyIn start_web(), provider warm-up, and channel threads are preceded by explicit initialization.Worker startup consistently fails fast on invalid replay configuration; background threads may not initiate first initialization independently.
openprogram/cli/__init__.pyRemove the recording environment-variable sentinel; keep direct management-function dispatch.Module boundaries guarantee management recovery.
tests/component/providers/registry/test_provider_initialization.pyAdd import-purity, state-machine, concurrency, failure-atomicity, and auth/Web boundary tests.Separate lifecycle tests from format and CLI tests.
tests/component/providers/registry/test_record_replay_cli.pyAdd real subprocess recovery cases for status/off with missing, corrupt, and unsupported-version files.Verify user recovery entries; do not substitute unit mocks for startup behavior.

Do not change vendor providers, off/record live factories, Web routes, Node CLI, or the recording format. Add only the replay branch to the runtime factory. Calls bypassing get_api_provider() or plugins bypassing register_api_provider() must return to the shared boundary; do not add vendor-specific cases in the recorder or lifecycle module.

14 · Acceptance and test matrix

DimensionCaseKey assertions
Import contractAn isolated subprocess executes only import openprogram.providersNo config read, recording open, vendor SDK/auth-adapter import, or API-registry mutation.
First initializationNo settings / mode off / record / replayProcess built-ins and settings once; after READY, preserve provider identity, credential-resolver counts, and existing behavior.
Concurrent initializationMultiple threads first call get_api_provider()Only one initializer; others receive the same READY provider or FAILED cause, with no deadlock.
Failure atomicityInject exceptions in built-in registration, config reading, ReplayProvider construction, and transform publicationNo original provider returned, credential lookup, or network-client construction; no partially published transform.
Entry-point consistencyWeb startup, worker, public stream, direct library lookup, and auth-adapter loadingActual provider use ensures READY; Web/worker fail fast before threads; auth registers built-ins without replay activation.
RegistryRegistration before/after wrapping, repeated configuration, two APIsTransform existing and later entries; reject conflicting transforms; recording wrappers share a sink, replay shares call_count.
Concurrent threadsTwo threads record multiple calls/events eachEvery line is valid JSON; call_index is unique and consecutive; each event_index is consecutive; call_end counts are correct.
Concurrent processesTwo processes write one managed fileOne header, no partial lines or duplicate call_index; strict parsing passes.
Errors and cancellationProvider exception, task cancellation, consumer aclose(), synchronous startup failurePreserve control flow; close the source generator; write correct call_end outcome/event_count; preserve whole-file parseability; replay fails at the matching call without corrupting later counts.
Activation failureMissing/corrupt replay file, unknown mode, invalid record selectorApplication initialization does not raise; runtime READY, snapshot.mode == "blocked"; provider calls fail closed without credentials/network, and management commands can recover.
Replay countingA request mismatches, then is corrected and retriedMismatch does not increment call_count; compare the corrected request against the same recorded call. Only success or a recorded interruption consumes it.
PermissionsNew directories/files/locks, existing broad-permission directories, managed legacy 0644 files, explicit external 0644 filesPOSIX 0700/0600; record and managed replay may tighten permissions; external replay validates and rejects broad permissions without chmod.
Paths../, absolute record paths, symlinks, directories, external deletionrecord/delete/prune reject escapes; replay/show may read explicit external files.
RedactionCase-varied fields, nested values, compound token/key/secret/password suffixes, common auth schemes, URL userinfo/query, ordinary textCredential bytes never appear in files; non-credential text such as token_count remains; record/replay use the same rule version.
Strict formatEmpty file, invalid JSON, duplicate header, unknown line, orphan event, index gap, duplicate end, wrong count, unknown eventReport path/line/call/reason when constructing ReplayProvider.
Strict offline behaviorSuccessful, mismatch, exhaustion, and corrupt-file replay pathsNo socket/HTTP-client sentinel or credential-resolver call; no live fallback.
Runtime factoryExplicit provider/model, non-credential defaults, missing defaults, plain/subscription providersReplay uses the entry’s model_namespace without importing/constructing runtime_class, CLI/AuthStore detection, or credential resolution; ReplayProvider still strictly compares the final wire-level Model.
CLI configurationrecord/replay/off/status, invalid selectors, concurrent config writesAtomic update; no config change on failure; restart notice; profile isolation; no runtime initialization.
Recovery commandsstatus/off with missing, corrupt, or unsupported-version replay filesReal subprocess starts; status reports a stable diagnostic; off updates settings; no environment sentinel required.
Managementmixed valid/invalid list, metadata show, content show, active delete, dry-run prune, partial failureStable JSON schema; content hidden by default; active files protected; correct counts and exit codes.
Legacy filesHeader-only v1 metadata generated by current testsValid files still replay; structurally corrupt legacy files fail new strict checks.
Existing loopMulti-turn tool-loop record → replayEvent types, tool execution, and final message match current tests.

Minimum post-implementation verification commands

pytest -q tests/component/providers/registry/test_provider_initialization.py tests/component/providers/registry/test_record_replay.py tests/component/providers/registry/test_record_replay_registry.py tests/component/providers/registry/test_record_replay_cli.py
  pytest -q tests/component/providers/adapters/test_scripted_provider.py tests/component/providers/registry/test_registry_from_config.py tests/unit/runtime/test_usage_stream_chokepoint.py tests/unit/providers/auth/test_auth_methods.py tests/unit/webui/test_web_config_schema.py tests/component/config/test_config_write_safety.py
python -m openprogram recordings --help
python -m openprogram config get record_replay.mode
python -m scripts.docs_site.build
python -m scripts.docs_site.checklinks
git diff --check

15 · Implementation and verification record

Status
Scope
Evidence (design baseline 990bfe36; implementation review 99252205)
Implemented
Shares RecordingSink writes one v1 JSONL with thread locks, interprocess flock, complete os.write and call_end, and fsync; extends mandatory redaction and enforces 0700/0600 plus symlink/regular-file checks.
recording.py::RecordingSink, paths.py::get_recordings_dir; a three-process spawn test strictly parses 15 consecutive calls.
Implemented
A once-only registry transform covers existing and later providers; recording shares a sink, replay shares one prevalidated provider.
api_registry.py::configure_provider_transform, recording.py::activate_record_replay_from_config, test_record_replay_registry.py.
Implemented
The strict parser validates headers, versions, line types, call/event indices, call_end/count, and event models at construction. Replay has no original provider/fallback; both stream entries select the provider before skipping credential resolution.
replay.py::read_recording_file, ReplayProvider.requires_credentials, stream.py; structural-failure, credential-sentinel, and multi-turn tool-loop tests.
Implemented
record_replay.mode/file are next_start settings. CLI provides status/record/replay/off/list/show/delete/prune. Failed configuration rolls back new files; destructive commands protect active files, symlinks, external paths, locks, and non-TTY confirmation.
config_schema.py, cli/__init__.py, recording.py and CLI/management tests.
Temporary fix superseded
Recording management neither imports nor initializes provider runtime; with corrupt or missing replay files, status/off directly recovers configuration. The environment-variable sentinel has been removed.
e8c9f645, test_off_recovers_from_a_replay_file_that_became_invalid and import-side-effect subprocess tests.
Implemented
Explicit provider lifecycle, side-effect-free package import, thread-safe first initialization, stable FAILED propagation for built-in registration errors, and fail-closed blocked providers for record/replay activation errors while runtime remains READY (snapshot.mode="blocked"), with auth/recording/runtime separation and read-only model resolution in replay.
4d82d485..99252205; specification re-review PASS, quality re-review PASS; committed state tests/unit + tests/providers is recorded in the delivery report.
Reliability revision implemented
Exceptions, cancellation, early close, and synchronous startup failure write one outcome-bearing call_end and close the source. Stop after the first terminal event; preserve source-close errors. Activation failure atomically replaces the existing registry transform with a fail-closed provider. Mismatches do not consume calls; matched interrupted calls consume once and report the interruption.
c26df53a, a4f27b3b, fe727546, 6595d444; public-entry RED/GREEN, specification re-review PASS, quality re-review PASS.
Compatibility boundary
Retain v1 constructors, attributes, exceptions, old headers, and mismatch behavior; stricter checks reject corrupt lines ignored by old readers. Strict offline guarantees remain limited to LLM providers; interprocess scheduling order is not guaranteed reproducible.
test_record_replay.py continues to cover library recording, two-turn tool loops, version rejection, and field differences.
Explicit exclusions
Web UI, process-wide HTTP recording, tool/MCP recording, fuzzy request matching, automatic network fallback, automatic upload, and Windows-specific implementation/validation.
Outside this phase.
Verification completed
Relevant pytest, complete unit/providers, changed-file Ruff, docs build, link checker, CLI smoke, and whitespace diff checks.
Repository-root pytest is separately blocked during integration collection by the existing missing module openprogram.programs.workflow.test_framework; this change does not modify that entry.

Design sources: current OpenProgram provider implementation, CLI/config entries, tests, and the in-repository references/pi-ai snapshot. Implementation-status updates must cite code symbols, tests, or commits; a written design is not an implemented capability.