[{"data":1,"prerenderedAt":1207},["ShallowReactive",2],{"navigation_docs":3,"-docs-operations-evidence-and-relay":356,"-docs-operations-evidence-and-relay-surround":1202},[4,8,34,64,90,139,157,171,193,227,241,266,312,334],{"title":5,"path":6,"stem":7},"Documentation","\u002Fdocs","docs\u002Findex",{"title":9,"path":10,"stem":11,"children":12},"Getting started","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started\u002Findex",[13,14,18,22,26,30],{"title":9,"path":10,"stem":11},{"title":15,"path":16,"stem":17},"Introduction","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002F01.getting-started\u002F01.introduction",{"title":19,"path":20,"stem":21},"Concepts","\u002Fdocs\u002Fgetting-started\u002Fconcepts","docs\u002F01.getting-started\u002F02.concepts",{"title":23,"path":24,"stem":25},"Quickstart (5 minutes)","\u002Fdocs\u002Fgetting-started\u002Fquickstart","docs\u002F01.getting-started\u002F03.quickstart",{"title":27,"path":28,"stem":29},"Local development","\u002Fdocs\u002Fgetting-started\u002Flocal-development","docs\u002F01.getting-started\u002F04.local-development",{"title":31,"path":32,"stem":33},"FAQ","\u002Fdocs\u002Fgetting-started\u002Ffaq","docs\u002F01.getting-started\u002F05.faq",{"title":35,"path":36,"stem":37,"children":38},"Architecture","\u002Fdocs\u002Farchitecture","docs\u002F02.architecture\u002Findex",[39,40,44,48,52,56,60],{"title":35,"path":36,"stem":37},{"title":41,"path":42,"stem":43},"Architecture overview","\u002Fdocs\u002Farchitecture\u002Foverview","docs\u002F02.architecture\u002F01.overview",{"title":45,"path":46,"stem":47},"Services","\u002Fdocs\u002Farchitecture\u002Fservices","docs\u002F02.architecture\u002F02.services",{"title":49,"path":50,"stem":51},"Request lifecycle","\u002Fdocs\u002Farchitecture\u002Frequest-lifecycle","docs\u002F02.architecture\u002F03.request-lifecycle",{"title":53,"path":54,"stem":55},"Data model","\u002Fdocs\u002Farchitecture\u002Fdata-model","docs\u002F02.architecture\u002F04.data-model",{"title":57,"path":58,"stem":59},"Status and evidence","\u002Fdocs\u002Farchitecture\u002Fstatus-and-evidence","docs\u002F02.architecture\u002F05.status-and-evidence",{"title":61,"path":62,"stem":63},"Target architecture and authority","\u002Fdocs\u002Farchitecture\u002Ftarget-architecture","docs\u002F02.architecture\u002F06.target-architecture",{"title":65,"path":66,"stem":67,"children":68},"Auth","\u002Fdocs\u002Fauth","docs\u002F03.auth\u002Findex",[69,70,74,78,82,86],{"title":65,"path":66,"stem":67},{"title":71,"path":72,"stem":73},"Overview","\u002Fdocs\u002Fauth\u002Foverview","docs\u002F03.auth\u002F01.overview",{"title":75,"path":76,"stem":77},"Organization and agent model","\u002Fdocs\u002Fauth\u002Forg-project-model","docs\u002F03.auth\u002F02.org-project-model",{"title":79,"path":80,"stem":81},"Issuing API keys","\u002Fdocs\u002Fauth\u002Fissuing-api-keys","docs\u002F03.auth\u002F03.issuing-api-keys",{"title":83,"path":84,"stem":85},"Multi-tenant RLS","\u002Fdocs\u002Fauth\u002Fmulti-tenant-rls","docs\u002F03.auth\u002F04.multi-tenant-rls",{"title":87,"path":88,"stem":89},"Operator sessions and step-up","\u002Fdocs\u002Fauth\u002Foperator-sessions","docs\u002F03.auth\u002F05.operator-sessions",{"title":91,"path":92,"stem":93,"children":94},"Proxy","\u002Fdocs\u002Fproxy","docs\u002F04.proxy\u002Findex",[95,96,99,103,107,111,115,119,123,127,131,135],{"title":91,"path":92,"stem":93},{"title":71,"path":97,"stem":98},"\u002Fdocs\u002Fproxy\u002Foverview","docs\u002F04.proxy\u002F01.overview",{"title":100,"path":101,"stem":102},"Authentication","\u002Fdocs\u002Fproxy\u002Fauthentication","docs\u002F04.proxy\u002F02.authentication",{"title":104,"path":105,"stem":106},"Request routing","\u002Fdocs\u002Fproxy\u002Frequest-routing","docs\u002F04.proxy\u002F03.request-routing",{"title":108,"path":109,"stem":110},"Sessions","\u002Fdocs\u002Fproxy\u002Fsessions","docs\u002F04.proxy\u002F04.sessions",{"title":112,"path":113,"stem":114},"Directives","\u002Fdocs\u002Fproxy\u002Fdirectives","docs\u002F04.proxy\u002F05.directives",{"title":116,"path":117,"stem":118},"Idempotency and budgets","\u002Fdocs\u002Fproxy\u002Fidempotency-and-budgets","docs\u002F04.proxy\u002F06.idempotency-and-budgets",{"title":120,"path":121,"stem":122},"Rate limiting","\u002Fdocs\u002Fproxy\u002Frate-limiting","docs\u002F04.proxy\u002F07.rate-limiting",{"title":124,"path":125,"stem":126},"Provider adapters","\u002Fdocs\u002Fproxy\u002Fprovider-adapters","docs\u002F04.proxy\u002F08.provider-adapters",{"title":128,"path":129,"stem":130},"Auth caching","\u002Fdocs\u002Fproxy\u002Fauth-caching","docs\u002F04.proxy\u002F09.auth-caching",{"title":132,"path":133,"stem":134},"Configuration","\u002Fdocs\u002Fproxy\u002Fconfiguration","docs\u002F04.proxy\u002F10.configuration",{"title":136,"path":137,"stem":138},"Provider routing and resilience","\u002Fdocs\u002Fproxy\u002Fprovider-routing-and-resilience","docs\u002F04.proxy\u002F11.provider-routing-and-resilience",{"title":140,"path":141,"stem":142,"children":143},"Memory","\u002Fdocs\u002Fmemory","docs\u002F05.memory\u002Findex",[144,145,149,153],{"title":140,"path":141,"stem":142},{"title":146,"path":147,"stem":148},"Memory overview","\u002Fdocs\u002Fmemory\u002Foverview","docs\u002F05.memory\u002F01.overview",{"title":150,"path":151,"stem":152},"Write path","\u002Fdocs\u002Fmemory\u002Fwrite-path","docs\u002F05.memory\u002F02.write-path",{"title":154,"path":155,"stem":156},"Search and lifecycle","\u002Fdocs\u002Fmemory\u002Fsearch-and-lifecycle","docs\u002F05.memory\u002F03.search-and-lifecycle",{"title":158,"path":159,"stem":160,"children":161},"Context","\u002Fdocs\u002Fcontext","docs\u002F06.context\u002Findex",[162,163,167],{"title":158,"path":159,"stem":160},{"title":164,"path":165,"stem":166},"Assembly pipeline","\u002Fdocs\u002Fcontext\u002Foverview","docs\u002F06.context\u002F01.overview",{"title":168,"path":169,"stem":170},"Ranking and packing","\u002Fdocs\u002Fcontext\u002Franking-and-packing","docs\u002F06.context\u002F02.ranking-and-packing",{"title":172,"path":173,"stem":174,"children":175},"Intelligence","\u002Fdocs\u002Fintelligence","docs\u002F07.intelligence\u002Findex",[176,177,181,185,189],{"title":172,"path":173,"stem":174},{"title":178,"path":179,"stem":180},"Workers","\u002Fdocs\u002Fintelligence\u002Fworkers","docs\u002F07.intelligence\u002F01.workers",{"title":182,"path":183,"stem":184},"Extraction","\u002Fdocs\u002Fintelligence\u002Fextraction","docs\u002F07.intelligence\u002F02.extraction",{"title":186,"path":187,"stem":188},"Embedder","\u002Fdocs\u002Fintelligence\u002Fembedder","docs\u002F07.intelligence\u002F03.embedder",{"title":190,"path":191,"stem":192},"Extraction evaluation","\u002Fdocs\u002Fintelligence\u002Fevaluation","docs\u002F07.intelligence\u002F04.evaluation",{"title":194,"path":195,"stem":196,"children":197},"API reference","\u002Fdocs\u002Fapi-reference","docs\u002F08.api-reference\u002Findex",[198,199,203,207,211,215,219,223],{"title":194,"path":195,"stem":196},{"title":200,"path":201,"stem":202},"Chat completions","\u002Fdocs\u002Fapi-reference\u002Fchat-completions","docs\u002F08.api-reference\u002F01.chat-completions",{"title":204,"path":205,"stem":206},"Responses","\u002Fdocs\u002Fapi-reference\u002Fresponses","docs\u002F08.api-reference\u002F02.responses",{"title":208,"path":209,"stem":210},"Errors","\u002Fdocs\u002Fapi-reference\u002Ferrors","docs\u002F08.api-reference\u002F03.errors",{"title":212,"path":213,"stem":214},"Health and metrics","\u002Fdocs\u002Fapi-reference\u002Fproxy-health","docs\u002F08.api-reference\u002F04.proxy-health",{"title":216,"path":217,"stem":218},"HTTP route inventory","\u002Fdocs\u002Fapi-reference\u002Fhttp-routes","docs\u002F08.api-reference\u002F05.http-routes",{"title":220,"path":221,"stem":222},"Management API","\u002Fdocs\u002Fapi-reference\u002Fmanagement-api","docs\u002F08.api-reference\u002F06.management-api",{"title":224,"path":225,"stem":226},"Auth gRPC (ValidateToken, ValidateAgent)","\u002Fdocs\u002Fapi-reference\u002Fauth-grpc","docs\u002F08.api-reference\u002F07.auth-grpc",{"title":228,"path":229,"stem":230,"children":231},"MCP","\u002Fdocs\u002Fmcp","docs\u002F09.mcp\u002Findex",[232,233,237],{"title":228,"path":229,"stem":230},{"title":234,"path":235,"stem":236},"Memory server","\u002Fdocs\u002Fmcp\u002Fmemory-server","docs\u002F09.mcp\u002F01.memory-server",{"title":238,"path":239,"stem":240},"Operator gateway","\u002Fdocs\u002Fmcp\u002Foperator-gateway","docs\u002F09.mcp\u002F02.operator-gateway",{"title":242,"path":243,"stem":244,"children":245},"Security","\u002Fdocs\u002Fsecurity","docs\u002F10.security\u002Findex",[246,247,251,254,258,262],{"title":242,"path":243,"stem":244},{"title":248,"path":249,"stem":250},"Security overview","\u002Fdocs\u002Fsecurity\u002Foverview","docs\u002F10.security\u002F01.overview",{"title":100,"path":252,"stem":253},"\u002Fdocs\u002Fsecurity\u002Fauthentication","docs\u002F10.security\u002F02.authentication",{"title":255,"path":256,"stem":257},"Tenant isolation","\u002Fdocs\u002Fsecurity\u002Ftenant-isolation","docs\u002F10.security\u002F03.tenant-isolation",{"title":259,"path":260,"stem":261},"Secrets and keys","\u002Fdocs\u002Fsecurity\u002Fsecrets-and-keys","docs\u002F10.security\u002F04.secrets-and-keys",{"title":263,"path":264,"stem":265},"Prompt injection","\u002Fdocs\u002Fsecurity\u002Fprompt-injection","docs\u002F10.security\u002F05.prompt-injection",{"title":267,"path":268,"stem":269,"children":270},"Operations","\u002Fdocs\u002Foperations","docs\u002F11.operations\u002Findex",[271,272,276,280,284,288,292,296,300,304,308],{"title":267,"path":268,"stem":269},{"title":273,"path":274,"stem":275},"Observability","\u002Fdocs\u002Foperations\u002Fobservability","docs\u002F11.operations\u002F01.observability",{"title":277,"path":278,"stem":279},"Traces and ClickHouse","\u002Fdocs\u002Foperations\u002Ftraces-and-clickhouse","docs\u002F11.operations\u002F02.traces-and-clickhouse",{"title":281,"path":282,"stem":283},"Health checks","\u002Fdocs\u002Foperations\u002Fhealth-checks","docs\u002F11.operations\u002F03.health-checks",{"title":285,"path":286,"stem":287},"Incident response","\u002Fdocs\u002Foperations\u002Fincident-response","docs\u002F11.operations\u002F04.incident-response",{"title":289,"path":290,"stem":291},"Troubleshooting","\u002Fdocs\u002Foperations\u002Ftroubleshooting","docs\u002F11.operations\u002F05.troubleshooting",{"title":293,"path":294,"stem":295},"Billing and budgets","\u002Fdocs\u002Foperations\u002Fbilling-and-budgets","docs\u002F11.operations\u002F06.billing-and-budgets",{"title":297,"path":298,"stem":299},"Evidence and relay","\u002Fdocs\u002Foperations\u002Fevidence-and-relay","docs\u002F11.operations\u002F07.evidence-and-relay",{"title":301,"path":302,"stem":303},"Console","\u002Fdocs\u002Foperations\u002Fconsole","docs\u002F11.operations\u002F08.console",{"title":305,"path":306,"stem":307},"Failure modes and recovery","\u002Fdocs\u002Foperations\u002Ffailure-and-recovery","docs\u002F11.operations\u002F09.failure-and-recovery",{"title":309,"path":310,"stem":311},"Data lifecycle and deletion","\u002Fdocs\u002Foperations\u002Fdata-lifecycle-and-deletion","docs\u002F11.operations\u002F10.data-lifecycle-and-deletion",{"title":313,"path":314,"stem":315,"children":316},"Deployment","\u002Fdocs\u002Fdeployment","docs\u002F12.deployment\u002Findex",[317,318,322,326,330],{"title":313,"path":314,"stem":315},{"title":319,"path":320,"stem":321},"Docker Compose (dev)","\u002Fdocs\u002Fdeployment\u002Fdocker-compose","docs\u002F12.deployment\u002F01.docker-compose",{"title":323,"path":324,"stem":325},"Environment variables","\u002Fdocs\u002Fdeployment\u002Fenvironment-variables","docs\u002F12.deployment\u002F02.environment-variables",{"title":327,"path":328,"stem":329},"Kubernetes","\u002Fdocs\u002Fdeployment\u002Fkubernetes","docs\u002F12.deployment\u002F03.kubernetes",{"title":331,"path":332,"stem":333},"Production readiness","\u002Fdocs\u002Fdeployment\u002Fproduction-readiness","docs\u002F12.deployment\u002F04.production-readiness",{"title":335,"path":336,"stem":337,"children":338},"Reference","\u002Fdocs\u002Freference","docs\u002F13.reference\u002Findex",[339,340,344,348,352],{"title":335,"path":336,"stem":337},{"title":341,"path":342,"stem":343},"Glossary","\u002Fdocs\u002Freference\u002Fglossary","docs\u002F13.reference\u002F01.glossary",{"title":345,"path":346,"stem":347},"Roadmap and gates","\u002Fdocs\u002Freference\u002Froadmap","docs\u002F13.reference\u002F02.roadmap",{"title":349,"path":350,"stem":351},"Architecture decisions","\u002Fdocs\u002Freference\u002Fadr","docs\u002F13.reference\u002F03.adr",{"title":353,"path":354,"stem":355},"Compatibility and versioning","\u002Fdocs\u002Freference\u002Fcompatibility","docs\u002F13.reference\u002F04.compatibility",{"id":357,"title":297,"audience":358,"author":359,"authorUrl":359,"body":360,"coverIndex":359,"coverLabel":359,"coverTone":359,"date":359,"decisionStatus":359,"description":1194,"excerpt":359,"extension":1195,"featured":1196,"historical":1196,"meta":1197,"navigation":1090,"path":298,"readingTime":359,"scope":1198,"seo":1199,"sourceOfTruth":1200,"status":367,"stem":299,"tags":359,"verifiedDate":368,"__hash__":1201},"docs\u002Fdocs\u002F11.operations\u002F07.evidence-and-relay.md","operator",null,{"type":361,"value":362,"toc":1179},"minimark",[363,369,373,378,386,413,416,427,431,514,519,593,602,606,624,631,635,697,700,704,711,714,718,775,812,815,1004,1007,1010,1023,1029,1033,1053,1057,1136,1143,1147,1175],[364,365],"page-status",{"note":366,"status":367,"verified":368},"Local outbox and relay exist; production sink and hosted recovery remain open","PROVISIONAL","2026-10-21",[370,371,372],"p",{},"Evidence is written to a PostgreSQL transactional outbox and projected asynchronously by a default-off relay daemon. The outbox is the durable handoff contract; ClickHouse is a pilot projection, not the source of truth.",[374,375,377],"h2",{"id":376},"write-side-contract","Write-side contract",[370,379,380,381,385],{},"The outbox envelope uses ",[382,383,384],"code",{},"evidence.v1"," and carries:",[387,388,389,401,404,407,410],"ul",{},[390,391,392,393,396,397,400],"li",{},"Tenant and event identity: ",[382,394,395],{},"org_id",", ",[382,398,399],{},"event_id",", aggregate ID, aggregate sequence",[390,402,403],{},"Schema and event type",[390,405,406],{},"A payload plus SHA-256 digest and digest scheme",[390,408,409],{},"A redaction class",[390,411,412],{},"A tombstone\u002Fversion fence",[370,414,415],{},"Known event types include run committed, span committed, assembly metrics, score candidates, directive snapshot, tool audit, and session event. The outbox is intentionally narrow: it is not a general model-policy invalidation bus or an organization-deletion cascade mechanism.",[370,417,418,419,422,423,426],{},"Payload and metadata are written in one PostgreSQL transaction with the durable effect. A payload cannot assign its own ",[382,420,421],{},"redaction_class"," or ",[382,424,425],{},"tombstone_fence","; the producer owns those fields. Invalid JSON, a mismatched digest, a caller-supplied fence, or a prohibited class is rejected at write time.",[374,428,430],{"id":429},"delivery-protocol","Delivery protocol",[432,433,438],"pre",{"className":434,"code":435,"language":436,"meta":437,"style":437},"language-mermaid shiki shiki-themes material-theme-lighter vitesse-light vitesse-dark","flowchart LR\n  Pending[\"pending\"] --> Claim[\"claim → in_flight\"]\n  Claim --> Validate[\"validate identity, class, digest, fence\"]\n  Validate --> Fence[\"authoritative session fence\"]\n  Fence -->|alive| Sink[\"fenced sink write\"]\n  Sink --> Delivered[\"delivered\"]\n  Validate -->|invalid\u002Fpermanent| Poison[\"poison\"]\n  Fence -->|tombstoned\u002Fstale\u002Fnot_found| Poison\n  Sink -->|transient| Failed[\"failed + backoff\"]\n  Failed --> Pending\n  Claim -->|crash| Stale[\"stale in_flight\"]\n  Stale -->|recover after window| Pending\n","mermaid","",[382,439,440,448,454,460,466,472,478,484,490,496,502,508],{"__ignoreMap":437},[441,442,445],"span",{"class":443,"line":444},"line",1,[441,446,447],{},"flowchart LR\n",[441,449,451],{"class":443,"line":450},2,[441,452,453],{},"  Pending[\"pending\"] --> Claim[\"claim → in_flight\"]\n",[441,455,457],{"class":443,"line":456},3,[441,458,459],{},"  Claim --> Validate[\"validate identity, class, digest, fence\"]\n",[441,461,463],{"class":443,"line":462},4,[441,464,465],{},"  Validate --> Fence[\"authoritative session fence\"]\n",[441,467,469],{"class":443,"line":468},5,[441,470,471],{},"  Fence -->|alive| Sink[\"fenced sink write\"]\n",[441,473,475],{"class":443,"line":474},6,[441,476,477],{},"  Sink --> Delivered[\"delivered\"]\n",[441,479,481],{"class":443,"line":480},7,[441,482,483],{},"  Validate -->|invalid\u002Fpermanent| Poison[\"poison\"]\n",[441,485,487],{"class":443,"line":486},8,[441,488,489],{},"  Fence -->|tombstoned\u002Fstale\u002Fnot_found| Poison\n",[441,491,493],{"class":443,"line":492},9,[441,494,495],{},"  Sink -->|transient| Failed[\"failed + backoff\"]\n",[441,497,499],{"class":443,"line":498},10,[441,500,501],{},"  Failed --> Pending\n",[441,503,505],{"class":443,"line":504},11,[441,506,507],{},"  Claim -->|crash| Stale[\"stale in_flight\"]\n",[441,509,511],{"class":443,"line":510},12,[441,512,513],{},"  Stale -->|recover after window| Pending\n",[515,516,518],"h3",{"id":517},"states","States",[520,521,522,535],"table",{},[523,524,525],"thead",{},[526,527,528,532],"tr",{},[529,530,531],"th",{},"State",[529,533,534],{},"Meaning",[536,537,538,553,563,573,583],"tbody",{},[526,539,540,546],{},[541,542,543],"td",{},[382,544,545],{},"pending",[541,547,548,549,552],{},"Eligible for claim when ",[382,550,551],{},"available_at"," allows",[526,554,555,560],{},[541,556,557],{},[382,558,559],{},"in_flight",[541,561,562],{},"Claimed by one relay cycle; not yet finalized",[526,564,565,570],{},[541,566,567],{},[382,568,569],{},"delivered",[541,571,572],{},"Sink accepted the row",[526,574,575,580],{},[541,576,577],{},[382,578,579],{},"failed",[541,581,582],{},"Transient failure; retry after backoff",[526,584,585,590],{},[541,586,587],{},[382,588,589],{},"poison",[541,591,592],{},"Terminal: permanent validation\u002Ffence failure or attempt limit reached",[370,594,595,596,598,599,601],{},"A stale ",[382,597,559],{}," row is returned to ",[382,600,545],{}," only after the recovery window. A crash after claim but before acknowledgement therefore causes redelivery, not loss. The sink must make redelivery idempotent using stable event identity.",[515,603,605],{"id":604},"validation-order","Validation order",[370,607,608,609,612,613,616,617,396,620,623],{},"Before any sink call, the relay validates row identity, redaction class, tombstone fence, payload presence, digest format, and digest match. Only the ",[382,610,611],{},"metadata"," redaction class is currently projectable. ",[382,614,615],{},"redacted"," is not projectable in this slice; ",[382,618,619],{},"unclassified",[382,621,622],{},"prohibited",", and unsupported classes fail closed.",[370,625,626,627,630],{},"A fence must name a resource type, resource ID, and positive version. A non-",[382,628,629],{},"session"," fence or malformed fence is permanent; an ordinary database error while checking the fence is retryable.",[515,632,634],{"id":633},"fence-semantics","Fence semantics",[520,636,637,647],{},[523,638,639],{},[526,640,641,644],{},[529,642,643],{},"Result",[529,645,646],{},"Action",[536,648,649,659,669,679,689],{},[526,650,651,656],{},[541,652,653],{},[382,654,655],{},"alive",[541,657,658],{},"Deliver through the fence-aware sink",[526,660,661,666],{},[541,662,663],{},[382,664,665],{},"tombstoned",[541,667,668],{},"Poison; never resurrect deleted data",[526,670,671,676],{},[541,672,673],{},[382,674,675],{},"stale_version",[541,677,678],{},"Poison; the row references an obsolete resource version",[526,680,681,686],{},[541,682,683],{},[382,684,685],{},"not_found",[541,687,688],{},"Poison",[526,690,691,694],{},[541,692,693],{},"Database error",[541,695,696],{},"Leave retryable",[370,698,699],{},"The replay check and the sink write are not one database transaction. This is the central recovery gap: the design narrows the race with an authoritative fence and idempotent sinks, but does not prove an atomic fence-and-project boundary.",[374,701,703],{"id":702},"retry-and-dead-letter-behavior","Retry and dead-letter behavior",[370,705,706,707,710],{},"Transient failures use exponential backoff with cryptographic jitter, capped at 60 seconds. Permanent delivery failures poison immediately. A row also poisons when its post-claim attempt count reaches ",[382,708,709],{},"IBEX_RELAY_MAX_ATTEMPTS",".",[370,712,713],{},"Permanent classes include unclassified\u002Fredacted\u002Fprohibited redaction, missing or invalid fence, fenced delivery being unavailable, unsupported fence resource, and a tombstoned resource. A poison row is retained for inspection; it is not silently dropped.",[374,715,717],{"id":716},"process-and-identity","Process and identity",[520,719,720,730],{},[523,721,722],{},[526,723,724,727],{},[529,725,726],{},"Behavior",[529,728,729],{},"Detail",[536,731,732,740,751,759,767],{},[526,733,734,737],{},[541,735,736],{},"Disabled",[541,738,739],{},"Validates configuration, logs a reason, exits 0 without connecting",[526,741,742,748],{},[541,743,744,745],{},"Missing ",[382,746,747],{},"IBEX_ENV",[541,749,750],{},"Fails closed, exit 1",[526,752,753,756],{},[541,754,755],{},"Enabled without both DSNs",[541,757,758],{},"Fatal startup error",[526,760,761,764],{},[541,762,763],{},"Shutdown",[541,765,766],{},"Stops the loop, waits for the in-flight batch, closes HTTP and dependencies",[526,768,769,772],{},[541,770,771],{},"Abandoned claims",[541,773,774],{},"Recovered by stale recovery, not released at shutdown",[370,776,777,778,781,782,785,786,788,789,792,793,796,797,800,801,396,804,807,808,811],{},"The daemon connects as a login role but pins ",[382,779,780],{},"ibex_evidence_relay"," per connection and asserts ",[382,783,784],{},"current_user"," at startup. ",[382,787,780],{}," is ",[382,790,791],{},"NOLOGIN",", is not granted to ",[382,794,795],{},"ibex_app",", and receives only the helper privileges required by migration ",[382,798,799],{},"000047",". The HTTP surface is ",[382,802,803],{},"\u002Fhealth",[382,805,806],{},"\u002Fready",", and ",[382,809,810],{},"\u002Fmetrics","; there is no relay operator API.",[374,813,132],{"id":814},"configuration",[520,816,817,830],{},[523,818,819],{},[526,820,821,824,827],{},[529,822,823],{},"Variable",[529,825,826],{},"Default",[529,828,829],{},"Bounds",[536,831,832,847,860,871,892,912,930,950,968,990],{},[526,833,834,839,844],{},[541,835,836],{},[382,837,838],{},"IBEX_RELAY_ENABLED",[541,840,841],{},[382,842,843],{},"false",[541,845,846],{},"Boolean",[526,848,849,854,857],{},[541,850,851],{},[382,852,853],{},"IBEX_RELAY_POSTGRES_DSN",[541,855,856],{},"—",[541,858,859],{},"Required when enabled; secret",[526,861,862,867,869],{},[541,863,864],{},[382,865,866],{},"IBEX_RELAY_CLICKHOUSE_DSN",[541,868,856],{},[541,870,859],{},[526,872,873,878,883],{},[541,874,875],{},[382,876,877],{},"IBEX_RELAY_POLL_INTERVAL",[541,879,880],{},[382,881,882],{},"2s",[541,884,885,888,889],{},[382,886,887],{},"500ms","–",[382,890,891],{},"5m",[526,893,894,899,904],{},[541,895,896],{},[382,897,898],{},"IBEX_RELAY_BATCH_SIZE",[541,900,901],{},[382,902,903],{},"32",[541,905,906,888,909],{},[382,907,908],{},"1",[382,910,911],{},"256",[526,913,914,918,923],{},[541,915,916],{},[382,917,709],{},[541,919,920],{},[382,921,922],{},"8",[541,924,925,888,927],{},[382,926,908],{},[382,928,929],{},"100",[526,931,932,937,942],{},[541,933,934],{},[382,935,936],{},"IBEX_RELAY_RECOVER_AFTER",[541,938,939],{},[382,940,941],{},"60s",[541,943,944,888,947],{},[382,945,946],{},"1s",[382,948,949],{},"1h",[526,951,952,957,962],{},[541,953,954],{},[382,955,956],{},"IBEX_RELAY_OPERATION_TIMEOUT",[541,958,959],{},[382,960,961],{},"30s",[541,963,964,888,966],{},[382,965,946],{},[382,967,891],{},[526,969,970,975,980],{},[541,971,972],{},[382,973,974],{},"IBEX_RELAY_ERROR_BACKOFF",[541,976,977],{},[382,978,979],{},"5s",[541,981,982,888,984,987,988],{},[382,983,887],{},[382,985,986],{},"1m","; doubles, cap ",[382,989,986],{},[526,991,992,997,1001],{},[541,993,994],{},[382,995,996],{},"IBEX_SHUTDOWN_TIMEOUT",[541,998,999],{},[382,1000,961],{},[541,1002,1003],{},"Shared graceful-shutdown budget",[370,1005,1006],{},"A missing or unreachable dependency when enabled is a fatal startup error. Secrets are never logged, and error messages do not echo DSNs.",[374,1008,273],{"id":1009},"observability",[370,1011,1012,1015,1016,1019,1020,710],{},[382,1013,1014],{},"ibex_relay_batches_total{result}",", claimed, delivered, retried, dead-letter, and recovered counters; batch, delivery, and fence-check duration histograms; and ",[382,1017,1018],{},"ibex_process_up",". Labels are bounded, and unknown values collapse to ",[382,1021,1022],{},"error",[370,1024,1025,1026,1028],{},"Alert on a rising dead-letter count, stale claims that never recover, repeated database errors, and a relay that is enabled but has no successful batches. A high ",[382,1027,569],{}," count does not by itself prove end-to-end durability before chat acknowledgement.",[374,1030,1032],{"id":1031},"known-limitations","Known limitations",[387,1034,1035,1038,1041,1044,1047,1050],{},[390,1036,1037],{},"ClickHouse remains a non-production projection pilot; there is no production sink.",[390,1039,1040],{},"No hosted or HA recovery evidence exists.",[390,1042,1043],{},"No relay-level tenant\u002Fagent allowlist, request-auth layer, or operator endpoint.",[390,1045,1046],{},"The fence read, outbox write, and projection are not one atomic transaction.",[390,1048,1049],{},"Chat acknowledgement is not response-bound, so durable-before-ack is not proven end to end.",[390,1051,1052],{},"GAP-005 and GAP-011 remain open.",[374,1054,1056],{"id":1055},"verify","Verify",[432,1058,1062],{"className":1059,"code":1060,"language":1061,"meta":437,"style":437},"language-bash shiki shiki-themes material-theme-lighter vitesse-light vitesse-dark","go test .\u002Fpackages\u002Fevidenceoutbox\u002F...\ngo test .\u002Fservices\u002Frelay\u002F...\n\nPOSTGRES_TEST_DSN=postgres:\u002F\u002Fibex:ibex@127.0.0.1:5433\u002Fibex_test?sslmode=disable \\\n  go test -tags=integration -p 1 .\u002Fservices\u002Frelay\u002F...\n","bash",[382,1063,1064,1077,1086,1092,1116],{"__ignoreMap":437},[441,1065,1066,1070,1074],{"class":443,"line":444},[441,1067,1069],{"class":1068},"sYn-s","go",[441,1071,1073],{"class":1072},"sTbE_"," test",[441,1075,1076],{"class":1072}," .\u002Fpackages\u002Fevidenceoutbox\u002F...\n",[441,1078,1079,1081,1083],{"class":443,"line":450},[441,1080,1069],{"class":1068},[441,1082,1073],{"class":1072},[441,1084,1085],{"class":1072}," .\u002Fservices\u002Frelay\u002F...\n",[441,1087,1088],{"class":443,"line":456},[441,1089,1091],{"emptyLinePlaceholder":1090},true,"\n",[441,1093,1094,1098,1102,1105,1108,1110,1113],{"class":443,"line":462},[441,1095,1097],{"class":1096},"sSC40","POSTGRES_TEST_DSN",[441,1099,1101],{"class":1100},"soVBu","=",[441,1103,1104],{"class":1072},"postgres:\u002F\u002Fibex:ibex@127.0.0.1:5433\u002Fibex_test?",[441,1106,1107],{"class":1096},"sslmode",[441,1109,1101],{"class":1100},[441,1111,1112],{"class":1072},"disable",[441,1114,1115],{"class":1068}," \\\n",[441,1117,1118,1121,1123,1127,1130,1134],{"class":443,"line":468},[441,1119,1120],{"class":1072},"  go",[441,1122,1073],{"class":1072},[441,1124,1126],{"class":1125},"sz9Cv"," -tags=integration",[441,1128,1129],{"class":1125}," -p",[441,1131,1133],{"class":1132},"s7CZa"," 1",[441,1135,1085],{"class":1072},[370,1137,1138,1139,1142],{},"Use ",[382,1140,1141],{},"-p 1"," for integration tests so migration locks do not collide. Local tests cover claim, poison, tombstone fence, stale recovery, role denial, and redaction rejection; they do not constitute a production recovery drill.",[374,1144,1146],{"id":1145},"related","Related",[387,1148,1149,1155,1160,1165,1170],{},[390,1150,1151,1154],{},[1152,1153,309],"a",{"href":310}," — tombstone semantics",[390,1156,1157,1159],{},[1152,1158,277],{"href":278}," — analytics versus canonical traces",[390,1161,1162,1164],{},[1152,1163,305],{"href":306}," — restore classes",[390,1166,1167,1169],{},[1152,1168,293],{"href":294}," — separate ledger authority",[390,1171,1172,1174],{},[1152,1173,255],{"href":256}," — org predicates and RLS boundaries",[1176,1177,1178],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sYn-s, html code.shiki .sYn-s{--shiki-light:#E2931D;--shiki-default:#59873A;--shiki-dark:#80A665}html pre.shiki code .sTbE_, html code.shiki .sTbE_{--shiki-light:#91B859;--shiki-default:#B56959;--shiki-dark:#C98A7D}html pre.shiki code .sSC40, html code.shiki .sSC40{--shiki-light:#90A4AE;--shiki-default:#B07D48;--shiki-dark:#BD976A}html pre.shiki code .soVBu, html code.shiki .soVBu{--shiki-light:#39ADB5;--shiki-default:#999999;--shiki-dark:#666666}html pre.shiki code .sz9Cv, html code.shiki .sz9Cv{--shiki-light:#91B859;--shiki-default:#A65E2B;--shiki-dark:#C99076}html pre.shiki code .s7CZa, html code.shiki .s7CZa{--shiki-light:#F76D47;--shiki-default:#2F798A;--shiki-dark:#4C9A91}",{"title":437,"searchDepth":450,"depth":450,"links":1180},[1181,1182,1187,1188,1189,1190,1191,1192,1193],{"id":376,"depth":450,"text":377},{"id":429,"depth":450,"text":430,"children":1183},[1184,1185,1186],{"id":517,"depth":456,"text":518},{"id":604,"depth":456,"text":605},{"id":633,"depth":456,"text":634},{"id":702,"depth":450,"text":703},{"id":716,"depth":450,"text":717},{"id":814,"depth":450,"text":132},{"id":1009,"depth":450,"text":273},{"id":1031,"depth":450,"text":1032},{"id":1055,"depth":450,"text":1056},{"id":1145,"depth":450,"text":1146},"The PostgreSQL outbox, claim and fence protocol, delivery classes, and the recovery limits of the relay daemon.","md",false,{},"provisional",{"title":297,"description":1194},"services\u002Frelay\u002FREADME.md; packages\u002Fevidenceoutbox; ADR-0085","CPUgEucdKDqzOcKm9j_QtQOYbfszLmMmMxQYq2R-F20",[1203,1205],{"title":293,"path":294,"stem":295,"description":1204,"children":-1},"Rate cards, usage facts, hard-cap admission holds, reconciliation, and the limits of each authority.",{"title":301,"path":302,"stem":303,"description":1206,"children":-1},"The canonical operator application, its live data allowlist, and the surfaces that are still preview-only.",1792875070769]