SEO / Portfolio / Public Site
Production Reliability Architecture for the InternationalIntelligence.org Daily Brief
Report summary
I assess the most plausible failure as production split-brain across execution, origin, cache, release, and browser layers , not failure of the internal Daily Brief workflow itself.
Key topics
- SEO / Portfolio / Public Site
- SEO
- Portfolio
- Public Site
- .NET
- Runtime
- Semantic Systems
- Research Archive
- Strategy
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: 20 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 finding and research method
Executive finding
I assess the most plausible failure as production split-brain across execution, origin, cache, release, and browser layers, not failure of the internal Daily Brief workflow itself.
A workflow test can pass while the public site still looks broken when any of the following are true:
- The scheduler does not execute, executes late, overlaps, or invokes an obsolete release.
- PHP CLI advances state using a different configuration, user, filesystem, secrets set, or database target than PHP-FPM.
- An alternate hostname, virtual host, CDN origin, or document root serves a different release or site instance.
- A reverse proxy, CDN, browser cache, or service worker returns stale status JSON.
- A browser tab displays provisional HTML or local state after polling has been throttled or suspended.
- An old response arrives after a newer response and overwrites it.
- A process exists, but its last meaningful progress is stale.
- A deployment changes the web release while cron, OPcache, workers, or service-worker caches remain attached to the previous release.
The assignment reports that provider connectivity works and that process IDs, monotonic revisions, polling, cross-tab synchronization, trigger leasing, canonical-host handling, and versioned assets have already been attempted. Those controls are necessary but cannot prove that scheduled production execution and public delivery use the same release, site instance, authoritative datastore, filesystem, origin, and cache policy. I therefore treat the uploaded project description as the case study and as the source of reported—but not independently verified—system facts.
My central architectural recommendation is:
Use one server-side publication authority, backed by transactional idempotency and a lease with an expiry; let one primary scheduler and one independently monitored fallback submit trigger requests; expose immutable release and site-instance identities through every execution and status record; make status endpoints uncacheable at every layer; and treat every browser representation as provisional until reconciled with the authoritative API.
An external scheduler may request work, but it must never decide that a publication cycle exists, choose a new process ID, increment a revision, bypass eligibility rules, or declare success. Those decisions belong to the server authority.
Scope and limitations
I have no source-code, shell, hosting-panel, CDN, DNS, credentials, deployment logs, scheduler logs, database records, or private runtime-state access. Consequently, I cannot identify the actual fault with certainty. I can provide a production architecture, evidence requirements, safe diagnostics, failure hypotheses, and acceptance tests that distinguish likely causes without relying on privileged access.
Details not supplied remain unspecified, including:
| Item | Status |
|---|---|
| Hosting provider and control panel | Unspecified |
| Linux distribution and init system | Unspecified |
| PHP and PHP-FPM versions | Unspecified |
| Database or state-store technology | Unspecified |
| CDN and reverse-proxy vendors | Unspecified |
| Canonical hostname | Unspecified |
| Alternate hostnames | Unspecified |
| Current release identifier | Unspecified |
| Site-instance identifier | Unspecified |
| Existing scheduler type and schedule | Unspecified |
| Publication timezone and eligibility rule | Unspecified |
| Service-worker presence and scope | Unspecified |
| Number and location of active origins | Unspecified |
Methodology
I modeled the system as a chain of independently falsifiable contracts:
- A scheduler emits an authenticated trigger.
- The canonical origin validates identity and mode.
- The server authority determines eligibility.
- A transaction reserves or resumes a publication process.
- A worker advances state while renewing its lease and heartbeat.
- The status API serializes authoritative state.
- Reverse proxies and CDNs forward rather than reuse that response.
- Browser code reconciles snapshots monotonically.
- Cross-tab messaging accelerates—but never creates—convergence.
- Deployment preserves release and state compatibility through rollout and rollback.
For normative behavior, I prioritized current standards and official implementation documentation as of August 1, 2026. HTTP cache semantics come from RFC 9111; request-target, host, and redirect semantics from RFC 9110; forwarded-header risks from RFC 7239; PHP behavior from the PHP manual; scheduler behavior from cron, systemd, cPanel, Google Cloud, and AWS documentation; and browser behavior from WHATWG, W3C, Chromium, Mozilla, and WebKit documentation. RFC 9111 expressly distinguishes shared and private caches and specifies that no-cache allows storage but requires successful validation before reuse, whereas no-store prohibits storage by conforming caches.
Evidence-source comparison
| Source class | Primary use in this report | Strength | Limitation |
|---|---|---|---|
| IETF RFCs | Host routing, redirects, caching, forwarded headers | Normative Internet standards | Products can be misconfigured or nonconforming |
| PHP manual | CLI/FPM configuration, pools, OPcache | Official implementation documentation | Hosting vendors may patch or wrap PHP |
| cron/systemd manuals | Scheduling, environment, catch-up, service limits | Direct operational semantics | Cron implementations differ |
| Cloud scheduler documentation | Retry, at-least-once delivery, deadlines, DST | Current managed-service contract | Vendor-specific behavior |
| WHATWG/W3C specifications | BroadcastChannel, storage, service workers, page lifecycle | Browser-platform definitions | Browsers retain implementation latitude |
| Browser-vendor documentation | Throttling, suspension, lifecycle behavior | Documents real implementation behavior | Policies can change between versions |
| CDN/reverse-proxy documentation | Origin-header handling and overrides | Describes actual edge controls | Exact behavior depends on account configuration |
| Recent academic research | Hidden-cache and service-worker risk context | Empirical evidence beyond advertised headers | Does not replace product-specific diagnostics |
Recent research reinforces the need for active cache testing rather than trusting response labels alone. A 2024 study proposed timing-based discovery of hidden web caches and reported that some caches did not advertise their involvement through standard status headers; this supports using paired cache-busted and ordinary synthetic requests as diagnostic evidence, not as the normal freshness mechanism.
End-to-end execution model
Production path
The production contract should be understood as this chain:
| Layer | Required proof | Typical “tests pass, site broken” failure |
|---|---|---|
| Scheduler registration | Enabled schedule, next-run time, UTC rule, target release strategy | No cron entry, disabled panel job, wrong user |
| Trigger delivery | Trigger ID, attempt number, receipt timestamp, authenticated principal | Request blocked, timed out, retried, delivered to alternate origin |
| Canonical-origin gate | Observed host, canonical origin, proxy trust result | State initialized before redirect; forwarded host trusted from the Internet |
| Authority transaction | Site instance, cycle key, reservation result | Duplicate process creation or stale permanent lock |
| Worker runtime | PHP binary, SAPI, INI files, extensions, UID, CWD, release | CLI uses another PHP or release |
| State persistence | Database identity, schema contract, filesystem identity | CLI and web point to different state stores or mounts |
| Publication progress | Monotonic revision, stage, heartbeat, meaningful-progress time | PID exists but process is stalled |
| Status serialization | Current process and release contract | API reads old database, old replica, or old release |
| Proxy/CDN delivery | Age, cache status, origin request ID, no-store compliance | Cached JSON returned |
| Browser reconciliation | Request sequence and accepted process/revision | Delayed response overwrites newer state |
| Cross-tab propagation | Code-only snapshot notification | Local message mistaken for server authority |
| Localization | Same identifiers and codes in English and Spanish | Localized prose interpreted as state |
A successful internal workflow test ordinarily validates only a subset of these rows. It does not prove that cron exists, that it invokes the same release as the website, that a public hostname reaches that release, or that the status response was fetched from the authority.
Applied case-study choice
I chose the InternationalIntelligence.org Daily Brief production path because the uploaded assignment supplies a concrete, plausible system with scheduler, PHP, CDN, browser, bilingual, and deployment concerns. This is preferable to inventing an unrelated example, while still requiring me to mark all unobserved implementation details as unspecified.
The likely causal families are:
| Priority | Failure family | Why it fits the reported symptom | Decisive evidence |
|---|---|---|---|
| Critical | Scheduler absent or wrong target | Internal manual tests pass; unattended publication does not | Scheduler execution log tied to trigger ID and release |
| Critical | Release or document-root split-brain | Some hosts/tabs/languages show different behavior | Response headers expose different release/site-instance IDs |
| Critical | Status JSON cached | Back end progresses but public display remains old | Repeated requests show nonzero Age, edge hits, or identical old snapshot-generation time |
| High | CLI/FPM drift | Manual web test works while cron PHP fails | CLI and web doctor reports differ |
| High | Stale or non-expiring lease | Trigger arrives but no process can reserve work | Lease owner, expiry, database clock, last heartbeat |
| High | Service-worker interception | Origin headers look correct while one browser remains stale | DevTools or synthetic clean profile shows service-worker response |
| High | Delayed response race | Tabs intermittently regress | Request sequence logs show old response accepted after new response |
| Medium | Background suspension | Active tab updates; inactive/mobile tab does not | Visibility and poll telemetry |
| Medium | DST or timezone mismatch | Failure clusters near cycle boundary or DST transition | UTC schedule, server time, eligibility calculation |
| Medium | Provider/API issue | Reportedly less likely because connectivity works | Provider request IDs and provider-state records |
Reliability timeline
timeline
title Daily Brief production reliability lifecycle
Scheduler configuration : Define UTC cadence
: Bind target and credentials
Trigger receipt : Validate trigger contract
: Record immutable trigger ID
Reservation : Evaluate next eligible cycle
: Atomically create or resume process
: Acquire expiring lease
Advancement : Poll provider
: Persist stage and revision
: Renew heartbeat and lease
Publication : Commit bilingual evidence
: Mark meaningful progress
Status delivery : Generate no-store snapshot
: Expose release and site-instance IDs
Browser convergence : Fetch authoritative API
: Reject stale responses
: Notify other tabs
Deployment : Switch immutable release
: reset FPM OPcache
: purge only intended CDN objects
: verify service-worker compatibility
Entity-relationship model
erDiagram
SITE_INSTANCE ||--o{ RELEASE : serves
SITE_INSTANCE ||--o{ PUBLICATION_CYCLE : owns
RELEASE ||--o{ TRIGGER : receives
TRIGGER }o--|| SITE_INSTANCE : targets
PUBLICATION_CYCLE ||--o{ PROCESS : attempts
PROCESS ||--o{ RESERVATION : protected_by
PROCESS ||--o{ HEARTBEAT : emits
PROCESS ||--o{ SNAPSHOT : produces
PROCESS ||--o{ EVIDENCE_ITEM : accumulates
RELEASE ||--o{ SNAPSHOT : serializes
BROWSER_CLIENT }o--o{ SNAPSHOT : observes
SITE_INSTANCE {
string site_instance_id PK
string canonical_origin
string state_store_identity
}
RELEASE {
string release_id PK
string contract_version
string asset_manifest_hash
}
PUBLICATION_CYCLE {
string cycle_key PK
date target_date
timestamp next_eligible_at
}
TRIGGER {
string trigger_id PK
string trigger_type
timestamp requested_at_utc
string mode
}
PROCESS {
string process_id PK
int revision
string stage_code
timestamp last_meaningful_progress
}
RESERVATION {
string lease_token PK
timestamp acquired_at
timestamp expires_at
string owner
}
HEARTBEAT {
timestamp observed_at
string health_code
int revision
}
SNAPSHOT {
string snapshot_id PK
timestamp generated_at
int revision
string release_id
}
EVIDENCE_ITEM {
string evidence_id PK
string type_code
string locale_scope
}
BROWSER_CLIENT {
string client_instance_id PK
string origin
string locale
}
The database, not the operating-system PID, should own process identity. An OS PID is host-local, reusable, and potentially absent for HTTP or managed-function execution. It can be recorded as supporting evidence, but process_id should be an application-generated immutable identifier.
Scheduler architecture and authority contract
Scheduler-model comparison
Cron behavior is implementation-specific around daylight-saving transitions. Traditional Vixie-style documentation warns that nonexistent local times may never match and repeated times may match twice, while Cronie documents compensation for clock changes of less than three hours. That difference alone is sufficient reason to schedule the authority in UTC and compute local publication eligibility explicitly in application code.
Systemd timers can persist missed calendar activations and start a service after downtime when Persistent=true, while service units provide explicit users, working directories, environments, runtime limits, exit states, logs, and credential mechanisms.
Managed schedulers should be treated as at-least-once submitters. Google states that duplicate requests are possible in rare circumstances and instructs handlers to be idempotent; it also recommends UTC when an exact cadence must avoid DST anomalies. AWS EventBridge Scheduler documents at-least-once delivery, configurable retries, event retention, and dead-letter queues.
| Model | Delivery and missed-run behavior | Overlap and catch-up | Runtime and environment | Failover, cost, and complexity | Assessment |
|---|---|---|---|---|---|
| Traditional system cron invoking PHP CLI | Best-effort local invocation; no inherent durable delivery receipt; downtime normally loses runs unless paired with another mechanism | Overlap is possible; use server-side lease plus optional flock; catch-up is not intrinsic | Minimal environment; unspecified CWD unless command changes it; must use absolute PHP/script paths and explicit INI; stdout/stderr usually mailed or redirected | Host-bound; low cost; low-to-medium operational complexity | Acceptable primary on one well-managed host, but only with heartbeat monitoring and idempotency |
| Hosting-control-panel cron | Usually wraps system cron; UI simplifies registration but can hide PHP path, environment, mail, and execution limits | Overlap possible; panel documentation itself warns to leave enough completion time | Vendor-selected user, PATH, shell, PHP version, and resource limits; absolute paths required | Tied to hosting account; low marginal cost; limited observability | Viable on shared hosting if doctor output and logs are externally retained |
| Systemd timer plus service | Durable local orchestration; Persistent=true can catch up missed calendar activation | Service activation and unit state make overlap easier to control; explicit timeout and failure handling | Strongest local control over user, group, CWD, environment, mounts, credentials, logging, and runtime | Host-bound unless duplicated; no service fee; medium complexity | Preferred local scheduler on a controlled Linux server |
| Cloud scheduler or authenticated HTTP trigger | At-least-once with retries and provider logs; delivery can fail independently of origin execution | Provider may serialize attempts, but duplicates remain possible; catch-up and retry policy are vendor-specific | HTTP deadline, network path, identity token, and origin limits replace CLI environment concerns | Independent of host and useful for detecting local scheduler failure; low cost; medium complexity | Strong primary or fallback, provided it is only a trigger submitter |
| Queue worker or managed scheduled function | Queue commonly provides at-least-once delivery; durable backlog and retry/DLQ options | Consumer concurrency must be limited or made idempotent; backlog supplies catch-up | Explicit image/runtime, secrets, IAM, and time limits; filesystem may be ephemeral | Strong host failover; variable cost; higher architecture complexity | Best when advancement naturally decomposes into short resumable steps |
| Redundant schedulers with server idempotency | Highest trigger availability, but deliberately produces duplicate requests | Only authority transaction prevents duplicate work; each trigger records its own attempt | Mixed environments are acceptable because the trigger payload is normalized | Better failover; higher monitoring and testing burden | Recommended as primary plus delayed fallback, not simultaneous independent authorities |
cPanel’s current documentation warns that jobs can overlap if scheduled too frequently, tells operators to use absolute paths, and notes that discarding stdout and stderr with /dev/null 2>&1 disables useful notification evidence.
Detailed operational comparison
| Concern | Cron / panel cron | Systemd timer | External HTTP scheduler | Queue or managed function |
|---|---|---|---|---|
| Execution guarantee | No end-to-end guarantee without monitoring | Local start and failure state recorded | Provider delivery contract with retry; still at-least-once | Durable queue offers strongest retry semantics |
| At-least-once possibility | Yes, through overlap, DST, manual runs | Yes, through retries or multiple timers | Explicitly yes for common managed products | Normally yes |
| Overlap prevention | Authority lease; shell lock is secondary | Unit state plus authority lease | Authority lease | Consumer concurrency plus authority lease |
| Missed run | Usually lost | Catch-up possible with persistent calendar timer | Product retry/catch-up rules | Message remains pending until retention expires |
| Maximum runtime | Hosting and shell limits | RuntimeMaxSec= or equivalent | HTTP deadline; Cloud Scheduler documents product-specific deadlines | Function/worker limit |
| Environment | Sparse and shell-dependent | Declarative | Request headers/body and workload environment | Declarative deployment environment |
| Working directory | Often home or implementation-dependent | Explicit WorkingDirectory= | Not applicable to scheduler; application decides | Explicit image/function configuration |
| PHP executable | Must be absolute | Absolute ExecStart= | Web PHP/FPM or application service | Runtime image or function version |
| PHP configuration | Explicit -c or verified default | Explicit -c, environment, extensions | FPM or web runtime | Image-controlled |
| Filesystem user | Cron account | Explicit User=/Group= | Web service user | Worker identity |
| Secret access | Often missing web secrets | Credentials or restricted files | IAM/OIDC/HMAC; origin secrets | IAM/secret manager |
| Timezone | Daemon/server/CRON_TZ; implementation-sensitive | Explicit calendar zone; prefer UTC | Usually explicit IANA zone; prefer UTC | UTC event plus app eligibility |
| stdout/stderr | Mail or redirected files | Journal and unit status | Provider request/execution logs | Centralized logs |
| Exit-code capture | Mail/wrapper required | Native unit result | HTTP status is only trigger acceptance, not necessarily publication completion | Native task status and DLQ |
| Deployment coupling | Often hard-coded path | Unit can target stable launcher/current symlink | Targets stable canonical endpoint | Versioned task/function |
| Host failover | None by default | None by default | Scheduler independent; origin still needs failover | Managed platform typically supports it |
| Cost | Lowest | Lowest | Usually low | Higher but scalable |
| Complexity | Low, with hidden risks | Moderate | Moderate | Highest |
Recommended scheduler topology
For a small-to-medium PHP publication site, I recommend:
- Primary: systemd timer where server control exists; otherwise an authenticated managed HTTP scheduler.
- Fallback: an independently hosted authenticated scheduler delayed by a grace interval.
- Authority: one transactional server endpoint or worker command shared by all trigger types.
- Execution: short, resumable advancement steps rather than one long monolithic request.
- Monitoring: independent freshness alerting based on
last_meaningful_progress, not merely scheduler success. - Timezone: scheduler cadence in UTC; publication date derived from a named IANA timezone inside the authority.
- Idempotency: unique cycle key such as
(site_instance_id, target_date, edition_type)with a database uniqueness constraint.
The fallback should not run exactly with the primary. It should ask, for example, five or ten minutes later whether the eligible cycle has already been reserved or progressed. The authority either returns already_current, resumes a recoverable process, or reserves once.
Scheduled-advancement sequence
sequenceDiagram
participant S as Primary Scheduler
participant G as Canonical-Origin Gate
participant A as Publication Authority
participant DB as Authoritative Store
participant W as Worker
participant P as Provider
S->>G: POST /internal/trigger<br/>signed contract + trigger_id
G->>G: Validate trusted route, host, signature, time window
G->>A: Submit normalized trigger
A->>DB: INSERT trigger receipt
A->>DB: Transaction: evaluate cycle and reserve
DB-->>A: process_id + lease_token + revision
A-->>S: 202 accepted / already-current
A->>W: Dispatch resumable advance step
W->>DB: Verify lease, release, site instance
W->>P: Poll/fetch provider
P-->>W: Provider result + request ID
W->>DB: Commit state + revision + heartbeat
W->>DB: Renew/release lease
Duplicate-trigger sequence
sequenceDiagram
participant S1 as Primary Scheduler
participant S2 as Fallback Scheduler
participant A as Authority
participant DB as Store
par Nearly simultaneous triggers
S1->>A: trigger T1 for cycle C
S2->>A: trigger T2 for cycle C
end
A->>DB: Transaction reserve C
DB-->>A: T1 wins; process P created
A->>DB: Transaction reserve C
DB-->>A: Unique cycle exists; return process P
A-->>S1: 202 reserved P
A-->>S2: 200 already_reserved P
Note over A,DB: No second process or revision lineage is created
Scheduler contract
Every invocation should carry or derive the following normalized contract:
| Field | Purpose and validation |
|---|---|
contract_version | Reject unsupported trigger schemas |
release_id | Records the submitter’s expected release; mismatch enters doctor/status-only behavior unless explicitly compatible |
site_instance_id | Prevents one environment from advancing another |
requested_at_utc | ISO 8601 UTC timestamp; enforce bounded clock skew |
trigger_id | Globally unique idempotency and audit identifier |
trigger_type | systemd, cron, panel_cron, cloud_http, queue, operator, synthetic |
expected_canonical_origin | Exact preconfigured origin; never copied blindly into a redirect |
mode | One of status_only, doctor, or advance |
maximum_runtime_seconds | Hard execution budget below platform termination limit |
reservation_policy | Acquire, resume, observe-only, or refuse when occupied |
target_cycle_hint | Optional hint; authority independently computes eligibility |
authentication_principal | Verified scheduler identity, key ID, or service account |
attempt_number | Distinguishes provider retries under one trigger ID |
trace_id | Correlates edge, application, worker, and provider logs |
The trigger must not provide an authoritative process ID, target revision, stage, publication-success flag, or next-eligible time.
Exit-code taxonomy
For CLI and worker modes, use stable machine-readable exit codes:
| Code | Meaning |
|---|---|
0 | Success, including meaningful progress |
10 | No eligible cycle; healthy no-op |
11 | Already reserved or already complete |
12 | Status-only or doctor completed |
20 | Contract or release mismatch |
21 | Site-instance or canonical-origin mismatch |
22 | Authentication or authorization failure |
30 | Temporary provider failure |
31 | Temporary state-store or filesystem failure |
32 | Lease lost or superseded |
40 | Permanent configuration failure |
41 | Schema or data-integrity failure |
42 | Unsupported runtime/PHP contract |
50 | Maximum runtime reached after checkpoint |
70 | Unexpected internal exception |
HTTP trigger acceptance should use a separate response contract. A 202 means the trigger was authenticated and recorded, not that publication succeeded.
Heartbeat record
The heartbeat should be a persisted record, not merely a log line:
{
"site_instance_id": "prod-us-central-01",
"release_id": "2026-08-01.3+git.ab12cd3",
"process_id": "proc_01J...",
"cycle_key": "daily-brief:2026-08-01",
"trigger_id": "trg_01J...",
"trigger_type": "systemd",
"worker_instance_id": "host-a:pid-18420",
"lease_token_hash": "sha256:…",
"lease_expires_at": "2026-08-01T12:06:00Z",
"heartbeat_at": "2026-08-01T12:05:30Z",
"last_successful_reservation_at": "2026-08-01T12:00:02Z",
"last_meaningful_progress_at": "2026-08-01T12:04:54Z",
"revision": 17,
"stage_code": "PROVIDER_WAIT",
"next_eligible_cycle_at": "2026-08-02T12:00:00Z",
"redacted_failure_class": null
}
A lease must expire according to the authoritative datastore’s clock, not a browser clock and preferably not a worker host clock. Renewal must compare the current lease token and process ID. Once a worker loses the lease, it must stop mutating state even if it continues running.
PHP runtime drift and deployment split-brain
Why CLI and web execution diverge
PHP reads configuration according to the invoked SAPI and startup path. The PHP manual notes that server modules generally read configuration when the server starts, whereas CLI and CGI invocations read configuration for each execution; PHP also supports additional scanned INI directories. PHP-FPM pools can set distinct users, groups, working directories, chroots, environment variables, and PHP options, and FPM’s clear_env defaults to clearing worker environments unless explicitly populated.
The CLI binary is a distinct SAPI whose location depends on installation, and multiple PHP binaries can coexist. Therefore /usr/bin/php, /usr/local/bin/php, and a hosting-provider PHP selector may represent different versions or builds.
Drift diagnostic matrix
Safe diagnostics should expose hashes and metadata, not secret values.
| Condition | Expected symptom | Safe diagnostic | Required evidence | Remediation | Release-proofing control |
|---|---|---|---|---|---|
Different php.ini | CLI-only errors, differing limits or extensions | Compare PHP_SAPI, php_ini_loaded_file(), scanned INI basenames and hashes | CLI doctor and authenticated web doctor | Pin CLI with absolute binary and -c; align required settings | Store runtime-contract hash in every trigger and status |
| Different PHP versions | Syntax, library, TLS, or type differences | PHP_VERSION, PHP_VERSION_ID, binary realpath | Both runtimes’ doctor records | Use same supported minor version or container/image | Reject unsupported runtime contract |
| Different extensions | Missing database, cURL, intl, mbstring, JSON, or timezone behavior | Sorted extension-name/version hash | get_loaded_extensions() and selected module versions | Install/enable same required extensions | Deployment preflight |
| Different environment variables | Missing endpoints, feature flags, or credentials | List approved variable names and value hashes | Redacted environment manifest | Load explicit secure environment for both | No implicit shell/login environment |
| Different filesystem users | Permission denied or files owned by cron user | UID/GID, effective user, directory access probes | stat results without content | Shared group/ACL or avoid mutable release files | Dedicated state directories |
| Different permissions | Web can write but cron cannot, or vice versa | Read/write/rename probe in dedicated diagnostic directory | Ownership, mode, ACL evidence | Correct least-privilege ACLs | Pre-deploy permission test |
| Different temporary directories | Locks or intermediate files never meet | sys_get_temp_dir() and filesystem-device ID | CLI/FPM temp paths and mount IDs | Use explicit application runtime directory | Never use ambient /tmp for cross-runtime authority |
| Different CWD | Relative includes or output paths break | getcwd(), __DIR__, included-file roots | CLI and web path manifests | chdir() only in launcher; otherwise absolute paths | Ban relative production state paths |
| Relative paths resolve differently | Wrong config/database/cache file | Resolve every configured path to canonical absolute path | Path-resolution doctor output | Build paths from immutable application root | Static check and startup assertion |
| Cron lacks web secrets | Provider or database authentication failure | Presence and version ID only, never secret value | Secret reference names and access result | Shared secret manager or protected file | Secret-contract version check |
| Cron points to old release | Scheduler “works” but advances obsolete code/state | Log script realpath, release ID, inode/device | Scheduler command plus runtime release record | Target a stable release-aware launcher | Launcher refuses retired/incompatible releases |
| Deployment symlink changed but cron path fixed | Web new; cron old | Compare current symlink target with executed script realpath | Deployment manifest and trigger record | Point scheduler to stable launcher/current target | Post-deploy trigger doctor |
| Stale FPM OPcache | Files changed but web behavior old | Expose release constant and OPcache configuration, not cache contents publicly | FPM release response before/after reset | Reload/restart FPM or invoke restricted FPM-side reset | Mandatory FPM reload and health gate |
| Multiple virtual hosts use different releases | Hostname-dependent behavior | Fetch every host and record release/site-instance headers | TLS SNI, Host, origin-IP matrix | One canonical vhost; alternate hosts redirect/reject at edge | Deployment inventory and synthetic host matrix |
| Shared host kills long PHP | Process stops mid-stage without final status | Runtime duration and termination-class telemetry | Host limit documentation and heartbeat gap | Short resumable steps/queue | Work units below conservative limit |
| Cron mail/logs discarded | Silent failures | Deliberate doctor exit and stderr canary | Receipt in durable log/alert sink | Central logs and explicit alerting | Deployment blocks /dev/null 2>&1 without replacement |
| Web and CLI see different mounted volumes | State or release differs by runtime | Filesystem device/inode IDs and sentinel file hash | Mount namespace and storage identity | Shared authoritative database/object store | Site-instance includes state-store identity |
PHP’s OPcache stores precompiled bytecode in shared memory. When timestamp validation is disabled, code changes do not take effect until OPcache is reset, scripts are invalidated, or the web server is restarted. The manual also documents that CLI OPcache is disabled by default, which means a CLI-side reset is not evidence that the FPM shared cache was reset. The latter conclusion is an architectural inference from the process-specific shared-memory model and should be verified against the actual hosting setup.
Immutable-release deployment model
Use this layout conceptually:
/var/www/international-intelligence/
├── releases/
│ ├── 2026-07-28.2+git.9183abc/
│ ├── 2026-08-01.3+git.ab12cd3/
│ └── ...
├── current -> releases/2026-08-01.3+git.ab12cd3/
├── shared/
│ ├── config/
│ ├── runtime/
│ ├── logs/
│ └── uploads/
└── bin/
└── daily-brief-launcher
The stable launcher should resolve current once, verify that the release contains a signed or hashed manifest, load that release’s bootstrap, and record the resolved realpath and release ID. It should never write process state into the release directory.
Whether cron should target current or a pinned release depends on migration compatibility:
- For routine operation, target the stable launcher and let it resolve the active release.
- During deployment, pause advancement briefly or use a release-compatibility gate.
- A process already reserved under release A may continue only if release B declares its persisted-state contract compatible.
- Otherwise, release A finishes or checkpoints before the active pointer changes.
- The authority—not cron—decides whether a trigger from another release can resume the process.
Preventing two releases from serving one process
Each process should persist:
created_by_release_idminimum_reader_contractmaximum_reader_contract, where necessarywriter_contractsite_instance_idstate_schema_version
A web release may display a process only if it understands its snapshot contract. A worker may mutate it only if its writer contract is permitted. This allows display compatibility without permitting two writer versions.
Release-rollout sequence
sequenceDiagram
participant D as Deployment Controller
participant R as New Immutable Release
participant DB as Authority Store
participant F as PHP-FPM
participant C as CDN
participant B as Browser Synthetic
D->>R: Install dependencies and build hashed assets
D->>R: Run offline runtime and schema compatibility checks
D->>DB: Verify no incompatible active writer
D->>R: Run doctor against production read-only dependencies
D->>D: Atomically switch current symlink
D->>F: Graceful reload / verified OPcache reset
D->>C: Purge HTML, service-worker script, and mistaken API entries
D->>B: Fetch canonical host with cache bypass
B-->>D: New release + same site_instance_id
D->>B: Run status, locale, alternate-host, and trigger synthetics
B-->>D: Acceptance gate passes
Rollback sequence
sequenceDiagram
participant O as Operator
participant DB as Authority Store
participant D as Deployment Controller
participant F as PHP-FPM
participant C as CDN
participant S as Synthetic Monitor
O->>DB: Check writer-contract compatibility
DB-->>O: Previous release may read/write current state
O->>D: Select previous immutable release
D->>D: Atomically repoint current
D->>F: Graceful reload / reset OPcache
D->>C: Purge HTML and service-worker entry
D->>S: Run rollback test suite
S-->>D: Release old, site instance unchanged, revisions monotonic
alt Prior release cannot write current schema
O->>DB: Put advancement in safe read-only mode
O->>D: Deploy forward-fix instead of destructive rollback
end
Rollback must not reverse database revisions, reuse a prior process ID, or replace a new authoritative snapshot with an older snapshot. If the earlier release cannot safely understand current state, the correct rollback is read-only service plus a forward fix.
Canonical origin, cache control, and edge delivery
Canonical-origin gate
Host validation must occur before:
- session startup;
- cookie creation;
- CSRF-token creation;
- state-store selection;
- process initialization;
- lock or lease acquisition;
- publication eligibility checks;
- operator authentication side effects;
- publication logic.
HTTP routing depends critically on the target URI’s authority or Host value. RFC 9110 warns that incorrect handling can misdirect requests and create cache-poisoning risks; servers can reject deceptive or misdirected routing with an error rather than processing it. RFC 7239 likewise warns that forwarded information can be modified by clients or intermediaries and is trustworthy only within a defined proxy trust boundary.
The gate should follow this algorithm:
- Obtain the connection peer address.
- Trust
ForwardedorX-Forwarded-*only when that peer is an explicitly configured proxy. - Parse exactly one effective scheme, host, and port according to the deployment’s proxy topology.
- Reject multiple, malformed, empty, control-character-bearing, or syntactically invalid host values.
- Lowercase the DNS hostname, remove a trailing dot according to policy, convert internationalized names through a consistent IDNA policy, and normalize default ports.
- Compare against an allowlist, never against a suffix or substring.
- Construct redirects from a static configured canonical origin plus the validated path and query.
- Do not derive the redirect destination from an untrusted host or forwarded-host value.
- For safe
GETandHEAD, return a permanent canonical redirect. - For unsafe or state-changing methods, reject the alternate-host request rather than redirecting it.
- Set no application cookie and initialize no state before completing this decision.
Redirect semantics
A 308 Permanent Redirect preserves the method and request content. That makes it useful for permanent canonicalization when preserving the method is intentional, but preserving an unsafe method toward another origin is precisely why the application should normally reject alternate-host POST, PUT, PATCH, and DELETE requests instead of redirecting them.
Recommended behavior:
| Request | Canonical host | Alternate allowed host | Unknown or malformed host |
|---|---|---|---|
GET | Process normally | 308 to static canonical origin, preserving path and query | 400 or 421 |
HEAD | Process normally | 308, no body | 400 or 421 |
OPTIONS | Serve narrowly defined policy on canonical host | Reject unless edge-specific CORS behavior requires otherwise | Reject |
POST/PUT/PATCH/DELETE | Authenticate and process | 421 Misdirected Request, 400, or 403; no redirect | Reject |
| Scheduler trigger | Require canonical internal route and authenticated principal | Reject and log security event | Reject |
| Operator action | Canonical host only | Reject before session or authorization side effects | Reject |
Query strings may be preserved for safe redirects, but secrets should not be placed in query strings. The application must encode and append the existing validated request path/query; it must never accept a user-supplied full destination URL.
Alternate-host rejection sequence
sequenceDiagram
participant U as Client
participant E as Edge or Reverse Proxy
participant G as Pre-Bootstrap Host Gate
participant A as Application
U->>E: POST https://alternate.example/operator/advance
E->>G: Forward with normalized trusted metadata
G->>G: Host is allowed alternate, but method is unsafe
G-->>U: 421/400/403 + Cache-Control: no-store
Note over G,A: No session, cookie, lock, process, or operator action
Two hostnames mapped to different roots
If www.example reaches release B while example or an old CDN origin reaches release A, application code in B cannot force A to execute B’s redirect logic. Every request to the stale origin runs whatever code and web-server configuration exist there.
Controls are therefore required outside the application:
| Layer | Required control |
|---|---|
| DNS | Remove obsolete origin records; keep a documented hostname inventory; use a controlled decommission period |
| TLS/load balancer | Bind all public names to one canonical edge policy; reject unknown SNI/host combinations |
| Reverse proxy | Canonicalize or reject before PHP; avoid per-vhost document-root drift |
| CDN | Map all aliases to the same origin pool and cache policy; block direct unintended origins |
| Hosting configuration | One active production document root or identical edge redirect vhosts |
| Deployment | Enumerate and update every vhost/origin; no undocumented manually copied roots |
| Synthetic monitoring | Probe each hostname, with SNI and Host combinations, from multiple networks |
| Application | Expose site_instance_id and release_id so any residual split is obvious |
Cache-layer map
| Layer | Can cause stale display? | Required policy |
|---|---|---|
| PHP/application cache | Yes | Status reads authoritative records or uses tightly invalidated in-process data |
| Web-server cache | Yes | Explicit status/operator location bypass |
| Reverse proxy | Yes | Never cache status or mutation routes; do not ignore origin cache headers |
| CDN | Yes | Route-level bypass, not merely origin headers |
| Intermediary cache | Yes | Standards-compliant no-store; HTTPS reduces uncontrolled intermediary behavior |
| Browser HTTP cache | Yes | Response no-store; fetch with cache: "no-store" |
| Service worker/Cache Storage | Yes | Network-only for status and operator routes; never cache.put() them |
| Back-forward cache | Yes, as restored DOM/memory | On pageshow, fetch status before declaring live |
| Initial server-rendered HTML | Yes | Label provisional; reconcile immediately |
| In-memory JavaScript state | Yes | Monotonic process/revision reducer |
localStorage | Yes | Notification/fallback only; never authority |
BroadcastChannel | Yes if misused | Codes and identifiers only; recipient still validates ordering and may refetch |
Service-worker Cache Storage is independent of the HTTP cache. The service-worker specification states that Cache entries do not update or expire automatically and do not disappear just because the service-worker script changes; authors must version and delete them deliberately.
Exact endpoint policies
Live public status
Recommended origin response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: no-store, max-age=0
Pragma: no-cache
Expires: 0
Surrogate-Control: no-store
CDN-Cache-Control: no-store
X-Site-Instance-ID: prod-us-central-01
X-Release-ID: 2026-08-01.3+git.ab12cd3
X-Snapshot-Generated-At: 2026-08-01T12:05:30Z
X-Request-ID: req_01J...
Additionally:
- Configure an explicit edge rule to bypass cache for the status pathname.
- Do not rely on a random query parameter as the permanent control.
- Do not emit
stale-while-revalidateorstale-if-error. - Normally omit
ETagandLast-Modified; a304optimization is not valuable for a small live status document where freshness proof is more important. - If validators are retained for bandwidth reasons, use
no-cache, private, max-age=0, must-revalidaterather than claiming that such a response is unstored. For the process-authority status, I still preferno-store. - Include a response request ID and snapshot-generation timestamp so a monitor can prove origin freshness.
- Suppress cookies from the public status endpoint.
RFC 9111 defines no-cache as a requirement to validate before reuse, not a prohibition on storage. no-store is therefore the clearer choice where a live status snapshot must not persist in shared or private HTTP caches. RFC 9111 also permits extensions and local cache configuration to affect behavior, so the CDN route must be tested and configured explicitly.
Cloudflare’s current default-cache documentation says origin cache directives are normally respected, but cache rules and edge-TTL behavior can override normal handling. Its cache-status documentation distinguishes bypassed, stale, revalidated, and cache-hit outcomes. Apache and Nginx likewise expose directives capable of changing or ignoring origin cache behavior.
Authorized operator reads
Cache-Control: no-store, private, max-age=0
Pragma: no-cache
Expires: 0
Vary: Authorization, Cookie
The endpoint must also enforce authentication, CSRF protection where cookies are used, canonical origin, and explicit method handling. private alone is insufficient because it still permits a private browser cache to store the response.
Operator and scheduler mutations
Use:
Cache-Control: no-store, private
Return an immutable trigger receipt rather than a potentially cached full status body. Require idempotency or trigger IDs.
Initial public HTML
A reasonable policy is:
Cache-Control: no-cache, max-age=0, must-revalidate
This allows storage but forces revalidation. The page must visibly indicate that embedded status is provisional until the first live API response.
Hashed JavaScript and CSS
For content-addressed filenames:
Cache-Control: public, max-age=31536000, immutable
A filename such as daily-brief.ab12cd3.js is safe to cache for a long duration because changed bytes produce another URL. This solves stale asset reuse only when every HTML document and service worker points to the new URL. It does not solve cached /api/status, because that URL and representation evolve in place.
Cache-bypassed retrieval sequence
sequenceDiagram
participant B as Browser
participant SW as Service Worker
participant C as CDN
participant R as Reverse Proxy
participant A as Status API
B->>SW: fetch /api/daily-brief/status<br/>cache: no-store
SW->>C: Network-only; no Cache Storage match
C->>C: Route-level cache bypass
C->>R: Forward request with request ID
R->>R: Proxy cache bypass
R->>A: Authoritative GET
A-->>R: no-store snapshot + generated_at
R-->>C: no-store
C-->>SW: BYPASS/DYNAMIC response
SW-->>B: Unstored authoritative snapshot
B->>B: Verify site instance, process, revision, request sequence
CDN and service-worker update strategy
For the status and operator routes:
- CDN cache rule: bypass.
- Worker/service-worker fetch handler: direct network fetch.
- Cache API: no
match,put, runtime fallback, or offline substitution. - Offline behavior: display the last accepted in-memory snapshot only with a prominent offline label and its age.
- Error behavior: do not return an old successful status body as though it were live.
- CDN “serve stale on error”: disabled for authority status.
stale-while-revalidate: disabled because it intentionally serves old data while fetching new data. Cloudflare documents that behavior as asynchronous stale delivery followed by background revalidation.
For the service-worker script itself:
- Serve with short revalidation or
no-cache, not a year-long immutable policy. - Use a versioned cache name tied to the release contract.
- During activation, delete caches owned by incompatible releases.
- Do not call
skipWaiting()blindly if the new worker cannot safely control pages running old JavaScript. - Either coordinate activation through a “new version available” reload flow or guarantee cross-version message/API compatibility.
- Expose the controlling service-worker version in the browser diagnostic panel.
- Include a “network-only status route” automated test in every release.
Client convergence, status freshness, and browser behavior
Authoritative snapshot contract
Every status response should include:
{
"schema_version": 3,
"site_instance_id": "prod-us-central-01",
"release_contract": {
"serving_release_id": "2026-08-01.3+git.ab12cd3",
"writer_release_id": "2026-08-01.3+git.ab12cd3",
"status_contract_version": 3
},
"process_id": "proc_01J...",
"target_date": "2026-08-01",
"revision": 17,
"stage_code": "PROVIDER_WAIT",
"provider_state_code": "PENDING",
"health_code": "HEALTHY_WAIT",
"last_meaningful_progress_at": "2026-08-01T12:04:54Z",
"last_provider_poll_at": "2026-08-01T12:05:10Z",
"server_checked_at": "2026-08-01T12:05:30Z",
"snapshot_generated_at": "2026-08-01T12:05:30Z",
"next_eligible_cycle_at": "2026-08-02T12:00:00Z",
"evidence_counts": {
"expected": 12,
"received": 8,
"accepted": 7
},
"deficit_codes": ["PROVIDER_ITEMS_MISSING"],
"next_action_code": "POLL_PROVIDER",
"cache_observation": {
"age_seconds": 0,
"edge_status": "BYPASS"
}
}
Localized prose should not appear in the authoritative state model. English and Spanish clients map the same codes through independent locale resources.
Reducer and ordering rules
I recommend a single reducer that applies these rules:
| Incoming condition | Required behavior |
|---|---|
| Same site instance, same process, higher revision | Accept atomically |
| Same site instance, same process, equal revision | No state change; optionally update browser-only observation time |
| Same site instance, same process, lower revision | Reject and record stale-response telemetry |
| Same site instance, different process with authoritative succession evidence | Replace old process atomically |
| Different site instance | Freeze “live” indication, show origin warning, perform hard canonical refresh |
| Response to older request sequence | Reject even if arrival is later |
| Snapshot schema unsupported | Show compatibility error and reload current assets |
| Network failure | Preserve snapshot as explicitly stale/offline; never advance it |
| Browser message only | Validate identifiers; optionally request API immediately; never authorize advancement |
| Initial HTML only | Display provisional status until API reconciliation completes |
A “new process” should not be accepted merely because its process ID differs. The snapshot should carry a server-authoritative process succession relation or target-cycle ordering so a delayed response from an old origin cannot invent a replacement.
A practical ordering key is:
(site_instance_id, process_generation, process_id, revision)
process_generation should be monotonically allocated by the authority. Timestamps are supporting evidence, not the primary order, because clocks can differ and responses can be delayed.
Stale-response rejection sequence
sequenceDiagram
participant B as Browser Reducer
participant API as Status API
B->>API: Request sequence 41
B->>API: Request sequence 42
API-->>B: seq 42, process P, revision 18
B->>B: Accept P/18; latest_sequence=42
API-->>B: delayed seq 41, process P, revision 17
B->>B: Reject because sequence < 42 and revision < 18
Note over B: DOM never regresses
Two-tab convergence
BroadcastChannel permits same-storage-key contexts to exchange structured messages, but eligible recipients must be active contexts. The HTML standard reports support across current Chromium, Firefox, and Safari generations. It remains a notification mechanism rather than persistent authority.
sequenceDiagram
participant T1 as Active Tab
participant API as Authority API
participant BC as BroadcastChannel
participant T2 as Background Tab
T1->>API: GET authoritative status
API-->>T1: P/revision 18
T1->>T1: Validate and accept
T1->>BC: {site, process, revision, stage_code}
BC-->>T2: Notification
T2->>T2: Validate identifiers
alt Payload is newer than local state
T2->>API: Read-only confirmation fetch
API-->>T2: P/revision 18
T2->>T2: Accept authoritative snapshot
else Equal or older
T2->>T2: Ignore/no-op
end
The fallback is a localStorage notification key whose value contains only a random event ID plus process/revision identifiers. The storage standard dispatches events to equivalent storage contexts, but it also explicitly warns that local storage has no general locking mechanism and can fail or be disabled by policy. It must not generate unique process IDs or coordinate publication locks.
English and Spanish convergence
sequenceDiagram
participant EN as English Client
participant ES as Spanish Client
participant API as Status API
participant BC as Cross-Tab Channel
EN->>API: GET /api/status
ES->>API: GET /api/status
API-->>EN: P/18, stage_code=PROVIDER_WAIT
API-->>ES: P/18, stage_code=PROVIDER_WAIT
EN->>EN: Render "Waiting for provider"
ES->>ES: Render localized Spanish label
EN->>BC: P/18 + codes only
BC-->>ES: P/18 + codes only
ES->>ES: Equal revision; no authoritative state change
Note over EN,ES: Identical process and revision; locale prose is independent
Status-freshness model
A PID or process ID must never by itself produce a green “live” state.
| Timestamp or value | Meaning | UI use |
|---|---|---|
last_meaningful_progress_at | Last durable stage/evidence/revision advancement | Primary stall detector |
last_provider_poll_at | Last attempted provider observation | Shows polling activity, not progress |
heartbeat_at | Last worker lease heartbeat | Shows worker liveness |
server_checked_at | Time authority evaluated health | Shows recency of server decision |
snapshot_generated_at | Time JSON was serialized | Helps identify replayed/cached bodies |
HTTP Age or CDN cache metadata | Time held by an intermediary | Must be zero/absent for live status |
Browser received_at | Local time response arrived | “Checked moments ago” only |
Browser offline_since | Start of known connectivity loss | Prominent offline-age label |
next_eligible_cycle_at | Earliest expected next process cycle | Prevents normal idle periods appearing broken |
health_code | Server-derived health based on stage-specific thresholds | Primary status category |
Suggested server health states:
| Health code | Meaning |
|---|---|
IDLE_NOT_ELIGIBLE | No cycle should be running yet |
HEALTHY_PROGRESS | Meaningful progress within stage-specific threshold |
HEALTHY_WAIT | Waiting is expected and recent provider polling/heartbeat exists |
DEGRADED_NO_PROGRESS | Worker is alive but progress threshold exceeded |
STALE_HEARTBEAT | Process owns a lease but heartbeat is late |
LEASE_EXPIRED_RECOVERABLE | Previous worker lost ownership; another trigger may resume |
BLOCKED_DEFICIT | Required evidence remains missing |
FAILED_RETRYABLE | Temporary failure and retry policy exists |
FAILED_PERMANENT | Operator intervention required |
ORIGIN_MISMATCH | Site-instance or release contract is inconsistent |
OFFLINE_CLIENT | Browser-only display condition, not a server health code |
Stage-specific thresholds matter. Ten minutes without a revision may be normal while waiting for a provider but abnormal during a local render stage expected to last seconds.
Browser compatibility and throttling
Background execution cannot be treated as a scheduler. Chromium documents intensive timer throttling for qualifying long-hidden pages, with timers checked on a much coarser cadence; request-animation callbacks also stop in background pages. WebKit documents background timer throttling and notes that iOS can suspend background tabs completely. Firefox likewise manages or unloads background tabs under resource pressure.
| Capability or behavior | Chromium family | Firefox | Safari macOS | Safari/iOS | Required design |
|---|---|---|---|---|---|
| BroadcastChannel | Supported | Supported | Supported in current releases | Supported in current releases | Feature-detect; storage-event fallback |
| Background timers | Aggressively throttled after qualifying hidden periods | Throttled; background lifecycle is resource-sensitive | Throttled | May be suspended entirely | Hidden tabs use low-frequency best-effort polling |
requestAnimationFrame in background | Paused | Generally paused | Paused | Paused/suspended | Never drive polling from animation frames |
| Tab unloading/discard | Possible | Possible | Possible | Common under memory pressure | Treat resume as cold reconciliation |
| Service worker | Supported | Supported | Supported | Supported with platform lifecycle constraints | Network-only status route; versioned cache cleanup |
| Back-forward restoration | Supported | Supported | Supported | Supported | Handle pageshow; refetch when restored |
localStorage events | Broad support | Broad support | Broad support | Broad support | Notification only; catch access exceptions |
| Private browsing | Storage/persistence constraints can differ | Constraints can differ | Constraints can differ | Constraints can differ | Feature-detect and continue without persistence |
| Online/offline events | Available but not proof of origin reachability | Same | Same | Same | Confirm with actual status request |
| Multiple windows | Supported | Supported | Supported | Limited by mobile UI/lifecycle | API remains authority |
| Orientation changes | No authority effect | No authority effect | No authority effect | Can accompany suspension/layout changes | Re-render, but do not mutate process state |
WHATWG defines pageshow.persisted so a page can detect restoration from retained session history rather than a fresh load. On every pageshow, and especially when persisted is true, the client should immediately mark the DOM provisional and fetch authoritative status.
Fallback protocol
The client should:
- Fetch immediately after page initialization.
- Refetch on
visibilitychangewhen a page becomes visible. - Refetch on
pageshow, including back-forward-cache restoration. - Refetch after a successful network reconnection.
- Keep a low-frequency, jittered, read-only poll while hidden when the browser permits.
- Expect missed hidden polls and reconcile on resume.
- Use BroadcastChannel as the preferred wake-up hint.
- Use the storage event as a fallback wake-up hint.
- Use neither mechanism to create process state or invoke advancement.
- Abort superseded requests where possible and still enforce sequence/revision checks.
- Display “offline” or “status unavailable” when no current authoritative response exists.
- Never solve throttling merely by reducing the polling interval; browsers may coalesce or suspend it regardless.
Production testing, deployment, and rollback controls
Synthetic test matrix
Every synthetic response should record DNS answer, TLS certificate/SNI, resolved origin, HTTP status, redirect chain, release ID, site-instance ID, request ID, cache status, Age, snapshot time, process ID, and revision.
| Test | Method | Expected result | Failure isolated |
|---|---|---|---|
| Canonical public page | GET canonical English and Spanish pages | Same site instance and release | Locale/vhost split |
| Alternate-host safe request | GET each alias | One 308 to configured canonical origin; path/query preserved | Edge canonicalization |
| Alternate-host mutation | Authenticated test POST with no effect | Rejected without cookie, session, trigger, or lock | Late host enforcement |
| Unknown Host | Direct edge/origin probe where authorized | 400/421, never default vhost | Host-routing weakness |
| Status freshness | Repeated status requests | no-store; zero/absent Age; advancing request IDs/timestamps | Browser/CDN/proxy cache |
| Cache-busted pair | Ordinary and unique diagnostic query | Same authoritative revision and fresh generation time | Hidden cache or cache-key issue |
| Service-worker clean profile | New browser profile | Same status as established profile | Stale worker/cache |
| Service-worker bypass | Browser with worker bypassed | Same authoritative result | Worker interception |
| CLI doctor | Scheduler runtime | Expected PHP, INI, extension, UID, CWD, release, site instance | PHP drift |
| Web doctor | Authorized web runtime | Contract matches CLI where required | FPM drift |
| Scheduler canary | Status-only trigger | Trigger receipt and heartbeat, no publication mutation | Scheduler delivery |
| Duplicate trigger | Two trigger IDs for one cycle | One process and revision lineage | Idempotency |
| Lease-expiry recovery | Controlled test process stops renewing | New worker resumes only after expiry | Permanent lock |
| Delayed-response race | Artificially delay older status response | UI never regresses | Client reducer |
| Background resume | Hide/suspend tab, progress server, resume | Immediate reconciliation | Timer dependency |
| Back-forward restore | Navigate away/back after server progress | Provisional state then current API state | bfcache staleness |
| Cross-locale | Open English and Spanish simultaneously | Same process/revision/codes | Localized-state divergence |
| Cross-host process | Query every public hostname | No different site instance or process lineage | Root/origin split-brain |
| FPM OPcache | Deploy release canary | Web response changes only after verified reload gate | Stale bytecode |
| Rollback | Controlled prior release | Site instance unchanged; revisions do not decrease | Unsafe rollback |
| DST simulation | Test eligibility around spring/fall transitions | Exactly one cycle per target date | Local-time scheduling bug |
| Separate filesystem sentinel | CLI/web read same read-only sentinel hash | Identical identity | Mount split |
| CDN stale-on-error | Controlled nonproduction origin failure | Status becomes unavailable, not falsely live | Edge stale serving |
| Offline browser | Disable network | Explicit offline label and increasing offline age | Stale snapshot masquerading as live |
Scheduled-trigger acceptance checks
A scheduler test is not complete when the scheduler reports an HTTP 2xx. The monitor must correlate:
scheduler execution
→ trigger receipt
→ reservation result
→ heartbeat
→ meaningful revision or healthy no-op
→ status API visibility
→ browser-facing synthetic visibility
Alert separately on:
- no scheduler execution;
- execution without receipt;
- receipt without reservation decision;
- reservation without heartbeat;
- heartbeat without meaningful progress;
- authoritative progress not visible at the canonical status endpoint;
- canonical endpoint current but browser synthetic stale.
This decomposition identifies the failing layer rather than reporting only “Daily Brief broken.”
Deployment checklist
| Phase | Required control |
|---|---|
| Build | Immutable release ID, dependency lock, asset manifest, status-contract version |
| Preflight | CLI and FPM compatibility, required extensions, schema compatibility, path and permission checks |
| Install | New release directory only; no in-place edits to current release |
| State gate | Confirm compatible active processes or pause/resume strategy |
| Switch | Atomic pointer or load-balancer target change |
| PHP | Graceful FPM reload or verified FPM-side OPcache invalidation |
| Scheduler | Doctor invocation resolves intended launcher and active release |
| CDN | Ensure API bypass; purge HTML, service-worker script, and accidentally cached API objects |
| Service worker | Verify script update, cache version, activation compatibility, network-only status route |
| Canonical hosts | Probe all aliases and direct-origin paths permitted to monitors |
| Browser | Clean and established profiles; English and Spanish; multiple tabs |
| Acceptance | Site-instance stable, release expected, status fresh, duplicate trigger idempotent |
| Rollback readiness | Prior immutable release retained and compatibility result known |
| Observation | Monitor at least one complete advancement cycle with correlated trace IDs |
Rollback checklist
A rollback should:
- stop new incompatible writers;
- retain the authoritative database and monotonic revision history;
- atomically restore the previous compatible release;
- reload FPM;
- purge affected HTML and service-worker entry points;
- leave hashed assets immutable;
- verify scheduler launcher resolution;
- run canonical-host, status, locale, and duplicate-trigger tests;
- resume advancement only after writer-contract compatibility is established.
Do not delete or “reset” the current process merely to make an older release appear healthy. Preserve the process record and use an explicit supersession or recovery transition.
Remediation roadmap, uncertainties, acceptance criteria, and reading list
Prioritized remediation roadmap
| Priority | Action | Why first | Evidence of completion |
|---|---|---|---|
| Immediate | Add site_instance_id, serving release, writer release, status contract, snapshot time, request ID, and cache observation to status responses | Makes split-brain and stale delivery visible | Every hostname returns traceable identity |
| Immediate | Enforce no-store plus explicit CDN/reverse-proxy/service-worker bypass on status and operator routes | Cached authority state is a direct correctness failure | Multi-region synthetics show no cache hits or Age |
| Immediate | Create authenticated CLI and web doctor reports | Quickly exposes PHP, path, secrets, and mount drift | Contract diff is empty or explicitly approved |
| Immediate | Verify scheduler existence, next run, command, PHP binary, release path, logs, and exit capture | Internal tests cannot substitute for production scheduling | Trigger trace from scheduler to authority |
| Immediate | Make reservation transactional, expiring, token-bound, and datastore-clock-based | Prevents duplicate work and permanent locks | Duplicate and lease-expiry tests pass |
| High | Implement monotonic browser reducer with request sequence rejection | Prevents visual regression despite correct server state | Artificial delayed-response test passes |
| High | Move canonical-origin enforcement before PHP application bootstrap where possible | Prevents alternate-host state side effects | Unsafe alias requests create no cookie or record |
| High | Consolidate all vhosts/CDN origins onto one document root/site instance | Eliminates stale-origin split-brain | Host inventory and synthetic matrix agree |
| High | Adopt immutable release directories and FPM reload gate | Eliminates in-place deploy and OPcache ambiguity | Rollout reports exact release through web and CLI |
| High | Add stage-aware health based on meaningful progress and heartbeat | PID alone is misleading | UI distinguishes waiting, stalled, offline, and failed |
| Medium | Use primary scheduler plus delayed independent fallback | Improves trigger availability | Primary-loss exercise still reserves one process |
| Medium | Convert long advancement to resumable work units | Reduces host runtime-limit risk | Forced termination resumes without duplication |
| Medium | Version and audit service-worker caches | Eliminates long-lived client split-brain | Established-profile upgrade test passes |
| Medium | Schedule in UTC and test publication-date computation over DST | Eliminates ambiguous wall-clock execution | Spring/fall simulations create one cycle |
| Ongoing | Run post-deploy and periodic production synthetics | Detects regressions outside application tests | Alerting tied to each layer’s contract |
Key uncertainties and evidence gaps
The most important unresolved questions are:
| Gap | Why it matters | Minimum evidence needed |
|---|---|---|
| Is any scheduler installed and enabled? | Without it, no autonomous advancement occurs | Scheduler configuration and last execution |
| Which release does it invoke? | Old code may update incompatible or invisible state | Executed script realpath and release ID |
| Do CLI and FPM share the same state store? | Both can appear healthy while observing different worlds | Redacted datastore identity hash |
| How many public origins/document roots exist? | An old origin can evade current application redirects | DNS, CDN, LB, vhost, and document-root inventory |
| Is status cached at the edge? | Browser may never see progress | Edge rule export and synthetic cache evidence |
| Is a service worker registered? | It can intercept despite correct HTTP headers | Registration, scope, script version, cache names |
| What is the lease implementation? | A stale lock may block every valid trigger | Lease token, owner, expiry, renewal history |
| What is the cycle timezone rule? | DST and date-boundary errors can look intermittent | IANA timezone and UTC eligibility examples |
| Are English and Spanish separate deployments? | Locale-specific roots may diverge | Release/site-instance headers on both |
| Is browser status acceptance monotonic? | Delayed responses can visually undo progress | Client telemetry or controlled race test |
Acceptance criteria
Production should not be declared reliable until all of the following are true:
Scheduler and authority
- At least one production scheduler is demonstrably enabled.
- Every run supplies a unique trigger ID and UTC timestamp.
- Every trigger receipt records trigger type, authenticated identity, expected origin, release, and site instance.
- Duplicate triggers for the same cycle create exactly one process lineage.
- Locks are expiring leases with token-bound renewal.
- A stopped worker becomes recoverable after a bounded expiry.
- The external scheduler cannot set process ID, revision, stage, success, or next cycle.
- Scheduler
2xxacceptance is not confused with publication completion. - UTC cadence and local publication-date calculation pass both DST-transition simulations.
Runtime and deployment
- CLI and FPM report approved PHP versions, INI contracts, extensions, paths, secrets references, site instance, and state-store identity.
- Scheduler commands use absolute paths.
- No production state depends on the current working directory or ambient temporary directory.
- Releases are immutable and identified in every trigger and response.
- The active release switch is atomic.
- FPM OPcache reset or reload is verified in the FPM runtime.
- Scheduler and web execution resolve a compatible release.
- Rollback preserves monotonic revisions and process identity.
- Two releases cannot concurrently mutate one process unless explicitly writer-compatible.
Origin security
- Canonical-host validation runs before cookies, sessions, locks, state, and authorization side effects.
- Safe alternate-host requests receive a deterministic canonical redirect.
- Unsafe alternate-host requests are rejected.
- Redirect destinations are constructed from static configuration.
- Forwarded hosts are trusted only from explicit proxy addresses.
- Malformed and unknown hosts never reach the normal application.
- All hostnames and origin paths resolve to one site instance or to an edge-level rejection/redirect.
Cache and CDN
- Public status and operator endpoints return
Cache-Control: no-store. - Reverse proxies and CDNs have explicit route-level bypass rules.
- Status responses do not use stale-while-revalidate or stale-if-error.
- CDN failure does not turn an old status into apparently live status.
- Browser fetches use
cache: "no-store". - The service worker uses network-only handling for status and mutation routes.
- Cache Storage contains no status or operator responses.
- Query-string cache busting is diagnostic only, not the primary policy.
- Hashed assets are immutable and HTML/service-worker entry points are revalidated.
Browser convergence
- Initial HTML is labeled provisional until an API response arrives.
- Same-process lower revisions are rejected.
- Equal revisions are no-ops except for browser-only observation times.
- A new process replaces the prior snapshot atomically.
- Different site-instance IDs force a visible warning and origin refresh.
- Older request sequences cannot overwrite newer responses.
- Background tabs reconcile on visibility and page restoration.
- Offline state is unmistakably labeled with offline age.
- BroadcastChannel and local storage cannot authorize or advance work.
- English and Spanish render the same codes and identifiers with independent localized strings.
- A process ID without recent meaningful progress does not produce a live indicator.
Observability
- The status UI separately displays meaningful progress, provider poll, server check, snapshot generation, browser check, cache age, and offline age.
- Every layer can be correlated through trigger, trace, request, process, release, and site-instance identifiers.
- Scheduler output and errors are retained outside transient cron mail.
- Synthetic monitoring covers every public hostname, both languages, clean and established browser profiles, cache bypass, background restoration, and duplicate triggers.
- Post-deploy checks block rollout completion when identity, freshness, or convergence contracts fail.
Prioritized official reading list
| Priority | Source | Why it matters | URL |
|---|---|---|---|
| Essential | RFC 9111, HTTP Caching | Normative definitions of no-store, no-cache, private/shared cache, validation, Age, Vary, and stale reuse | https://www.rfc-editor.org/rfc/rfc9111.html |
| Essential | RFC 9110, HTTP Semantics | Host/authority routing, safe and unsafe methods, redirects, 308 behavior, and misdirected requests | https://www.rfc-editor.org/rfc/rfc9110.html |
| Essential | RFC 7239, Forwarded HTTP Extension | Trusted-proxy and forwarded-header security considerations | https://www.rfc-editor.org/rfc/rfc7239.html |
| Essential | PHP configuration-file documentation | PHP configuration discovery and SAPI startup behavior | https://www.php.net/manual/en/configuration.file.php |
| Essential | PHP-FPM configuration | Pool users, environments, working directories, output handling, and PHP options | https://www.php.net/manual/en/install.fpm.configuration.php |
| Essential | PHP OPcache configuration | Timestamp validation, CLI OPcache, path keys, and required resets | https://www.php.net/manual/en/opcache.configuration.php |
| Essential | systemd timer manual | Calendar timers, persistence, accuracy, and timer activation | https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html |
| Essential | systemd execution environment | Users, working directories, environment, credentials, logging, and process execution | https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html |
| High | crontab manual | Cron fields, timezone handling, environment, and implementation caveats | https://man7.org/linux/man-pages/man5/crontab.5.html |
| High | cPanel Cron Jobs | Shared-host scheduling, absolute paths, overlap warning, and cron mail behavior | https://docs.cpanel.net/cpanel/advanced/cron-jobs/ |
| High | Google Cloud Scheduler troubleshooting | Duplicate delivery, idempotency, logs, retries, and UTC/DST guidance | https://cloud.google.com/scheduler/docs/troubleshooting |
| High | AWS EventBridge Scheduler | At-least-once delivery, retries, flexible windows, and target behavior | https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html |
| High | WHATWG BroadcastChannel | Same-origin/storage-key messaging semantics and active-context eligibility | https://html.spec.whatwg.org/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts |
| High | WHATWG Web Storage | Storage-event behavior, failure conditions, and absence of locking guarantees | https://html.spec.whatwg.org/multipage/webstorage.html |
| High | W3C Service Workers | Cache Storage lifetimes and manual cache versioning | https://www.w3.org/TR/service-workers/ |
| High | WHATWG navigation and history | pageshow, persisted-page restoration, and history lifecycle | https://html.spec.whatwg.org/multipage/nav-history-apis.html |
| High | Page Visibility specification | Reliable visibility-state observation for resume reconciliation | https://www.w3.org/TR/page-visibility-2/ |
| Supporting | Nginx proxy module | Proxy cache controls and origin-header override behavior | https://nginx.org/en/docs/http/ngx_http_proxy_module.html |
| Supporting | Apache mod_cache | Reverse-proxy cache operation and administrative overrides | https://httpd.apache.org/docs/2.4/mod/mod_cache.html |
| Supporting | Cloudflare default cache behavior | Current edge defaults and interaction with origin cache headers | https://developers.cloudflare.com/cache/concepts/default-cache-behavior/ |
| Research | Hidden Web Caches Discovery, 2024 | Empirical technique for identifying caches that do not clearly advertise themselves | https://arxiv.org/abs/2407.16303 |
| Research | The Remote on the Local, 2021 | Security implications of programmable service-worker caches | https://doi.org/10.1109/SPW53761.2021.00062 |
The architectural endpoint is not “poll more often.” It is a system in which every layer can prove that it is observing the same site instance, compatible release, process lineage, revision, and authoritative state—and in which a scheduler, cache, alternate host, old service worker, suspended tab, or delayed response can fail without manufacturing a false picture of publication health.