Decisions index
DECISIONS.md in the repository is append-only: a record that a later record supersedes,
corrects or extends keeps its original text. This page, generated from the log at every
docs build, lists each record with the later records that cite it and the relation their
wording names, so a reader can tell what still stands before relying on it. A citation
is a pointer to read, not a verdict; a record cited by nothing later is, as far as the
log knows, current.
| Record | Decision | Cited by later records |
|---|---|---|
| D1 | One Kafka Streams application per declared process | — |
| D2 | A channel is identified by (topic ID, partition) | D21, D26, D33 |
| D3 | Causal metadata wire format: one reserved header, strict canonical binary | D94, D98 (supersedes) |
| D4 | Dependencies are summarized as one maximum position per channel | D52 (corrects), D115 |
| D5 | Deliverability: settled frontier from fed-or-never plus the hold-back buffer | D6, D78, D102, D104, D115 |
| D6 | The host's read-position report is the feed itself plus committed group offsets | D26, D35 (corrects), D115 (supersedes) |
| D7 | An internal wall-clock punctuator ingests facts | D20, D44, D115 (supersedes) |
| D8 | Failing closed stops the whole process, by exception | D94 |
| D9 | auto.offset.reset=none, with initial positions pre-committed while the group is empty |
D25, D26, D74, D76, D104, D109, D115 (narrows) |
| D10 | Re-feeds below the session floor are dropped; contradictions within an execution fail closed | D25, D26, D36, D45, D78 (narrows), D91, D115 |
| D11 | Parsley owns the KafkaStreams lifecycle; nothing weaker is constructible | D111 |
| D12 | The seam: Effects handle(Delivery, StateReader); reads live, writes returned |
D26, D60 |
| D13 | An application payload its own serde cannot decode fails the step | D62 (implements), D81 |
| D14 | Application stores are byte stores; serdes apply at the seam; changelog-name serde scoping | — |
| D15 | Emissions inherit the delivered message's timestamp and default partitioning | D111 |
| D16 | Deterministic drain: channels in total order, to fixpoint | — |
| D17 | Ordering state: one reserved store; held bodies persisted only if still held at step end | D57, D102, D106, D110 |
| D18 | Reserved prefixes: parsley. for headers, __parsley. for stores |
D56 |
| D19 | Toolchain: Kafka clients/Streams 3.9.1, Java 21, Maven, JUnit 5 | D57, D69 (supersedes), D70 (supersedes) |
| D20 | The facts interval is configurable, one second by default | D115 (supersedes) |
| D21 | A deleted topic settles its remaining positions; dead incarnations are vacuous | D26, D46 (corrects), D93, D105, D115 |
| D22 | Log starts are attributed to a topic ID only under a describe-after-query identity check | D26, D50, D79, D107, D115 (supersedes) |
| D23 | Self-dependency is impossible by construction; adversarial self-deps hold forever | D26, D105 |
| D24 | A step is the host's transaction; several deliveries may share one step | — |
| D25 | Structural 16 mechanics: refusal by held-scan; leave/rejoin by retained state | D74, D106 |
| D26 | Assumptions taken, and what breaks if one proves false | D46, D78, D104 (corrects), D115 (corrects) |
| D27 | Naming: candidate.parsley:parsley, packages candidate.parsley.* |
D64 (corrects) |
| D28 | Emissions always carry the causes header, even when empty | — |
| D29 | Null keys and values bypass serdes; tombstones pass through | — |
| D30 | Diagnostics: the decision unit reports its blockers | D103 |
| D31 | A joining channel starts above the delivered causal past | D41, D42, D74, D102, D105, D106 |
| D32 | A channel is declared dead only after consecutive confirming rounds | D40 (corrects), D44 (supersedes), D115 (supersedes) |
| D33 | Topic names are bound to channel identity in ordering state; recreation refuses | D36, D44, D47, D76 (reverses), D115 |
| D34 | No deliveries from within processor initialisation | — |
| D35 | A read_committed probe settles trailing never-yielding runs; corrects D6 | D78, D107 (corrects), D115 (supersedes) |
| D36 | When prior state exists, missing group offsets restart from earliest | D48, D74 (corrects), D111, D115 (narrows) |
| D37 | Exception handlers are unoverridable configuration | D51 (extends), D80 (extends) |
| D38 | The runtime refuses stranded held messages by reading the changelog | D57 |
| D39 | Received topics may have unequal partition counts | — |
| D40 | Correction to D32's blast-radius claim | D44 (corrects), D75, D115 (supersedes) |
| D41 | The simulation oracle observes the feed; owed delivery is excused only by ground-truth delivered past | — |
| D42 | The oracle bounds expression from above, judged at send time | — |
| D43 | The generator reaches refusals; the harness survives them; catch margins are asserted per mode | D112, D115 |
| D44 | Channel death needs corroboration; recreation is affirmative; the debounce is time-based | D50, D75 (corrects), D78, D82, D84, D85 (extends), D89, D112, D115 (supersedes) |
| D45 | An in-execution feed regression fails closed, wherever it lies relative to the session floor | D77, D115 |
| D46 | A dead channel with undelivered held messages fails the process closed; corrects D21 | D104, D115 |
| D47 | The bootstrap scan diagnoses identity change before judging removal | — |
| D48 | Initial positions are committed through group membership, never by admin alteration | D50, D79, D80, D86, D108 (closes) |
| D49 | A task-width change against prior state is refused at start; names the Streams width validation | D59 |
| D50 | Test seams for the bootstrap and facts source: real broker, phase hooks, injected clock, overridable describe | — |
| D51 | Client interceptors and the timestamp extractor join the unoverridable set; extends D37 | D80 (extends) |
| D52 | A metadata budget in bytes, enforced on receipt and on emission; corrects D4's attribution | D75, D93, D98 (supersedes), D115 |
| D53 | Frontier size is logged every facts round and surfaced at 80% of budget | D90, D103, D115 |
| D54 | Position facts are gathered on one background thread; applied on the stream thread | D74, D107, D115 (supersedes) |
| D55 | Per-process status: state plus refusal reason, readable programmatically | D59, D72, D73, D77, D92, D103 (resolves), D109, D111 |
| D56 | The seam's header view is application headers only; the reserved refusal names its reason | D73, D87 |
| D57 | The ordering store's changelog requests logging and compaction explicitly | D110 |
| D58 | Declared topic names must stay clear of the runtime's namespace | — |
| D59 | Partition expansion is handled by restart; mid-run it gets a parsley diagnosis | D109 |
| D60 | StateReader keeps point lookups only; enumeration stays out of v1 | — |
| D61 | Naming: the wrong-edit hazard is fixed; mechanical enforcement is deferred, recorded as a deviation | — |
| D62 | Emissions are matched to the declared send set by topic name; the emission's Channel supplies the serdes | D73 (supersedes) |
| D63 | close() releases every resource, each step isolated and bounded | D109 |
| D64 | Real coordinates: io.github.tobyjamesclements:parsley, packages io.github.tobyjamesclements.parsley.* (corrects D27) |
D99 |
| D65 | The mutation gate's skip flag is bound to a declared property | D67 (supersedes) |
| D66 | The mutation gate covers the core and the API, not the Kafka adapter | D67 (supersedes) |
| D67 | No mutation gate; the three gaps it found are recorded here instead (supersedes D65, D66) | D106, D112 |
| D68 | kafka-metadata:test dropped; the rest of the broker test stack is load-bearing |
— |
| D69 | Kafka 3.9.2 (supersedes D19's version pin) | D70 (supersedes) |
| D70 | Kafka 4.3.1 (supersedes D69 and D19's pin) | D71 (amends) |
| D71 | Avro dropped from the test dependencies (amends D70) | — |
| D72 | Names applied at vendoring (implements ASSESSMENT §5.2's decide-now) | D77 |
| D73 | The api/ surface validates at declaration; the send seam resolves the declared channel by name (supersedes D62's serde-supply and duplicate-sends choices; resolves ASSESSMENT §1.14 and §1.15's send-set bullet) | D81 (extends) |
| D74 | Re-established read positions are checked against durable coverage; corrects D36's "never lossy" | D104, D105, D112, D115 (narrows) |
| D75 | A nameless topic id is never confirmed dead; corrects D44's four-fold window | D84, D85 (extends), D89, D115 (supersedes) |
| D76 | Lost ordering state under surviving Streams offsets refuses at start | D79, D82, D84 (extends), D102, D114 |
| D77 | A report/feed contradiction has its own reason; OUT_OF_ORDER_FEED is feed order alone | D78, D91, D93, D103, D106, D115 (narrows) |
| D78 | Compacted received topics are an Assumption 10 reliance; the probe residual is recorded | D115 (supersedes) |
| D79 | Read-path hardenings: stable bootstrap reads, true-end changelog scan, offsets inside the confirmed window | D86 (extends), D92 |
| D80 | The membership protocol joins the unoverridable set; extends D37/D51, and the promised revisit | — |
| D81 | Seam and runtime diagnoses name their conditions; extends D73's taxonomy | D92, D94, D95, D98, D115 |
| D82 | Hand-built consumers are pinned against mutating the cluster | D88 (corrects), D92 |
| D83 | The reserved zero topic ID is undecodable metadata; the facts round tolerates unanswerable ids | D88, D92, D95, D105 (extends), D113 |
| D84 | Prior state is keyed on ordering records, and prior-state describes are corroborated; extends D76 | D88 (corrects), D96, D102, D113 (extends), D115 |
| D85 | Verdict windows require observed continuity; recreation is debounced; contradicted verdicts are rescinded (extends D44/D75) | D88 (corrects), D115 (corrects) |
| D86 | A partially-covering stable listing is retried before the group join; extends D79 | D92, D96, D97 |
| D87 | Seam and configuration minors from the kafka-layer audit, in one sweep | D88 (corrects), D95, D115 |
| D88 | The audit fixes, reviewed adversarially; corrections to D82, D84, D85 and D87 | D96, D105, D107 (implements), D115 (narrows) |
| D89 | The eviction horizon is pinned by scripted-round evidence; name learning extracted as a seam | D95, D97 (corrects), D115 |
| D90 | The 80%-of-budget warning is pinned through a latch seam plus one stderr-capture wiring test | D97 |
| D91 | Mid-run supersession is pinned structurally over ProcessEngine, not through the sim harness | D112, D114, D115 |
| D92 | ParsleyRuntime's diagnosis, changelog-read and identity-floor behaviours get unit seams; pins issue #95's gaps E–G | D95, D96 (extends), D97 (corrects), D112 |
| D93 | The engine's error sites are pinned at reason-and-message level; the per-message budget gate is discriminated by raw length | D98 |
| D94 | Codec refusal diagnoses are pinned message-level; the position floor is pinned at the value objects | D100 |
| D95 | The processor's refusal sites, the bootstrap join wait and the facts round's abort paths get direct pins | D97 (corrects) |
| D96 | Start-path refusal decisions are pinned through scripted functional seams; extends D92 into the determination and recheck loops | D97 (corrects) |
| D97 | Review corrections to the D89–D96 pins: two trials that did not discriminate, seam waits parameterized, wiring gaps closed, two claims narrowed (corrects D89, D92, D95, D96) | — |
| D98 | Causes wire format: entries grouped by topic id, varint structural fields, fixed-width positions (supersedes D3's value grammar and D52's affine-size check) | D99 (retires), D101 (supersedes), D102, D106 |
| D99 | Issue #96's session companion lands as its own package, session, over the public surface |
D100 (extends) |
| D100 | Review hardenings to the session companion: compile-checked coverage exhaustiveness, identity merges, and shared fences (extends D99) | — |
| D101 | The grouped grammar releases as version byte 0x01 (supersedes D98's renumbering rejection) |
— |
| D102 | Hold-back memory is bounded by the heads, a flush costs the holds it writes, and the emission header is encoded once per frontier change | D105, D106, D110, D114, D115 |
| D103 | Each task publishes its delivery state, and status() carries it (fulfils D53's promise) |
D107, D111, D114, D115 |
| D104 | Retention crossing a held message fails the holder closed; the log-start check runs against the settled position (corrects D26's Assumption 10 line; the retention dual of D46) | D112, D115 (corrects) |
| D105 | The reserved maximum position is undecodable metadata and untrusted state (wire-format constraint 7; extends D83) | — |
| D106 | Review pins over the core: D67's gaps closed, the emission header pinned byte for byte, the simulator's timestamps decorrelated from positions | D112 |
| D107 | A facts round's tail is watched time; the probe is batched over the channels held heads wait on; the seed round does not probe (implements D88's spelling, whose pin did not cover the round tail; corrects D35's cost claim) | D115 (corrects) |
| D108 | A concurrent cold start waits for other instances' bootstrap members and replaces a refused stream thread (closes D48's residual S1) | — |
| D109 | Substrate-detected stops that recur identically carry their reason; start() says what it returns into; close() is bounded on every leg |
D111, D115 |
| D110 | The ordering store is cached, and the bootstrap view keeps a held message's presence rather than its body | — |
| D111 | The runtime can be waited on, an emission may carry its own timestamp, and the seam's documentation says what the code does | D114 (narrows), D115 |
| D112 | Five pins a mutation trial showed the suite lacked, and the sabotage mode D91 recorded as missing | — |
| D113 | Declared-topic resolution corroborates an unknown-topic answer before refusing (extends D84) | D115 |
| D114 | Runbooks: what an operator does when a process fails closed, reason by reason; the gaps the runbooks expose are recorded, not closed | — |
| D115 | The facts round is removed: a cause names a committed record, receipt is the only liveness input, retention is the fetch's to refuse, identity is checked once per task initialisation (wire-format constraint 8; supersedes D6, D7, D20, D22, D32, D35, D40, D44, D54, D75, D78, D85, D89, D91, D104, D107; narrows D9, D36, D74, D77, D88; corrects D26's Assumption 15 line; amends SPEC Liveness 3, Structural 13 and 15, Host obligation 2, Assumptions 13, 15 and 17) | — |
At a glance
115 records. Named as superseded or reversed by a later record: D3, D6, D7, D19, D20, D22, D32, D33, D35, D40, D44, D52, D54, D62, D65, D66, D69, D75, D78, D98. Named as corrected, refuted or amended in part: D4, D21, D26, D27, D36, D70, D82, D84, D85, D87, D89, D92, D95, D96, D104, D107. Every other citation is an extension or a reference; read the citing record to see which.