Repository navigation
Description
Problem
The repo still lacks one authoritative place that defines what the I/O boundary and control-plane guarantees actually are. Without that, a "correct by construction" architecture has no shared contract to be correct against.
This issue is the contract layer for the architecture umbrella. It is not only about receiver -> pipeline -> sink semantics; it also now owns the diagnostics/control-plane contract that operators and internal tooling will rely on.
Desired end-state
dev-docs/IO_CONTRACTS.md becomes the living contract for:
- receiver -> pipeline guarantees
- pipeline -> sink guarantees
- checkpoint advancement rules
- error and retry classification vocabulary
- duplicate/loss windows for file-tailing and restart behavior
- the probe/control-plane contract:
GET /liveGET /readyGET /admin/v1/status
- shared health vocabulary and meanings:
startinghealthydegradedstoppingstoppedfailed
- readiness impact vocabulary and roll-up rules
- quiet-source rule: lack of fresh traffic must not by itself fail readiness
- drain/shutdown semantics for readiness and serving state
- what is currently enforced by proofs/tests/runtime checks vs what is still intent
Scope
- Write and maintain
dev-docs/IO_CONTRACTS.mdas the current-truth contract document - Define probe semantics for
/live,/ready, and/admin/v1/status - Define status payload semantics including state, reason, timestamps, and readiness impact
- Define roll-up rules from component -> pipeline -> process
- Define degraded policy defaults including the default fail-open readiness stance for degraded states
- Define enforcement status for each guarantee: proof, proptest, integration test, runtime check, or TODO
- Cross-link existing docs such as
SCANNER_CONTRACT.mdinstead of duplicating inner-layer details - Document duplicate/loss windows honestly — no stronger claims than implementation and tests justify
- Keep it living — future I/O and control-plane changes must update this doc as part of landing semantic changes
Design stance
This document should describe the final contract we want, not a backward-compatibility story. We do not currently have external consumers that force us to preserve a weaker shape.
The initial revision should still be honest about current implementation truth where the repo has not caught up yet, but the contract should clearly define the target semantics we are building toward.
Relationships
Relates to:
- meta: I/O control-plane substrate — lifecycle, health, readiness, and status #1306 lifecycle/health/readiness/status substrate
- File tailer refactor — split monolith, typestate, per-file correctness #1310 tailer refactor
- OTLP receiver refactor — axum, streaming decompression, unified receivers #1311 receiver refactor
- Output delivery contract — retry, reject, checkpoint, fanout #1312 exporter semantics
- File appender output — new component with rotation, cleanup, path templates #1313 file appender
- I/O verification suite — TLA+, Turmoil, loopback, otelcol oracle, benchmarks #1314 verification suite
- I/O correctness refactor — correct by construction, not by patch #1315 architecture umbrella
- research: I/O component refactor — library evaluation and benchmarking #1283 research
Activity
github-actions commentedon Apr 6, 2026
tl;dr: This is
needs-decisionbecause the issue’s checkpoint rule (never on reject) conflicts with current implemented + verified behavior (reject advances checkpoint), so we need one explicit policy decision before draftingdev-docs/IO_CONTRACTS.mdas a normative contract.Recommendation
Pick Option 1 below (keep current reject semantics, document it explicitly), then implement
IO_CONTRACTS.mdmechanically.Findings
Code evidence (paths + lines)
Receiver→Pipeline backpressure is already explicit and enforced
crates/logfwd-io/src/otlp_receiver.rs:25(CHANNEL_BOUND: 4096)crates/logfwd-io/src/otlp_receiver.rs:59(mpsc::sync_channel(capacity))crates/logfwd-io/src/otlp_receiver.rs:230-236full channel => HTTP429crates/logfwd-io/src/otlp_receiver.rs:1043testreturns_429_when_channel_full_not_200Receiver field names are currently hardcoded (not semantic-fields-driven yet)
crates/logfwd-io/src/otlp_receiver.rs:363,371,379,403,409,496,504,511,532,539(
timestamp_int,level,message,trace_id,span_id)Pipeline→Sink contract today is
RecordBatch + BatchMetadata; checkpoint state is separate ticket statecrates/logfwd-output/src/sink.rs:74-80(Sink::send_batch(&RecordBatch, &BatchMetadata))crates/logfwd-output/src/lib.rs:75-80(BatchMetadata { resource_attrs, observed_time_ns })crates/logfwd/src/pipeline.rs:917-930metadata creation + submit to worker poolCheckpoint behavior conflict (core decision point)
crates/logfwd/src/pipeline.rs:977-982failed output path usesticket.reject()thenmachine.apply_ack(receipt)crates/logfwd-types/src/pipeline/lifecycle.rs:524-532unit testreject_advances_checkpointcrates/logfwd-types/src/pipeline/lifecycle.rs:1069-1089proof comment + verification for reject-advancestla/PipelineMachine.tla:153,173RejectBatch(s,b) == AckBatch(s,b)Delivery semantics are documented, but not in one boundary contract doc yet
book/src/architecture/pipeline.md:116at-least-once with queuedev-docs/SCANNER_CONTRACT.md:1-5scanner-only scope; does not cover full I/O boundariesRelated roadmap context is active
[codex] add OTLP and file IO contract oracles) likely overlaps this areaVerification
Commands run
Needs human decision
What’s unclear: Should checkpoint advancement occur on permanent sink rejection?
Option 1 (recommended): keep current behavior
rejectadvances checkpoint (drop undeliverable data, avoid infinite replay/drain stalls)Option 2: change behavior to “never advance on reject”
Option 3: configurable policy (
advance_on_reject = true|false)Recommendation: Option 1.
Label: please add
needs-decision.Detailed action plan (after decision)
Mechanical implementation steps
Create
dev-docs/IO_CONTRACTS.mdBoundary | Guarantee | Preconditions | Failure mode | Delivery semantics | Duplicate/loss window | Checkpoint rule | Enforcement mechanism | Evidence (path:line) | TODOCross-link scanner scope in
dev-docs/SCANNER_CONTRACT.md(top section)dev-docs/IO_CONTRACTS.mdfor boundary-level guaranteesPopulate initial enforcement column
Kani/proptest/TLA+/integration testwhere evidence existsTODO: not yet enforcedwhere it does notResolve semantic field naming row with Shared semantic field definitions (logfwd-types) #1302 state
Conflict check with open PR [codex] add OTLP and file IO contract oracles #1290 before merge
Tests/docs checks for triage handoff
cargo test -p logfwd-io --test itcargo test -p logfwd-types reject_advances_checkpointRelated items
crates/logfwd-io/src/otlp_receiver.rscrates/logfwd/src/pipeline.rscrates/logfwd-types/src/pipeline/lifecycle.rstla/PipelineMachine.tladev-docs/SCANNER_CONTRACT.mdbook/src/architecture/pipeline.mdNote
🔒 Integrity filtering filtered 6 items
Integrity filtering activated and filtered the following items during workflow execution.
This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.
issue_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)search_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)issue_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)issue_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)What is this? | From workflow: Issue Triage
Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.
[-]IO_CONTRACTS.md — living contract document for I/O boundaries[/-][+]IO_CONTRACTS.md — living contract for I/O and control-plane semantics[/+]strawgate commentedon Apr 6, 2026
Scheduling layer for this issue:
/admin/v1/statusThis keeps
#1303as the contract source of truth while letting execution happen in bounded, merge-safe slices.strawgate commentedon Apr 11, 2026
Closing as completed via the canonical contract document and follow-on work-units.
Verification evidence:
Note: issue text names , but implementation settled on as the canonical file.
strawgate commentedon Apr 11, 2026
Follow-up verification summary (clean copy):
The original issue filename text used IO_CONTRACTS.md; implementation standardized on ADAPTER_CONTRACT.md.