Runtime
Reliable Orchestration of an OpenAI-Backed Daily Brief Workflow
Report summary
InternationalIntelligence.org should treat the OpenAI Responses API as a subordinate asynchronous execution service , not as the authority for the Daily Brief’s publication state. The publication system’s own durable supervisor—implemented in its database and advanced through compare-and-swap transi
Key topics
- Runtime
- Privacy
- Semantic Systems
- Research Archive
- Strategy
- Audit
- Architecture
- Governance
Research provenance
For citation, use the report title and canonical URL. Archival presence does not establish authorship or promote report statements into portfolio evidence.
Source availability: 48 citation markers in the source export have no recoverable source links. Those markers are omitted from this reader; any supplied bibliography and ordinary links remain. Check the original sources before relying on the cited claims.
This page renders the archived Markdown as safe, formatted HTML. It is background research and does not become a portfolio claim without evidence review.
Full report
On this page
Executive Recommendation
InternationalIntelligence.org should treat the OpenAI Responses API as a subordinate asynchronous execution service, not as the authority for the Daily Brief’s publication state. The publication system’s own durable supervisor—implemented in its database and advanced through compare-and-swap transitions—must remain the sole authority for process identity, revision, stage, accepted evidence, composition eligibility, and publication readiness.
The supplied project brief correctly reframes the problem from basic API connectivity to distributed-workflow correctness: the essential challenge is whether the site can create, persist, retrieve, validate, reconcile, consume, retry, and clean up provider operations without duplicate jobs, lost results, stale-worker commits, or indefinite stalls.
The recommended architecture has the following defining properties:
| Requirement | Recommended rule |
|---|---|
| State authority | The local supervisor owns the Daily Brief state. Provider statuses are observations about one subordinate operation. |
| Active-operation limit | At most one locally authorized provider operation may exist for the current process revision and stage. |
| Creation safety | Commit an immutable request contract and pending-create outbox record before issuing the provider POST. |
| Duplicate prevention | Use a stable local fingerprint, a database uniqueness constraint, an operation generation, and a fencing token. |
| Ambiguous POST handling | A create timeout after transmission becomes CREATE_ACCEPTANCE_UNKNOWN; do not automatically issue a replacement POST. |
| Polling | Poll only when a durable next_poll_at has arrived and a worker owns a valid lease. Browser requests remain read-only. |
| Completion | A provider completed status is not success. Output, schema, evidence, citations, editorial constraints, and stage invariants must all pass locally. |
| Commit | Accept a stage result through one compare-and-swap database transaction, exactly once. |
| Retry | Retry only after classifying whether the prior operation definitely failed, may still exist, or reached a provider terminal state. |
| Evidence | Copy required source and citation evidence into local durable storage before provider deletion. |
| Degraded mode | Keep the last verified edition visibly labeled as the last verified edition; expose a delayed-publication state and never fabricate a replacement. |
| Operations | Use bounded, auditable commands such as “reconcile current operation,” “request cancellation,” and “authorize replacement generation,” never generic “run again.” |
The core invariant should be expressed directly in code, database constraints, tests, and operator procedures:
No provider response may publish, advance, overwrite, or invalidate a Daily Brief unless it is attached to the current process ID, expected revision, current stage, live operation generation, and valid fencing token, and its result passes the stage’s local acceptance contract.
Scope and key questions
This report assumes no access to the site’s source code, private prompts, credentials, provider response bodies, account identifiers, or hosting environment. It therefore specifies an implementation-neutral PHP production design based on documented OpenAI behavior and conservative distributed-systems assumptions.
The key questions are:
- What does the current OpenAI platform officially guarantee for background Responses, retrieval, statuses, web-search evidence, structured outputs, request correlation, cancellation, deletion, webhooks, and retries?
- Which workflow properties must InternationalIntelligence.org implement locally because the provider does not document them?
- How should the system handle an API POST that may have succeeded even though the client did not receive the response identifier?
- How can research, supplemental research, and composition be made independently retryable without losing accepted work?
- What validation, cost, privacy, and operational controls are required before the workflow can be trusted for unattended publication?
The recommended delivery priority is:
- Build the local supervisor, immutable contracts, operation reservations, and compare-and-swap transitions.
- Make ambiguous creation a first-class state.
- Add deterministic provider fixtures and crash-point testing.
- Implement evidence-preserving research and composition contracts.
- Add polling, webhooks, cancellation, and deletion only after the authority model is correct.
- Run isolated live probes before connecting the orchestrator to publication state.
Official OpenAI Capability Baseline and Recent Developments
Current capability summary
The following findings were checked against current official OpenAI documentation on August 1, 2026. “Documented” means the behavior appears in the official API reference or platform guide. “Engineering consequence” is this report’s recommendation and is not an OpenAI guarantee.
| Capability | Officially documented finding, verified August 1, 2026 | Engineering consequence |
|---|---|---|
| Responses API | The Responses API creates response objects whose output can contain messages, tool calls, reasoning items, and other item types. Response objects are retrievable by ID. | Do not assume output[0] is the final message. Iterate and type-check every output item. |
| Background mode | Setting background: true starts asynchronous execution. The client retrieves the response object and polls while its status is queued or in_progress; leaving those states is terminal for the provider operation. | Persist the returned provider ID before scheduling any poll. Provider terminality is distinct from local acceptance. |
| Response statuses | The documented response-status enum is queued, in_progress, completed, incomplete, failed, and cancelled. | Map all six statuses explicitly. Unknown future statuses must fail closed into quarantine, not be treated as success. |
| Retrieval | A response can be retrieved with GET /v1/responses/{response_id}. Official background examples poll the response by ID. | A provider ID is a critical durable identifier, but not an authority token. |
| Cancellation | The platform documents POST /v1/responses/{response_id}/cancel for cancelling a background response. | Cancellation is a request that can race with completion. Always retrieve again before deciding the local outcome. |
| Deletion | The API documents DELETE /v1/responses/{response_id} and returns a deletion result. | Delete only after evidence, output, usage, and incident-correlation data required by local policy have been preserved. |
| Web search | Web-search output can contain a web_search_call item and a message whose text includes URL-citation annotations. The action can describe search, page opening, or text finding. | Research acceptance must require both usable message data and independently inspectable tool/source evidence. |
| Full source list | The web-search guide documents a sources collection and the include: ["web_search_call.action.sources"] option, which can expose consulted sources beyond inline citations. | Store source evidence separately from the generated candidate JSON. Inline citations alone are insufficient for auditability. |
| Citation presentation | OpenAI’s web-search guide says citations presented to end users should be visible and clickable. | Preserve citation annotations and URL/title relationships through research, composition, rendering, and localization. |
| Structured Outputs | The Responses API supports JSON Schema through text.format, with type: "json_schema" and strict: true; supported strict schemas use a subset of JSON Schema. | Use strict provider schemas, then run a separate local schema validator. Do not equate schema conformity with editorial correctness. |
| Incomplete output | Official examples check for response.status === "incomplete" and inspect incomplete_details, including output-token exhaustion. | Treat truncation as a provider terminal result requiring controlled replacement, not as parseable partial success. |
| Refusals and absent messages | Official Structured Outputs examples inspect message items, distinguish refusals, and handle missing parsed output rather than assuming a completed response contains usable JSON. | “Completed” means execution ended, not that the publication contract was satisfied. |
| Tool-choice controls | The current Responses reference documents required tool selection and allowed-tool controls. It also documents a max_tool_calls limit applying across built-in tool calls. | Primary research can require web search and cap built-in calls. Composition should omit tools or explicitly disallow them. |
| Request identifiers | OpenAI returns an x-request-id for API requests and recommends logging it. Clients may send an X-Client-Request-Id, an ASCII value up to 512 characters, for correlation; OpenAI documents it as useful when a timeout prevents receipt of the server request ID. | Use both IDs for diagnostics. Neither should be treated as a documented create-idempotency key. |
| Metadata | Responses support bounded string metadata fields attached to an object. | Include only non-sensitive correlation tags. Do not depend on metadata to recover an unknown response ID. |
| Response listing/search | The current Responses endpoint index documents create, retrieve, delete, input-item listing, input-token counting, cancellation, and compaction, but no general response-list or response-search endpoint. This is an inference from the documented endpoint surface, not a promise that no internal capability exists. | Never design ambiguous-POST recovery around “find the response by fingerprint” unless OpenAI later documents such an endpoint. |
| Create idempotency | The current official materials consulted document request correlation but do not document an idempotency guarantee for POST /v1/responses. | Treat create as a potentially non-idempotent external side effect. A repeated POST may create duplicate billable work. |
| Webhooks | OpenAI documents response-completion webhooks, signature verification, and retrieval of the response by the ID in the event. | A webhook is a notification, not a stage commit. Persist it, deduplicate it, and run the same fenced reconciliation path used by polling. |
| Webhook retries and duplicates | Failed webhook delivery can be retried for up to 72 hours with exponential backoff, and duplicate events can occur; the webhook ID can be used for deduplication. | Webhook processing must be at-least-once safe and tolerate old events arriving after a process revision has advanced. |
| Error classes | Official documentation identifies authentication, authorization/region, rate-limit or quota, server, and overload classes, including HTTP 401, 403, 429, 500, and 503. | Map protocol errors to durable workflow decisions; never collapse them into one generic “API failed” state. |
| Rate-limit retry | OpenAI recommends honoring Retry-After where present, otherwise using exponential backoff with jitter and bounded attempts; failed requests can count against rate limits. | Persist the provider’s retry eligibility, use one retry controller, and open a circuit breaker during storms. |
| Storage and retention | The current data-control documentation states that Responses have a default application-state retention period and that background processing requires temporary storage for polling; exact compatibility with an organization’s retention configuration must be checked against its current data-control settings. | InternationalIntelligence.org must not use provider retention as its evidence archive. Copy required evidence locally before cleanup. |
| Forward compatibility | OpenAI states that backward-compatible API changes can add fields and that opaque identifier formats may change. | Reject unknown fields inside the publication payload schema, but tolerate unknown top-level provider fields in the transport decoder. Never parse meaning from ID prefixes. |
Recent capability timeline
timeline
title OpenAI capabilities relevant to the Daily Brief workflow
2024-08-06 : Structured Outputs announced
: Exact schema adherence introduced for supported strict schemas
2025-03-11 : Responses API introduced
: Built-in web search introduced with the new API
2025-05-21 : Background mode added to Responses
: Longer-running asynchronous work became directly retrievable
2026-08-01 : Current documentation baseline verified
: Retrieve, cancel, delete, webhooks, citations, request IDs, and current status handling reviewed
OpenAI announced Structured Outputs on August 6, 2024, while explicitly noting that schema correctness does not eliminate mistakes within field values. The Responses API and built-in web search were announced on March 11, 2025, and background mode was announced among additional Responses capabilities on May 21, 2025.
Actors and trust boundaries
| Actor | Legitimate authority | Must not be allowed to do |
|---|---|---|
| Daily Brief supervisor | Own process ID, revision, target date, stage, accepted artifacts, publication eligibility, and terminal outcome | Delegate publication authority to a provider status |
| Scheduler or cron | Find eligible local work and attempt to acquire a lease | Unconditionally create or poll on every invocation |
| Provider-operation worker | Execute one fenced external action for one reserved operation | Commit after its lease or process revision becomes stale |
| OpenAI Responses API | Execute the submitted response operation and report provider status/output | Advance the publication workflow directly |
| Web-search tool | Return search actions, source evidence, and citations | Define which events are editorially acceptable |
| Webhook receiver | Authenticate, deduplicate, and durably record notifications | Perform publication in the HTTP request thread |
| Database/outbox | Preserve authoritative transitions, uniqueness, leases, and audit records | Contain credentials, full prompts, or unrestricted raw provider bodies in ordinary logs |
| Operator | Approve bounded recovery actions under audit | Trigger an unconstrained “run everything again” action |
| Public browser | Read bounded status and published content | Create, poll, cancel, reconcile, or delete provider work |
| Publisher/rendering layer | Publish only a locally committed and approved edition | Read provider output directly as publishable content |
Documented guarantees versus local obligations
The provider documents mechanisms for creating, retrieving, cancelling, deleting, and receiving completion notifications for responses. It does not thereby guarantee exactly-once job creation, exactly-once webhook delivery, exactly-once local consumption, recovery of an unknown response ID after an ambiguous POST, editorial usefulness, evidence sufficiency, bilingual parity, or preservation of accepted research across retries. Those are application-level obligations.
The appropriate methodology is therefore a combination of:
- immutable command contracts;
- a transactional outbox;
- database-enforced uniqueness;
- leases with fencing tokens;
- compare-and-swap revision transitions;
- explicit ambiguous-outcome states;
- idempotent result consumption;
- source-evidence validation;
- reconciliation instead of blind replay;
- deterministic fault injection;
- bounded operator actions.
Authority Model and Durable Provider Lifecycle
Supervisor state model
A Daily Brief process should have one durable supervisor row, for example:
daily_brief_process
process_id
target_date
locale_set
revision
stage
stage_status
active_operation_id
accepted_research_revision
accepted_evidence_digest
composition_revision
publication_status
health_code
last_meaningful_progress_at
next_action_code
created_at
updated_at
Recommended process stages are:
RESEARCH_PRIMARY
RESEARCH_ASSESS
RESEARCH_SUPPLEMENTAL
RESEARCH_ACCEPTED
COMPOSITION
COMPOSITION_VALIDATE
READY_FOR_EDITORIAL
READY_TO_PUBLISH
PUBLISHED
DELAYED
QUARANTINED
ABANDONED
DELAYED and QUARANTINED should be overlays or explicit states with a preserved resumable stage. They must not erase accepted research.
A provider operation belongs to one stage attempt:
provider_operation
operation_id
process_id
expected_process_revision
stage_code
operation_generation
request_fingerprint
contract_version
request_payload_digest
provider_response_id_encrypted_or_restricted
provider_state
local_state
create_attempt_count
poll_attempt_count
validation_attempt_count
worker_fence
lease_owner
lease_expires_at
create_started_at
provider_accepted_at
last_polled_at
next_poll_at
terminal_observed_at
result_digest
result_commit_key
cancel_requested_at
delete_requested_at
quarantine_reason
cost_ceiling
token_ceiling
The process row answers, “What is the publication doing?” The operation row answers, “What happened to this one external execution?” A provider operation must never answer the first question by itself.
Core invariants
The database should enforce these invariants wherever its engine permits:
| Invariant | Enforcement |
|---|---|
| One active operation for the current stage | Partial unique index on active operations by process_id, expected_process_revision, and stage_code; otherwise a reservation table with a unique key |
| No duplicate logical request | Unique key on process_id, revision, stage, contract version, fingerprint, and operation generation |
| Monotonic process revision | Every stage transition uses UPDATE ... WHERE process_id=? AND revision=? AND stage=? |
| Stale worker cannot commit | Every operation mutation checks the current fencing token and expected process revision |
| One local result commit | Unique result_commit_key plus an atomic artifact-insert/process-advance transaction |
| Provider ID cannot silently move | Provider ID is immutable after first durable attachment; a conflicting ID quarantines the operation |
| Publication requires validated artifacts | Database-level publication precondition or service-layer transaction checks evidence and composition acceptance records |
| Cleanup cannot precede preservation | Deletion eligibility depends on a durable evidence_preserved_at and terminal commit or abandonment record |
Request fingerprint and reservation design
A request fingerprint must identify the semantic and operational contract, not incidental JSON formatting. Compute it from a canonical serialization of:
process_id
target_date
expected_process_revision
stage_code
contract_version
model_policy_version
prompt_template_version or prompt digest
schema_version
canonical evidence-input digest
tool configuration
allowed domains, if any
maximum tool calls
input-token ceiling
maximum output tokens
language requirements
editorial policy version
cost ceiling
Use a construction such as:
request_fingerprint =
SHA-256(
"daily-brief-response-v1" ||
canonical_json(immutable_contract)
)
The canonicalizer must define UTF-8 normalization, object-key ordering, numeric formatting, array ordering, null treatment, and line-ending normalization. Do not include worker ID, start time, attempt number, transport timeout, or provider request ID in the fingerprint; those describe execution, not the requested result.
operation_generation distinguishes an explicitly authorized replacement from the same logical request. Generation zero is the first creation. Generation one is permitted only after generation zero is conclusively terminal, safely abandoned under policy, or overridden by an audited operator action. The fingerprint stays stable; the generation changes.
Before the network call, durably record:
| Field | Purpose |
|---|---|
| Process ID and suffix | Associate external work with one Daily Brief |
| Stage | Prevent a research response from being consumed as composition |
| Expected revision | Reject workers and results from superseded process state |
| Request fingerprint | Deduplicate the logical contract |
| Contract version | Make validation reproducible |
| Operation generation | Distinguish an authorized replacement |
| Attempt number | Bound transport attempts |
| Creation start time | Detect stuck or ambiguous creates |
| Worker identity and fence | Reject stale completion |
| Client request ID | Correlate with OpenAI support and local logs |
| Cost ceiling | Prevent retries from exceeding the process budget |
| Payload digest | Detect mutation between reservation and POST |
| Redacted request summary | Support operations without retaining the prompt |
The X-Client-Request-Id should be derived from a random operation identifier plus generation, not from private text. OpenAI documents it as a correlation aid, including for timeouts, but not as a create-idempotency mechanism.
Suggested bounded provider metadata, where supported by the current request schema, is:
{
"workflow": "daily_brief",
"process_suffix": "7F3A91",
"stage": "research_primary",
"revision": "12",
"operation_generation": "0",
"fingerprint_prefix": "b42a1e5d",
"contract_version": "research-2026-08"
}
Do not place target article text, private prompts, full process IDs, account identifiers, sensitive URLs, or personal information in metadata. Although metadata may aid interpretation of a response that is later discovered, the current documented Responses endpoint surface does not provide a general lookup-by-metadata operation, so it cannot be the primary ambiguous-creation recovery mechanism.
Complete provider lifecycle
The table below defines the required treatment of every lifecycle step. Codes are illustrative bounded enums.
| Lifecycle step | Local preconditions | External call | Principal ambiguity | Required durable write and idempotency | Stale-worker check and recovery | Public representation | Private diagnostic |
|---|---|---|---|---|---|---|---|
| Build immutable stage contract | Current process/revision/stage; accepted inputs frozen | None | Input may change while being assembled | Store canonical contract, schema version, evidence digest, token/tool/cost ceilings; immutable after reservation | Re-read process revision before reservation; discard draft if changed | PREPARING | CONTRACT_BUILT, digests, versions |
| Compute fingerprint | Canonical contract complete | None | Different serialization could create false differences | Store SHA-256 fingerprint and canonicalizer version | Recompute and compare before dispatch; quarantine on mismatch | PREPARING | FINGERPRINT_COMPUTED |
| Reserve operation | No live operation for current revision/stage | None | At-least-once scheduler may race | Transactionally insert operation and attach it to process; unique active-operation constraint | Compare process ID, revision, stage, and active slot | RESERVED | OP_RESERVED, fence |
| Persist pending create | Reservation valid and budget available | None | Crash before or after network call | Insert outbox/pending-create row in same transaction as reservation | Outbox consumer checks fence and revision | CREATE_PENDING | OUTBOX_READY |
| Create provider response | Valid lease; pending create; no provider ID; create eligibility reached | POST /v1/responses with background mode | Provider may accept while response to client is lost | Before call write CREATE_STARTED, client request ID, timestamps, attempt; after clear success write provider ID and observed status atomically | Re-check fence after call before attachment; stale result is quarantined, not attached to current process | SUBMITTING | HTTP class, x-request-id, timing, redacted cURL result |
| Persist accepted state | Response ID returned and reservation still current | None | Crash after response received but before commit | Store provider ID once, accepted time, provider status, next poll time; immutable ID | If current process changed, store as orphan/quarantined operation | QUEUED or PROCESSING | PROVIDER_ID_ATTACHED |
| Poll when eligible | Provider ID; state queued/in-progress; due time; valid lease; not quarantined | GET /v1/responses/{id} | Timeout leaves status unknown but does not create a new job | Store poll start, result, next eligibility, request ID; poll key by operation and sequence | Check fence before call and before applying result; stale poll may update restricted operation history but not process state | QUEUED, PROCESSING, or DELAYED | POLL_OK, POLL_TIMEOUT, provider status |
| Interpret status | Retrieved object belongs to expected ID | None | New or unknown status may appear in future | Map all known statuses; unknown values become quarantined transport records | Verify operation remains active for current process before scheduling next action | Bounded provider-state code | STATUS_UNKNOWN with redacted snapshot digest |
| Retrieve output and sources | Terminal provider state or completion webhook | Usually same retrieval GET; optionally input-item/source retrieval documented for relevant tool output | Completed object may lack usable message, sources, or citation annotations | Preserve normalized provider envelope digest, output items, usage, source evidence, and citation graph in restricted storage | Old operation can preserve evidence but cannot feed current stage without operator-approved reconciliation | VALIDATING | Counts and digests, not raw public logs |
| Validate strict local contract | Evidence copied; correct contract/schema available | None | Strict provider schema may still contain unusable facts or unsupported claims | Write immutable validation report with every rule outcome | Validation keyed to operation ID, fingerprint, contract version, and result digest | VALIDATING, EVIDENCE_DEFICIT, or OUTPUT_REJECTED | Rule-level failure codes |
| Commit result exactly once | Validation accepted; operation current; process revision/stage unchanged | None | Duplicate worker or crash during commit | Single transaction inserts accepted artifact, marks operation consumed, advances process revision, and writes event; unique commit key | Compare-and-swap process revision and worker fence | Next stage code | RESULT_COMMITTED |
| Preserve evidence before cleanup | Provider output accepted or incident retention required | None | Provider object may later expire or be deleted | Copy source URLs/titles/dates, citation mappings, hashes, candidate records, validation report, and minimum diagnostic identifiers | Evidence records are versioned and immutable | Evidence counts only | EVIDENCE_PRESERVED |
| Cancel or delete | Cancellation/deletion policy satisfied; no concurrent commit | Cancel POST or delete request | Cancellation may race with completion; deletion may erase unretrieved evidence | Record intent before call and result after; use one cancellation/deletion command per operation generation | Retrieve/reconcile after cancel; deletion blocked without evidence-preservation flag | CANCELLING, CANCELLED, or unchanged published state | CANCEL_REQUESTED, DELETE_CONFIRMED |
| Record bounded audit event | Every meaningful transition | None | Logs can leak secrets or become unbounded | Append structured event with enums, IDs or suffixes, hashes, timestamps, actor, and transition result | Events reference process revision and operation fence | Selected bounded fields | Full authorized correlation fields, redacted by policy |
Normal completion sequence
sequenceDiagram
participant C as Cron/Scheduler
participant S as Local Supervisor
participant D as Database/Outbox
participant W as Fenced Worker
participant O as OpenAI Responses
participant V as Local Validator
C->>S: Find eligible process
S->>D: Reserve operation under revision R
D-->>S: Operation O, fence F
S->>D: Persist immutable contract and pending-create
W->>D: Acquire lease for O/F
W->>O: POST background response
O-->>W: response_id + queued/in_progress
W->>D: Attach response_id, set next_poll_at
loop Only when eligible
W->>D: Acquire poll lease and verify R/F
W->>O: GET response_id
O-->>W: queued/in_progress/completed
W->>D: Persist observation and next eligibility
end
W->>O: GET final response if needed
O-->>W: output + tool/source evidence
W->>D: Preserve output and evidence
W->>V: Validate schema, claims, citations, stage rules
V-->>W: Accepted
W->>D: CAS commit under R/F and advance revision
D-->>W: Exactly-once commit succeeded
Stale-worker rejection
sequenceDiagram
participant W1 as Old Worker
participant W2 as New Worker
participant D as Database
participant O as OpenAI
participant S as Supervisor
W1->>D: Acquire lease with fence 41
W1->>O: GET response
Note over W1,O: W1 is delayed
S->>D: Advance or replace operation
D-->>S: New fence 42
W2->>D: Acquire current lease, fence 42
W1->>D: Attempt to persist or commit with fence 41
D-->>W1: Rejected as stale
W1->>D: Record bounded stale-worker event
W2->>D: Continue current reconciliation
Crash after provider completion
sequenceDiagram
participant W1 as Worker Before Crash
participant O as OpenAI
participant D as Database
participant W2 as Recovery Worker
participant V as Validator
W1->>O: GET response
O-->>W1: completed + output
W1->>D: Persist terminal observation and raw-artifact digest
Note over W1: Process crashes before stage commit
W2->>D: Acquire new fenced lease
W2->>D: Read completed, unconsumed operation
W2->>O: Retrieve again only if required artifacts absent
W2->>D: Preserve missing evidence
W2->>V: Run deterministic validation
V-->>W2: Accepted
W2->>D: CAS exactly-once result commit
Ambiguity, Polling, Retry, and Reconciliation
Ambiguous create-POST analysis
The most dangerous failure is:
- the local worker sends
POST /v1/responses; - OpenAI accepts and creates background work;
- the client times out or loses the connection before receiving the response ID.
The local system cannot safely conclude either that the operation exists or that it does not exist. Because the current documented Responses API does not expose a general response-list or search-by-metadata endpoint, and because the official request-ID mechanism is documented for correlation rather than create idempotency, the application must not invent an automatic lookup or blindly repeat the POST.
What can be recovered
| Mechanism | What it can do | What it cannot safely do |
|---|---|---|
x-request-id | Correlate a response when the server header was received | Help when the header itself was lost |
X-Client-Request-Id | Correlate local logs with OpenAI support when a timeout prevented receipt of the server request ID | Prove that no provider response was created; prevent duplicate creation |
| Stable fingerprint | Detect an attempted duplicate inside the local system | Locate an unknown response through an undocumented provider query |
| Provider metadata | Help identify a response after its ID becomes known | Reliably find an unknown response without a documented list/search endpoint |
| Outbox record | Prove that the local system intended and began one creation | Prove whether the remote server accepted it |
| Webhook | Potentially reveal a completed response ID later, after signature verification and deduplication | Guarantee arrival, immediate delivery, or simple correlation to the unknown operation |
| Logs | Establish timing, bytes sent, transport phase, request IDs, and worker identity | Convert an ambiguous network result into proof of non-creation |
| Operator reconciliation | Escalate with the client request ID; wait for a webhook; inspect permitted account tooling; authorize a replacement | Eliminate the possibility of an orphan if the provider offers no discoverable record |
| Cancellation | Stop work once the response ID is known | Cancel an unidentified response |
| Safe abandonment | Prevent the uncertain operation from influencing current publication state | Prevent unidentified provider work from incurring already-started cost |
Required policy
A create attempt should enter one of three outcome classes:
| Outcome class | Examples | Replacement POST policy |
|---|---|---|
| Definitely not dispatched | Local contract failure, budget rejection, database failure before network call; reliably detected DNS/connect failure before request bytes could be sent | May retry the same generation under the existing reservation |
| Provider response identified | Successful create response includes a provider response ID | Poll/reconcile that ID; never create a second live operation for the stage |
| Acceptance unknown | Timeout after connection, broken connection after possible body transmission, malformed or truncated success response, process crash during POST, or uncertain 5xx path | Do not automatically create a replacement; enter CREATE_ACCEPTANCE_UNKNOWN |
For CREATE_ACCEPTANCE_UNKNOWN:
- Freeze the active-operation slot.
- Record the transport phase, elapsed time, cURL error class, client request ID, payload digest, worker fence, and create-start timestamp.
- Wait through a configurable reconciliation window.
- Accept a valid signed webhook that identifies a response and can be safely correlated.
- Permit an operator to request reconciliation, which schedules a fenced local action but does not create work.
- Escalate to OpenAI support with
X-Client-Request-Idwhen warranted. - After the maximum ambiguity age, move to
SAFE_ABANDONED_UNKNOWNor retain quarantine. - Create generation
n+1only through a separate policy decision that acknowledges possible duplicate cost and prevents generationnfrom ever committing to the current process. - If the old response later appears, preserve the diagnostic event and quarantine or delete it after safe evidence handling; never let it become a second authority.
This policy trades some availability for protection against duplicate cost and conflicting results. That is appropriate for an unattended publication workflow whose source material must remain auditable.
Ambiguous POST sequence
sequenceDiagram
participant W as Worker
participant D as Local Database
participant O as OpenAI
participant H as Webhook Receiver
participant R as Reconciler
participant P as Operator
W->>D: Persist pending-create, fingerprint, client request ID
W->>O: POST background response
O--xW: Connection lost after possible acceptance
W->>D: Mark CREATE_ACCEPTANCE_UNKNOWN
D-->>W: Block replacement creation
alt Signed webhook later arrives
O-->>H: response.completed with response ID
H->>D: Deduplicate and store event
R->>D: Acquire fenced reconciliation lease
R->>O: GET response ID
O-->>R: Response object
R->>D: Correlate or quarantine
else No response ID becomes discoverable
P->>D: Request bounded reconciliation
R->>D: Inspect logs, age, client request ID
R-->>P: Still ambiguous
P->>D: Authorize safe abandonment/replacement generation
D->>D: Fence old generation; reserve generation n+1
end
Polling policy
OpenAI’s guide demonstrates polling while a response is queued or in_progress. The guide’s example cadence is illustrative; production cadence, ownership, jitter, age limits, and duplicate prevention remain application responsibilities.
Recommended policy:
| Parameter | Research operation | Composition operation | Rationale |
|---|---|---|---|
| Initial delay after accepted create | 5 seconds | 3 seconds | Avoid immediate duplicate GET after create |
| Minimum cadence | 5 seconds | 5 seconds | Prevent tight loops |
| Backoff sequence without progress | 5, 10, 20, 40, 60 seconds | 5, 10, 20, 40, 60 seconds | Bounded load |
| Maximum cadence | 60 seconds | 60 seconds | Preserve eventual observation without excessive delay |
| Jitter | Random ±20%, persisted in next_poll_at | Same | Desynchronize multiple processes |
| State-change behavior | Reset next delay to 10 seconds after meaningful state change | Same | Observe active progress more closely |
| Default maximum response age | 30 minutes | 20 minutes | Engineering default; tune from measured production latency |
| Polls per worker cycle | Exactly one | Exactly one | Prevent loops monopolizing PHP worker time |
| Poll lease | 30 seconds, renewable only before network call | Same | Bound ownership |
| No-progress warning | 10 minutes | 7 minutes | Expose delay before hard age limit |
| Hard terminal policy | Request cancellation, then quarantine/reconcile | Same | Do not create a replacement while the old operation may still run |
A response is poll-eligible only when all of the following are true:
provider_response_id is present
provider_state is queued or in_progress
local_state is not quarantined, consumed, deleted, or terminally abandoned
now >= next_poll_at
process_id and expected_revision still match the active supervisor
operation_id is still the supervisor's active operation
cost and age limits have not been exceeded
no valid poll lease is held
no cancellation transition is currently being reconciled
The worker must:
- atomically acquire a lease and increment the fencing token;
- re-read process revision and active operation;
- write a
POLL_STARTEDevent; - perform at most one provider GET;
- write the observation and a durable next eligibility time;
- release or let the lease expire;
- never call the provider again in the same cycle merely because the response remains queued.
A browser request must only read a materialized public-status projection. It must not create an outbox command, acquire a workflow lease, issue a provider GET, or invoke reconciliation.
An operator’s “reconcile” action should only create a unique local command such as:
RECONCILE_OPERATION(process_id, revision, operation_id, requested_reason)
The scheduler consumes that command under the ordinary lease and fencing rules. Repeated clicks deduplicate against the command’s unique active key.
Cancellation/completion race
The cancellation endpoint is documented, but asynchronous cancellation can race with ordinary completion. The local system should not decide the stage result solely from the HTTP result of the cancellation call.
sequenceDiagram
participant P as Operator/Policy
participant D as Database
participant W as Worker
participant O as OpenAI
participant V as Validator
P->>D: Persist CANCEL_REQUESTED
W->>D: Acquire cancellation lease and verify fence
W->>O: POST cancel response_id
par Provider may complete
O->>O: Finish response
and Cancellation may apply
O->>O: Process cancellation
end
O-->>W: Cancellation-call result
W->>O: GET response_id for authoritative observed state
O-->>W: completed or cancelled/other terminal status
alt completed and operation still locally eligible
W->>D: Preserve result and evidence
W->>V: Validate
V-->>W: Accepted or rejected
W->>D: CAS commit only if process still allows it
else cancelled or locally superseded
W->>D: Record terminal cancellation/quarantine
end
Retry and reconciliation matrix
The values below are recommended production defaults, not provider guarantees. “Attempt” means a bounded attempt of that specific action, not a new provider response unless explicitly stated.
| Condition | Classification and action | Attempts, backoff, next eligibility | May create a new response? Duplicate prevention | Public / private code | Terminal condition and required event |
|---|---|---|---|---|---|
| DNS failure | Transport failure before connection; retry create or retrieval if client confirms no request transmission | 3 attempts: 5s, 20s, 60s with ±20% jitter | Same reserved generation only; no new reservation | PROVIDER_UNREACHABLE / NET_DNS | Terminal for current cycle after 3; NETWORK_RETRY_EXHAUSTED |
| TLS failure | Configuration/security failure; stop and alert | 1 automatic attempt; next eligibility operator-controlled | No | PROVIDER_SECURITY_ERROR / NET_TLS_VERIFY | Quarantine until certificate/CA issue corrected; TLS_FAILURE |
| Connection failure | Retry only when transport layer establishes request bytes were not sent | 3 attempts: 5s, 20s, 60s | Same reservation; otherwise classify as ambiguous | PROVIDER_UNREACHABLE / NET_CONNECT | Exhaustion produces delayed state and CONNECT_RETRY_EXHAUSTED |
| Client timeout before headers | Potentially ambiguous create; retrieval GET can safely be repeated | Create: one attempt enters ambiguity. GET: up to 5 retries | Create replacement prohibited; GET allowed for known ID | SUBMISSION_UNCERTAIN / POST_TIMEOUT_PRE_HEADERS | Create enters CREATE_ACCEPTANCE_UNKNOWN; event records transport phase |
| Client timeout after possible provider acceptance | Ambiguous external side effect; reconcile/quarantine | No automatic create retry; reconciliation at 1, 5, 15 minutes, then hourly until age limit | Only audited new generation after safe-abandonment decision | SUBMISSION_UNCERTAIN / POST_ACCEPTANCE_UNKNOWN | SAFE_ABANDONED_UNKNOWN or attached discovered response; event required |
| HTTP 400 | Contract/configuration error; stop automatic retries | 1 | Only after contract/configuration changes and new revision or contract version | REQUEST_INVALID / provider code plus schema/payload digest | Terminal operation; CREATE_REJECTED_400 |
| Authentication failure | Credentials/configuration incident | 1, then circuit open | No | PROVIDER_AUTH_ERROR / HTTP_401_AUTH | Terminal until credentials repaired; AUTH_FAILURE |
| Authorization failure | Access, region, project, or policy incident | 1, then operator action | No | PROVIDER_ACCESS_ERROR / HTTP_403_AUTHZ | Terminal until entitlement/configuration changes; AUTHZ_FAILURE |
| Model access failure | Configuration/model-policy failure | 1 | No silent model fallback; new operation only after approved model-policy revision | MODEL_UNAVAILABLE / MODEL_ACCESS_DENIED | Quarantine; MODEL_POLICY_FAILURE |
| Tool access failure | Research contract cannot be satisfied | 1 | No tool-free research fallback; retry after entitlement/tool policy corrected | RESEARCH_TOOL_UNAVAILABLE / WEB_SEARCH_ACCESS_DENIED | Research stage blocked; TOOL_ACCESS_FAILURE |
| Rate limit | Retryable capacity condition unless documentation/error says quota or billing action required | Honor Retry-After; otherwise 10s, 30s, 90s, 5m; maximum 4 per action and 15m total | Same known GET/cancel action; create retry only if prior rejection is unambiguous | PROVIDER_THROTTLED / HTTP_429_RATE | Open circuit after budget; RATE_LIMIT_EXHAUSTED |
| Quota, billing, or spend limit | Non-transient account condition | 1 | No | PROVIDER_BUDGET_BLOCKED / HTTP_429_QUOTA | Operator/account action required; QUOTA_BLOCK |
| Provider 5xx with complete error response | Provider fault; for GET retry; for POST conservatively assess ambiguity | GET: 5s, 20s, 60s, 3m, 10m. POST: at most one replay only if transmission and non-creation are established; otherwise ambiguity | New response normally prohibited until reconciled | PROVIDER_ERROR / HTTP_5XX | Circuit opens after bounded window; PROVIDER_5XX_EXHAUSTED |
| Background response queued | Normal nonterminal state | Next poll in persisted 5–10s, then backoff | No | QUEUED / RESP_QUEUED | Age limit or provider transition; PROVIDER_STATE_OBSERVED |
| Background response processing | Normal nonterminal state | Next poll in 10–60s according to schedule | No | PROCESSING / RESP_IN_PROGRESS | Age limit or provider transition; event only on meaningful change |
| Response older than allowed age | Stalled/over-age | Request cancellation once; reconcile after 5s, 30s, 2m | Not until old generation terminal or safely abandoned | PROVIDER_STALLED / MAX_RESPONSE_AGE | Quarantine after cancel/reconciliation budget; AGE_LIMIT_EXCEEDED |
| Completed with missing output | Provider terminal, local validation failure | Retrieve once more after 5s only to rule out transient retrieval inconsistency; then reject | Replacement generation allowed if attempt budget remains | OUTPUT_UNUSABLE / COMPLETED_NO_MESSAGE | Rejected operation; VALIDATION_MISSING_OUTPUT |
| Completed with invalid structured output | Local contract failure | No reparse loop; one deterministic parse and schema report | New generation allowed within stage-attempt budget | OUTPUT_INVALID / SCHEMA_VALIDATION_FAILED | Reject and preserve validation report |
| Research with too few usable sources | Editorial/evidence deficit | Create supplemental research, not full primary replay; maximum 2 supplemental rounds | Yes, as a new supplemental-stage operation with deficit-specific fingerprint | EVIDENCE_DEFICIT / SOURCE_COUNT_OR_QUALITY_DEFICIT | Operator review after supplemental budget; RESEARCH_DEFICIT_RECORDED |
| Composition with unsupported claims | Semantic validation failure | No publication; retry composition with explicit validation feedback, maximum 2 replacements | Yes, composition-only; accepted research remains immutable | COMPOSITION_REJECTED / UNSUPPORTED_CLAIM | Quarantine after attempt budget; validation event with claim IDs |
| Cancellation racing with completion | Reconciliation race | Cancel once; immediately retrieve, then at 5s and 30s if still nonterminal | No | CANCELLING / CANCEL_COMPLETION_RACE | Accept valid completion only if still locally eligible; otherwise quarantine |
| Local crash after provider completion | Recoverable local interruption | New worker resumes from durable terminal observation; retrieve only if evidence absent | No | RECOVERING / CRASH_AFTER_TERMINAL_OBSERVATION | Exactly-once commit or deterministic rejection; RECOVERY_RESUMED |
| Provider ID attached to old process revision | Stale result | Preserve restricted record; do not consume | No for old revision; current revision follows its own reservation | STALE_RESULT_IGNORED / PROVIDER_ID_REVISION_MISMATCH | Quarantined orphan; STALE_PROVIDER_RESULT |
| Provider completes after operator quarantine | Late terminal result | Retrieve only if incident/evidence policy requires; never auto-unquarantine | No automatic replacement interaction | QUARANTINED / LATE_COMPLETION_AFTER_QUARANTINE | Operator may inspect; event records no-commit decision |
| Provider response deleted before evidence extraction | Irrecoverable evidence loss | Stop; do not infer output from logs | New research generation only under explicit recovery policy | EVIDENCE_LOST / DELETED_BEFORE_PRESERVE | Terminal incident; PREMATURE_DELETE |
| Repeated polls with no meaningful state change | Stalled but not yet terminal | Increase to 60s maximum cadence; emit one warning, not one per poll | No | PROCESSING_DELAYED / NO_PROGRESS_WINDOW | Age limit triggers cancellation/quarantine; summarized event |
Provider status failed | Provider terminal failure | Classify error; no more polling | Replacement allowed if failure is retryable and process budget permits | PROVIDER_FAILED / RESP_FAILED_<CODE> | Terminal operation; PROVIDER_TERMINAL_FAILURE |
Provider status incomplete | Provider terminal incomplete result | Inspect incomplete_details; reject partial publication payload | Replacement allowed with adjusted bounded output/input contract | OUTPUT_INCOMPLETE / RESP_INCOMPLETE_<REASON> | Terminal operation; preserve reason and validation event |
Provider status cancelled | Provider terminal cancellation | Stop polling; reconcile local cancellation intent | Replacement only if current process still needs the stage | CANCELLED / RESP_CANCELLED | Terminal operation; PROVIDER_CANCELLED |
| Unknown provider status | Forward-compatibility condition | No retry loop based on guesses; quarantine and alert | No until code supports the status | PROVIDER_STATE_UNKNOWN / raw enum hash or bounded value | Operator/software update required; UNKNOWN_PROVIDER_STATUS |
| Duplicate webhook | Expected at-least-once notification | Acknowledge after dedupe; no repeated retrieval if already reconciled | No | No public change / WEBHOOK_DUPLICATE | Dedupe event by webhook ID |
| Webhook older than current revision | Stale notification | Authenticate, store minimal event, reject workflow effect | No | No public change / WEBHOOK_STALE_REVISION | STALE_WEBHOOK_IGNORED |
OpenAI recommends honoring Retry-After, otherwise using bounded exponential backoff with jitter, and warns that failed requests can consume rate-limit capacity. The application should therefore use one durable retry controller rather than stacking SDK retries, PHP wrapper retries, cron retries, and proxy retries.
Stage Contracts and Validation
Why staged work is more recoverable
A single “research the world, choose stories, write both languages, attach citations, and publish” response has one large failure domain. A late composition defect can force expensive research repetition; partial evidence cannot be safely retained; source deficiencies are difficult to distinguish from prose defects; and a retry may select an entirely different event set.
The staged model creates durable checkpoints:
| Design | Recovery characteristics |
|---|---|
| One giant request | Any failure can invalidate all work; retries repeat web search and composition; difficult to distinguish research, evidence, schema, and language failures |
| Primary research → supplemental research → composition | Accepted candidates survive composition failure; supplemental work targets measured deficits; composition retries consume only validated local evidence; each stage has a smaller schema and cost ceiling |
| Provider-linked chain using prior response state as sole memory | Recovery depends on provider retention and opaque prior state |
| Locally materialized stage artifacts | Every stage can be reconstructed, validated, versioned, and replayed independently |
The strongest design does not rely on previous_response_id as the only connection between stages. Instead, the system materializes validated research locally and supplies a bounded evidence package to composition.
Primary-research contract
The primary-research request should satisfy all of the following:
| Contract dimension | Requirement |
|---|---|
| Purpose | Discover and characterize candidate events; do not produce publication prose |
| Tool policy | Web search configured and required; maximum built-in tool calls explicitly bounded where supported |
| Output format | Strict JSON Schema |
| Candidate count | Minimum target and hard maximum, for example 8–16 candidates |
| Event identity | Model emits a proposed canonical event key; server assigns the durable local candidate ID |
| Claims | Atomic claim records with stable claim IDs |
| Sources | Explicit source records and claim-to-source references |
| Evidence | Web-search tool items, consulted-source list, and URL-citation annotations preserved |
| Time scope | Explicit target date and allowable chronology window |
| Geography/topics | Requested coverage dimensions and exclusions encoded in the contract |
| Publication prose | Prohibited |
| Unsupported entries | Rejectable independently without invalidating all otherwise valid candidates |
| Tool-call ceiling | For example, no more than 12 built-in calls, subject to model/tool support |
| Output-token ceiling | For example, 10,000–12,000 tokens; tune from measured candidate volume |
| Unknown fields | Disallowed inside the stage schema |
| External events | Candidate IDs cannot be fabricated as references to unpublished prior local state |
Illustrative schema shape:
{
"contract_version": "primary-research-2026-08",
"target_date": "YYYY-MM-DD",
"candidates": [
{
"proposed_event_key": "canonical-short-key",
"event_date": "YYYY-MM-DD",
"chronology_precision": "day",
"headline_fact": "Neutral factual description, not publication prose",
"regions": ["region-code"],
"topics": ["topic-code"],
"claims": [
{
"claim_id": "claim-local-within-candidate",
"claim": "One independently verifiable proposition",
"source_refs": ["src-1"],
"support_type": "direct"
}
],
"sources": [
{
"source_ref": "src-1",
"title": "Source title",
"publisher": "Publisher",
"url": "https://example.invalid/",
"published_at": "YYYY-MM-DD",
"source_type": "primary"
}
],
"selection_signals": {
"international_significance": "high",
"novelty": "medium",
"corroboration": "multiple_sources"
}
}
]
}
The server—not the model—should assign a stable candidate_id after normalization, for example from a process-scoped canonical event key plus collision-safe sequence. A model-provided identifier is input data, not a database authority.
A primary-research response passes only if:
- at least one usable
web_search_callis present; - required source details were retrieved through documented source inclusion or citation annotations;
- each accepted claim maps to at least one retrieved source;
- candidate and tool-call ceilings were respected;
- the strict local schema passes;
- every candidate is independently accept/rejectable;
- no publication-ready English or Spanish prose appears in fields intended only for neutral evidence.
The OpenAI web-search guide documents both tool-call output and URL-citation annotations, as well as inclusion of a broader source list.
Supplemental-research contract
Supplemental research must be a delta operation, not an implicit restart.
Its input includes:
accepted candidate IDs and evidence digests
rejected candidate IDs and rejection reasons
explicit deficit vector
remaining candidate/source/tool/cost budget
target date and unchanged editorial policy
Recommended deficit codes:
| Deficit code | Meaning | Permitted supplemental action |
|---|---|---|
REGION_GAP | Required geographic distribution is not met | Search only for the specified missing region or rebalance candidates |
CORROBORATION_GAP | A retained candidate lacks sufficient independent support | Search for corroboration or authoritative primary evidence for that candidate |
CHRONOLOGY_GAP | Event date, sequence, or freshness is unclear | Search only for timeline clarification |
TOPIC_GAP | Required topic category is absent | Search for candidates in the named category |
SOURCE_QUALITY_GAP | Existing source is derivative, weak, or inaccessible | Seek an official or higher-quality source |
CITATION_BINDING_GAP | Claim cannot be mapped to retrieved evidence | Obtain evidence for the named claim or mark it unsupported |
LANGUAGE_SOURCE_GAP | Evidence interpretation requires language-specific clarification | Obtain an authoritative source or translation basis; do not rewrite the whole brief |
Supplemental output must contain only:
{
"contract_version": "supplemental-research-2026-08",
"addressed_deficits": ["CORROBORATION_GAP"],
"candidate_patches": [],
"new_candidates": [],
"unresolved_deficits": []
}
Merging rules:
- accepted candidate records remain immutable;
- additions are stored as versioned evidence patches;
- removing an accepted claim requires an explicit invalidation decision and reason;
- candidate identity is resolved locally before merge;
- duplicates merge evidence rather than create new candidate IDs;
- unresolved deficits remain visible to the supervisor;
- a second supplemental round receives only remaining deficits;
- full primary research can be repeated only after a documented contract-level reason, such as a target-date change, broad evidence corruption, or editorial-policy revision.
Safe supplemental-research sequence
sequenceDiagram
participant A as Research Assessor
participant D as Local Database
participant S as Supervisor
participant O as OpenAI
participant V as Validator
A->>D: Read accepted candidates and evidence
A->>D: Write explicit deficit vector
S->>D: Reserve supplemental operation under current revision
S->>O: POST deficit-only research contract
O-->>S: Background response ID
S->>D: Attach ID and poll by eligibility
O-->>S: Completed delta output + source evidence
S->>D: Preserve delta evidence
S->>V: Validate patches, new candidates, citations
V-->>S: Accepted delta and unresolved deficits
S->>D: Merge additively; retain prior accepted candidates
D->>D: Advance revision without resetting primary research
Composition contract
Composition receives only locally validated evidence. It should not receive open-ended instructions to “research anything missing.”
| Contract dimension | Requirement |
|---|---|
| Input | Accepted event IDs, approved claims, source/citation graph, ordering and editorial constraints |
| Web search | Normally unavailable; omit the tool or explicitly disallow tool use |
| New events | Prohibited |
| New factual claims | Prohibited unless directly derivable and mapped to supplied claim IDs |
| Event identity | English and Spanish records use the same stable event IDs |
| Citation identity | Citation IDs remain attached to the same claims/events in both languages |
| Schema | Strict, versioned JSON Schema |
| Language parity | Event set, material facts, dates, numbers, names, confidence qualifications, and citation set must match |
| Research preservation | Composition failure changes no accepted research row |
| Retry scope | Composition only; no new research unless validation identifies a genuine evidence deficit and returns the supervisor to supplemental research |
Illustrative output:
{
"contract_version": "composition-2026-08",
"edition": {
"target_date": "YYYY-MM-DD",
"events": [
{
"event_id": "evt-...",
"citation_ids": ["cit-..."],
"english": {
"headline": "...",
"summary": "...",
"analysis": "..."
},
"spanish": {
"headline": "...",
"summary": "...",
"analysis": "..."
}
}
]
}
}
Composition acceptance requires:
output_event_ids == approved_event_ids
english_event_ids == spanish_event_ids
output_citation_ids ⊆ supplied_citation_ids
every factual sentence maps to one or more approved claim IDs
no tool-call output exists
no URL appears unless it is in the approved source set
all required language fields are present
dates, amounts, percentages, proper nouns, and qualification levels agree across languages
Composition retry without new research
sequenceDiagram
participant S as Supervisor
participant D as Local Evidence Store
participant O1 as Composition Attempt A
participant V as Validator
participant O2 as Composition Attempt B
S->>D: Freeze validated evidence package E
S->>O1: Compose from E, tools disabled
O1-->>S: Structured bilingual composition
S->>V: Validate schema, claims, citations, parity
V-->>S: Reject unsupported claim C
S->>D: Record composition failure; keep E unchanged
S->>O2: Retry composition from same E with bounded failure codes
O2-->>S: Corrected structured composition
S->>V: Revalidate against E
V-->>S: Accepted
S->>D: Commit composition exactly once
Structured-output and evidence validation
Structured Outputs improve syntactic reliability but do not remove the need for local validation. OpenAI’s own Structured Outputs materials distinguish schema adherence from truth or semantic correctness, and its examples explicitly handle incomplete responses, refusals, missing messages, and absent parsed output.
Validation should be layered:
| Layer | Checks | Failure result |
|---|---|---|
| Transport | HTTP and content-type validity; correct response ID; bounded body size | Retry retrieval or quarantine |
| Provider state | Known status; terminality; error/incomplete details | Poll, reject, or reconcile |
| Output-item extraction | Locate intended message; distinguish tool calls, refusals, and other items | MISSING_USABLE_MESSAGE |
| Text extraction | Exactly one expected JSON payload or SDK-parsed object; no accidental concatenation | AMBIGUOUS_OUTPUT_TEXT |
| JSON parsing | Valid UTF-8 and JSON; no trailing prose | INVALID_JSON |
| Schema | Contract version, required fields, types, enums, limits, additionalProperties: false | SCHEMA_MISMATCH |
| Identity | Candidate/event/claim/source IDs unique and correctly scoped | DUPLICATE_ID or FOREIGN_ID |
| Tool evidence | Required research call present; tool-call count within ceiling | WEB_SEARCH_MISSING or TOOL_LIMIT_EXCEEDED |
| Citation graph | Every citation points to a retrieved source; every accepted claim has support | CITATION_ORPHAN or CLAIM_UNSUPPORTED |
| Source quality | Minimum usable source count, dates, publisher, accessibility, and independence rules | SOURCE_DEFICIT |
| Editorial | Relevance, timeliness, duplication, prohibited content, balanced selection | EDITORIAL_REJECT |
| Composition grounding | Output contains no event, claim, number, or attribution outside approved evidence | UNSUPPORTED_COMPOSITION |
| Language parity | Same events, material facts, citations, uncertainty, and ordering requirements | LANGUAGE_PARITY_FAILURE |
| Publication | Rendering limits, escaping, link safety, and edition completeness | PUBLICATION_CONTRACT_FAILURE |
Specific detections:
| Defect | Detection method |
|---|---|
| Truncated output | status === "incomplete"; inspect incomplete_details.reason, including output-token exhaustion; never accept partial JSON. |
| Missing output | No message item with required output content after iterating all output items |
| Tool execution without usable message | One or more tool-call items exist but no acceptable message payload |
| Invalid JSON | Strict parser failure after extracting the intended output content; no repair-by-regex in production |
| Schema mismatch | Local JSON Schema validator against the exact stored contract version |
| Unknown fields | additionalProperties: false in provider and local schemas; report exact JSON Pointer |
| Missing required fields | Local validator reports field path and requirement |
| Duplicate candidate IDs | Set uniqueness check after Unicode normalization and case policy |
| Citation loss | Output claim references citation ID absent from composition input or research evidence |
| Citation URL not in evidence | Canonicalized citation URL lacks an exact source record or approved redirect relationship |
| Structurally valid but editorially unusable | Deterministic editorial rules plus an explicitly versioned human/editorial assessment gate |
| Too few usable sources | Count only sources that pass source-type, accessibility, date, independence, and claim-support rules |
| Unsupported composition claim | Sentence- or proposition-level claim cannot map to approved claim IDs |
| Language parity failure | Compare event-ID sets, citation-ID sets, dates, numbers, named entities, negation, confidence, and material propositions across languages |
URL normalization must be conservative. It may lowercase the scheme and host, remove a default port, and apply documented redirect mappings captured during retrieval. It should not silently equate unrelated paths, strip semantically meaningful query parameters, or convert a citation to a publisher homepage.
The local validation report should be immutable and machine-readable:
{
"validation_version": "daily-brief-validation-2026-08",
"operation_id": "op-...",
"result_digest": "sha256:...",
"accepted": false,
"failures": [
{
"code": "CITATION_ORPHAN",
"path": "/candidates/3/claims/1/source_refs/0",
"entity_id": "claim-3-1",
"detail_class": "SOURCE_REF_NOT_RETRIEVED"
}
],
"counts": {
"candidates_received": 12,
"candidates_accepted": 9,
"sources_retrieved": 22,
"sources_usable": 16
}
}
The report should not contain full article text or unrestricted source URLs in ordinary operational logs.
Cost, Cleanup, Observability, and Operational Testing
Cost and denial-of-wallet protections
The system should impose limits before reservation, before POST, after every provider observation, and before replacement generation.
Recommended initial ceilings:
| Control | Suggested initial policy |
|---|---|
| Active provider work | One active provider operation per process; global installation cap set from service tier and budget |
| Primary-research generations | One normal generation; one replacement only after conclusive terminal failure or audited safe abandonment |
| Supplemental rounds | Maximum two |
| Composition generations | Maximum three total |
| Provider create attempts | One network transmission per generation unless failure is proven pre-dispatch |
| Poll actions | One GET per eligible worker cycle |
| Built-in tool calls | Primary research maximum 12; supplemental maximum 6, using current max_tool_calls support where applicable |
| Input size | Stage-specific token and byte ceiling before API call |
| Output size | Stage-specific max_output_tokens; reject requests whose expected schema cannot fit |
| Research context | Candidate summaries and evidence digests, not an ever-growing transcript |
| Composition context | Only approved evidence needed for selected events |
| Per-process budget | Hard currency or normalized-cost ceiling computed using the price policy in force at dispatch |
| Per-day budget | Global cap plus warning threshold and circuit breaker |
| Browser-triggered work | Zero |
| Operator commands | One active command of each type per operation; cooldown and audit |
| Rate-limit storm | Open a circuit after bounded failures; do not let every cron process retry independently |
| Stale process | No work after target/revision deadline without explicit policy |
| Full-research reset | Prohibited after partial success unless a documented reset reason is recorded |
Before submission, use the documented token-counting capability where applicable, or a locally maintained conservative estimator, to reject oversized inputs. The request reference also documents token usage in response objects, which should be persisted as bounded accounting fields.
A process budget can be reserved rather than merely observed:
available_process_budget
>= reserved_max_cost_for_new_operation
The reservation is released or reconciled when actual usage is known. Unknown-acceptance operations retain their reserved maximum until safely abandoned or discovered; otherwise ambiguity could be exploited to exceed the budget through repeated replacements.
Repeated browser refreshes must not affect provider cost. Repeated cron invocations see either:
not yet eligible
lease already held
operation already reserved
provider job already active
budget exhausted
terminal result awaiting validation
and perform no duplicate external side effect.
When provider or local workflow health degrades, the site may:
- display that the current edition is delayed;
- display the date of the last verified edition;
- keep accepted research and deficits;
- offer one bounded operator command;
- resume from the last durable stage.
It must not relabel yesterday’s edition as today’s, invent a placeholder Daily Brief, omit a delay indicator, or publish unvalidated partial provider output.
Cleanup, cancellation, and deletion rules
Cancellation and deletion have different meanings:
| Action | Meaning | Safe use |
|---|---|---|
| Cancel | Ask the provider to stop a background operation | Over-age operation, operator quarantine, obsolete process revision, or budget shutdown; reconcile afterward |
| Delete | Remove the provider response object through the documented delete endpoint | Only after local preservation and policy eligibility |
| Quarantine | Prevent an operation from affecting publication | Ambiguity, stale revision, unknown status, suspicious output, or incident investigation |
| Abandon locally | Declare that the current process will never accept the operation | Unknown acceptance beyond policy limit; does not imply remote cancellation |
| Purge local raw artifact | Apply local data-retention policy | Only after keeping required normalized evidence, hashes, audit records, and publication artifacts |
OpenAI documents both cancellation and deletion endpoints. Neither should be used as a substitute for local state transitions.
Deletion eligibility should require all of:
provider_response_id is known
provider state is terminal or local policy expressly permits cleanup
no poll, validation, commit, cancellation, or incident lease is active
required output is preserved locally
required tool/source evidence is preserved locally
citation graph is preserved locally
validation report is preserved locally
usage and request-correlation fields are preserved
result has been committed, rejected, quarantined, or abandoned
minimum operational retention has elapsed
no open incident or operator hold exists
The deletion command should be written before the network call. If deletion succeeds, record provider_deleted_at. If deletion is uncertain, do not assume the object is gone; a subsequent authorized deletion check or delete retry may be appropriate because deleting an identified object is fundamentally different from repeating a create, but the implementation must still interpret documented responses and avoid unbounded retries.
Redacted diagnostics and public status
Public status should be generated from a dedicated projection rather than directly from provider objects.
Illustrative public payload:
{
"process_suffix": "7F3A91",
"revision": 12,
"target_date": "2026-08-01",
"stage_code": "RESEARCH_SUPPLEMENTAL",
"provider_state_code": "PROCESSING",
"health_code": "EVIDENCE_DEFICIT",
"last_meaningful_progress": "2026-08-01T14:32:10-05:00",
"next_eligible_cycle": "2026-08-01T14:33:05-05:00",
"evidence_counts": {
"candidates_accepted": 7,
"sources_usable": 14
},
"deficit_codes": ["REGION_GAP"],
"next_action": "WAIT_FOR_SUPPLEMENTAL_RESEARCH"
}
Public values must use bounded enums and counts. They must not disclose whether a specific provider account, project, region, credential, or private endpoint is in use.
Private diagnostic events may include:
full internal process and operation IDs
provider response ID in a restricted field
x-request-id
X-Client-Request-Id
request fingerprint
contract and schema versions
worker identity and fencing token
HTTP status class
cURL error class
attempt and poll sequence
latency
provider status and error code
token usage and estimated cost
result and evidence digests
redacted validation failure paths
They must redact or omit:
API credentials
Authorization headers
private prompts and full provider inputs
raw provider response bodies from ordinary logs
sensitive source URLs
account and project IDs
private filesystem paths
hostnames and IP addresses unless operationally required
personal information
cookies and session identifiers
database credentials
full webhook secrets or signatures
Use field-level allowlisting rather than a best-effort blacklist. Store sensitive artifacts, when operationally necessary, in a separate restricted evidence store with retention, encryption, and access auditing.
Suggested event envelope:
{
"event_type": "PROVIDER_STATE_OBSERVED",
"occurred_at": "2026-08-01T19:32:10Z",
"process_id": "internal-reference",
"process_revision": 12,
"operation_id": "internal-reference",
"operation_generation": 0,
"worker_fence": 42,
"stage_code": "RESEARCH_PRIMARY",
"from_state": "QUEUED",
"to_state": "IN_PROGRESS",
"provider_request_id": "restricted",
"client_request_id": "restricted",
"fingerprint_prefix": "b42a1e5d",
"actor_type": "WORKER",
"diagnostic_code": "POLL_OK"
}
Operator tooling
Operator actions should be commands with explicit eligibility checks:
| Operator action | Effect | Must not do |
|---|---|---|
| Reconcile current operation | Schedule one fenced retrieval or state assessment | Create a replacement |
| Request cancellation | Persist cancellation intent for the identified operation | Assume cancellation succeeded |
| Quarantine operation | Fence it from committing and preserve evidence | Delete it immediately |
| Release quarantine | Require current revision, validation status, and reason | Silently reattach a stale operation |
| Authorize replacement generation | Increment generation under budget after explicit ambiguity acknowledgment | Reuse the old generation’s authority |
| Retry composition | Reserve a composition-only operation from the same accepted evidence digest | Repeat research |
| Request supplemental research | Supply explicit deficits and remaining budget | Discard retained candidates |
| Hold cleanup | Prevent deletion during investigation | Change publication state |
| Mark process delayed | Expose clear delayed status | Publish stale content as current |
| Abandon process | Terminal local decision with reason | Pretend remote work was cancelled |
Every write action should require authentication, authorization, CSRF protection where applicable, an idempotent command key, reason code, actor identity, and audit event.
Deterministic no-network fixtures
A no-network provider adapter should implement the same interface as the live adapter:
interface ResponseProvider
{
public function create(CreateContract $contract, RequestContext $context): CreateObservation;
public function retrieve(string $responseId, RequestContext $context): RetrieveObservation;
public function cancel(string $responseId, RequestContext $context): CancelObservation;
public function delete(string $responseId, RequestContext $context): DeleteObservation;
}
The fixture adapter should be scriptable by operation and call number:
{
"create": [
{"result": "timeout_after_send"},
{"result": "must_not_be_called"}
],
"webhook": [
{"after_virtual_seconds": 30, "event": "response.completed", "response_id": "resp-fixture-1"}
],
"retrieve": [
{"status": "completed", "fixture": "valid_primary_research"}
]
}
Required fixtures include:
| Fixture family | Cases |
|---|---|
| Transport | DNS, TLS, connect failure, timeout before send, timeout after send, truncated HTTP response |
| Protocol | 400, 401, 403, 429 with and without Retry-After, quota 429, 500, 503 |
| Provider statuses | queued, in-progress, completed, incomplete, failed, cancelled, unknown |
| Output shape | missing message, multiple messages, refusal, tool-only output, invalid JSON, valid JSON with trailing prose |
| Schema | unknown field, missing required field, wrong enum, oversized array, duplicate IDs |
| Evidence | no web-search call, source list missing, orphan citation, unsupported claim, insufficient independent sources |
| Composition | new event, new URL, changed number, missing citation, English/Spanish event mismatch, confidence mismatch |
| Concurrency | duplicate cron, duplicate webhook, two workers, expired lease, stale fence, old process revision |
| Crash points | before POST, during POST, after create response, after provider completion, after evidence persistence, during result commit |
| Cleanup | cancel/completion race, duplicate cancel, deletion before preservation blocked, delete uncertainty |
| Cost | budget exhaustion, tool-call cap, token ceiling, repeated operator click, rate-limit storm |
Property-based or state-machine tests should continuously assert:
active_provider_operations(process, current_revision, current_stage) <= 1
published(process) implies validated_composition_exists(process)
accepted_composition evidence_digest == accepted_research evidence_digest
stale_fence cannot mutate supervisor
result_commit_count(operation) <= 1
provider_create_count(fingerprint, generation) <= 1
replacement_generation > prior_generation
deleted(operation) implies evidence_preserved(operation)
browser_request_provider_call_count == 0
Minimal isolated live-probe strategy
A live probe should exercise real OpenAI behavior without touching publication state.
Recommended design:
| Attribute | Rule |
|---|---|
| Isolation | Separate process namespace, tables or schema, credentials or project where operationally feasible, and no publication foreign keys |
| Prompt | Tiny non-sensitive fixed request |
| Structured output | Minimal strict schema such as {probe_id, status, checked_at} |
| Background | Enabled to verify create and retrieval |
| Web search | A separate bounded probe, not every probe run, to verify tool/source/citation retrieval |
| Tool limit | One or two calls |
| Output limit | Very small |
| Budget | Hard daily cap and per-probe maximum |
| Trigger | Internal scheduler only; no public endpoint |
| Validation | Verify status transitions, strict schema, request IDs, source evidence, and webhook signature path |
| Cancellation probe | Run periodically against an intentionally slow or cancellable test only if the chosen model reliably permits it; do not manufacture uncontrolled cost |
| Deletion probe | Delete only the probe response after evidence capture |
| Reporting | Emit health metrics and redacted diagnostics; never publish probe output |
| Failure behavior | Open probe-specific alert; do not automatically create publication jobs |
A probe sequence is:
reserve probe
create one background response
persist response ID
wait until eligible
retrieve at most once per cycle
validate provider status and schema
preserve minimal evidence
optionally verify webhook correlation
delete after retention condition
record result
A green live probe proves that the selected API path currently works. It does not prove the publication supervisor is correct; deterministic workflow tests and chaos tests must establish that.
Production Acceptance Criteria and Source Record
Production acceptance gates
The workflow should not be enabled for unattended publication until all of the following are demonstrated in a production-like environment.
| Area | Acceptance criterion |
|---|---|
| Authority | No provider status, webhook, or browser request can directly advance publication state |
| Reservation | Concurrent scheduler invocations produce one active operation for a process revision/stage |
| Ambiguous create | A timeout after possible POST acceptance produces no automatic duplicate POST |
| Correlation | Every external action stores a client request ID and any received server request ID |
| Stale-worker safety | A worker holding an old fencing token cannot attach a response ID, schedule a poll, preserve a current artifact, or commit |
| Provider ID integrity | A response ID cannot be reassigned to another operation, process, revision, or stage |
| Polling | At most one GET occurs per eligible server cycle; cadence and jitter are durable |
| Status handling | All six documented response statuses have tested transitions; unknown status fails closed |
| Webhooks | Signatures are verified, duplicate webhook IDs are deduplicated, and stale events cannot affect current state |
| Completion validation | A completed response with missing message, refusal, invalid JSON, schema defect, or unsupported evidence cannot advance |
| Research evidence | Accepted claims map to retrieved sources; inline citations and consulted sources are preserved |
| Supplemental research | Existing accepted candidates survive and only named deficits are researched |
| Composition | No new events or sources can enter; English and Spanish event and citation sets match |
| Exactly-once commit | A crash at every transaction boundary produces zero or one accepted artifact, never two |
| Cost | Per-operation, per-process, and per-day ceilings are enforced before creation |
| Denial-of-wallet | Browser refreshes, repeated cron runs, duplicate webhooks, and operator double-clicks do not create duplicate work |
| Rate limits | Retry-After is honored; one circuit breaker prevents a retry storm |
| Cancellation race | Either a valid eligible completion is accepted exactly once or the operation is cancelled/quarantined; no ambiguous mixed state |
| Evidence preservation | Deletion is impossible before required evidence and diagnostics are durably copied |
| Degraded mode | The site clearly distinguishes a delayed current edition from the last verified edition |
| Privacy | Structured logs pass automated tests for credentials, headers, prompts, account IDs, private paths, sensitive URLs, and personal information |
| Recovery time | Every nonterminal local state has a defined next eligible time or bounded operator action |
| Terminality | Every retry path has a maximum attempt count, maximum elapsed time, and explicit terminal state |
| Auditability | Every authority-changing transition records process revision, operation generation, fence, actor, reason, and result |
| Probe isolation | Live-probe failure or success cannot alter Daily Brief publication state |
| Runbook | Operators can identify whether to wait, reconcile, cancel, quarantine, authorize replacement, retry composition, request supplemental research, or abandon |
Recommended launch sequence
| Phase | Deliverable | Exit condition |
|---|---|---|
| Supervisor foundation | Process/revision model, operation reservation, fingerprints, outbox, unique constraints, fences | Concurrency tests prove one active operation and stale-worker rejection |
| Fake-provider integration | Deterministic fixture adapter and complete transition suite | Every retry-matrix row has an automated test |
| Research artifact model | Candidate, claim, source, citation, deficit, and validation records | Invalid evidence cannot become accepted research |
| Composition model | Evidence-only input and bilingual strict output | Unsupported claims and parity defects are rejected |
| Live transport | Real create/retrieve with isolated probe | Request IDs, statuses, evidence, and retention behavior observed |
| Webhooks and cancellation | Signed, deduplicated notification ingestion; cancel/retrieve reconciliation | Duplicate and race tests pass |
| Cleanup | Evidence-first deletion policy | Premature deletion is structurally blocked |
| Shadow production | Run Daily Brief workflow without publishing | Results remain deterministic under crashes and duplicate schedules |
| Supervised publication | Human approval after local validation | Operational metrics remain within cost and latency ceilings |
| Unattended eligibility | Automatic publication only if editorial policy permits and every gate is green | Incident rollback and delayed-mode behavior verified |
Final architectural judgment
The OpenAI platform currently provides the necessary primitives for this workflow: asynchronous Responses, retrieval, explicit statuses, structured schemas, built-in web search with source and citation information, request correlation, webhooks, cancellation, and deletion.
Those primitives are sufficient only when surrounded by a local orchestration system that assumes:
network results can be ambiguous
schedulers and webhooks are at least once
workers can become stale
provider completion is not local success
external creation is not safely repeatable without proof
every result must be reconciled to current authority
every accepted artifact must be committed exactly once
every cleanup operation must follow evidence preservation
The decisive production feature is therefore not another API connectivity test. It is a durable state machine in which the site can explain, for every provider operation:
why it was authorized
which immutable contract it represents
whether creation is known or ambiguous
who currently owns reconciliation
when another call is eligible
which evidence was recovered
why the output was accepted or rejected
whether it advanced the current process revision
what cost was consumed or reserved
when and why it may be cancelled or deleted
When those answers are durable, bounded, and testable, the Daily Brief can recover from timeouts, crashes, duplicate schedules, webhook replays, stale workers, provider delays, malformed output, and composition defects without fabricating content or losing accepted research.
Official sources
- OpenAI API reference, Responses endpoints, request identifiers, compatibility guidance, and response object behavior.
- OpenAI background-mode guide, including asynchronous creation and retrieval-based polling.
- OpenAI web-search guide, including search-call output, citation annotations, and source inclusion.
- OpenAI Structured Outputs guide and launch announcement.
- OpenAI error-code and rate-limit guidance.
- OpenAI webhook guide, including response completion, signature verification, retries, and duplicate-event handling.
- OpenAI cancellation and deletion references.
- OpenAI data-control documentation for Responses retention and background-processing storage considerations.
- OpenAI announcements for the Responses API, web search, and background mode.