{"record":{"id":"b0bf6d19b61ec49b","repo":"koala73/worldmonitor","slug":"cloudflare-verification-failed-after-apply","errorCode":null,"errorMessage":"Cloudflare verification failed after apply","messagePattern":"Cloudflare verification failed after apply","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/cloudflare-agent-readiness.mjs","lineNumber":65,"sourceCode":"  const token = resolveToken(env);\n  const zoneId = await resolveZoneId(token, { env, fetchImpl });\n  const read = (phase) => cloudflareRequest(`/zones/${zoneId}/rulesets/phases/${phase}/entrypoint`, { token, fetchImpl });\n  const firewall = await read(FIREWALL_PHASE);\n  const changes = planAgentReadiness(firewall);\n  if (mode !== '--apply' || changes.length === 0) return { zone: 'worldmonitor.app', ready: changes.length === 0, changes };\n\n  for (const change of changes) {\n    const current = await read(change.phase);\n    if (!isDeepStrictEqual(current.rules, firewall.rules)) {\n      throw new Error('Cloudflare rules changed after planning. Run --plan again before applying.');\n    }\n    const updated = await cloudflareRequest(`/zones/${zoneId}/rulesets/${change.rulesetId}/rules/${change.ruleId}`, {\n      token, fetchImpl, method: change.method, body: change.body,\n    });\n    firewall.rules = updated.rules;\n  }\n  const remaining = planAgentReadiness(await read(FIREWALL_PHASE));\n  if (remaining.length) throw new Error('Cloudflare verification failed after apply');\n  return { zone: 'worldmonitor.app', ready: true, applied: changes.map((change) => change.description) };\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n  const mode = process.argv[2];\n  if (process.argv.length !== 3 || !['--plan', '--check', '--apply'].includes(mode)) {\n    console.error('Usage: node scripts/cloudflare-agent-readiness.mjs --plan|--check|--apply');\n    process.exitCode = 1;\n  } else {\n    loadEnvFile(import.meta.url, { only: ['CLOUDFLARE_API_TOKEN', 'CLOUDFLARE_ALL_ACCESS_TOKEN', 'CLOUDFLARE_ZONE_ID'] });\n    runAgentReadiness(mode).then((result) => {\n      console.log(JSON.stringify(result, null, 2));\n      if (mode === '--check' && !result.ready) process.exitCode = 1;\n    }).catch((error) => {\n      console.error(error.message);\n      process.exitCode = 1;\n    });\n  }","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/cloudflare-agent-readiness.mjs#L47-L83","documentation":"After applying all planned changes, runAgentReadiness re-plans against a fresh read of the firewall phase to verify convergence. If any change is still pending — meaning an apply write did not take effect or a rule regressed — it throws 'Cloudflare verification failed after apply'. This is the post-condition check that the zone is actually ready.","triggerScenarios":"An HTTP update returned success but the resulting ruleset still leaves a BLOCK_RULES entry missing, non-block, or disabled, so planAgentReadiness on the re-read returns non-empty changes.","commonSituations":"Cloudflare propagation lag or an eventually-consistent read right after write, a middleware/other automation immediately reverting the rule, or the update API accepting the request while partially applying it.","solutions":["Wait briefly and re-run --check to see if the ruleset settled (propagation delay).","Inspect the phase entrypoint ruleset and compare each rule against the expected block-rule policy to find which rule did not stick.","Check audit logs for other actors that may have reverted the rule right after apply.","Re-run --plan then --apply once the interfering writer is stopped."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const remaining = planAgentReadiness(await readFirewall(token));\nif (remaining.length) {\n  console.error('apply did not converge; pending changes:', remaining.map((c) => c.description));\n}","typeGuard":null,"tryCatchPattern":"try {\n  await runAgentReadiness('--apply', { env, fetchImpl });\n} catch (e) {\n  if (e.message === 'Cloudflare verification failed after apply') {\n    await sleep(5000); // allow propagation to settle\n    await runAgentReadiness('--apply', { env, fetchImpl });\n    return;\n  }\n  throw e;\n}","preventionTips":["Add a bounded retry with backoff around the apply step for convergence lag.","Check Cloudflare audit logs for other actors reverting rules.","Alert on repeated verification failures — that signals an interfering automation, not lag.","Run --check a few minutes after apply in CI as a follow-up verification."],"tags":["cloudflare","verification","post-condition"],"backgroundTag":"api-error-response","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}