No reply field says the answering binary is older than the tree it indexed, and that is why #118 read as unfixed from inside the session that fixed it #181

Closed
opened 2026-09-06 09:52:21 +02:00 by buildagent · 3 comments
Member

Found by dogfooding during the 2026-09-06 triage session that closed 22 issues. It is not a hypothetical: it produced a concrete misread inside that session, on an issue the same session was verifying.

Sibling of the finding filed alongside it — the index discloses its root but never its commit. Same family: the answer does not disclose what produced it. That one is about the tree; this one is about the binary. Fix them together or the disclosure has a hole either way.

Measured

The MCP server answering this session is:

code-index 0.26.1 (4555887)

The working tree it indexes was at f6a878a, and moved to 45cf6e4 mid-session — roughly sixty commits past 4555887.

Probed live, on the real installed binary:

symbol answer
search_symbols("plugin_add", kind: "method") ref_count: 0, name_fallback_count: 0, no name_fallback_unmeasured
search_symbols("context_pack", …) (sibling #[tool] method) correctly carries name_fallback_unmeasured: "uses_may_be_generated"

That asymmetry is exactly the defect #118 describes, and #118 was fixed on master in 2f16e22:

  • fix: crates/daemon/src/local_index.rs:5893-5917 — "#118 — AN ANNOTATED ROW IS NOT ASKED", then if annotated.contains(&i) { continue; }, plus :5971
  • grading test: crates/mcp-server/tests/zero_basis_e2e.rs:405 an_annotated_declaration_is_not_measured_by_a_namesakes_call_sites — 1 passed, exit 0, with its RUN mutation recorded

So the tool said the bug was live while the tree said it was fixed, and nothing in the reply distinguished those two claims. The session only resolved it by noticing the binary's own version string, out of band. Had it not, the honest outcome would have been to leave #118 open on false evidence — the failure mode this repo has already paid for twice ("issue text goes stale").

Mechanism, and why the existing disclosure does not cover it

#83 shipped exactly the right thing for a different pair of endpoints:

  • pub enum DaemonBuild { NoDaemonLeg, Matched, Skewed{client,daemon,pid}, Unknown{why} } — crates/daemon/src/access.rs:36
  • read at call time — crates/daemon/src/rpc_index.rs:837-885
  • rendered into the payload — render_daemon_build, call site crates/mcp-server/src/server.rs:4470-4500

That compares client version ⇄ daemon version. Both were 0.26.1 here, so the verdict was Matched, and Matched emits nothing — correctly, for the question it asks.

The uncovered axis is binary ⇄ tree. A client and a daemon can agree perfectly with each other and both be sixty commits behind the source they are indexing. There is no field for it anywhere: no project_overview block, no index_coverage reason code, no per-row provenance.

Note the version string is structurally incapable of carrying this on its own: 0.26.1 covers ~60 commits, so --version matching the tree's Cargo.toml proves nothing. The build hash 4555887 is the fact that matters, and it is printed to a human and never to a caller.

Why existing gates cannot catch it

Every test builds its binary from the tree under test. The test binary and the indexed tree are the same commit by construction, so the skew is unrepresentable in the harness. No fixture can currently disagree with itself.

Compounding it, and found while verifying #83 in the same session: daemon_build appears in no test file at all. The skew disclosure that does exist is graded by a render_daemon_build unit test, never over the wire. So the one mechanism in this family is itself ungraded end to end.

Repro

  1. cargo install --path . (or unpack a release archive) at commit A.
  2. Advance the working tree to commit B, where some resolver or disclosure behaviour changed.
  3. Run the MCP server from the installed binary against that tree.
  4. Ask a question whose answer differs between A and B.

Today's instance, verbatim: search_symbols("plugin_add", kind: "method") against a tree containing 2f16e22.

The reply is A's answer, presented as current, with no field saying so.

What must NOT be done

  • Do not compare --version against the tree's Cargo.toml version. It does not move per commit; it would report Matched across the whole sixty-commit window that produced this bug.
  • Do not force a respawn, rebuild or refusal on mismatch. #83 already argued this correctly: an older binary is not automatically wrong, and forcing a rebuild mid-session is disruptive. Disclosure is the requirement; refusal is a separate policy argument.
  • Do not put it only in the daemon log. That is precisely the channel #83 moved away from (tracing::warn! reaches no agent).
  • Do not let absent read as "current". Three states, as everywhere else here: absent = this build did not report; equal = verified; different = the finding. An older daemon that cannot report must produce unavailable, not silence.
  • Do not grade it with a test that builds both sides from HEAD — that is the vacuity that hides it today. The test has to construct a genuine skew (e.g. stamp a different build hash into the index rows, or run a binary built from an earlier git archive).

Shape of the fix, stated as a requirement rather than a design

A reply whose content can differ between binaries must carry which binary produced it. The natural carrier already half-exists: the build hash is compiled in and printed by --version; the index rows were written by some binary. Comparing the binary that wrote the rows against the binary now serving them is the measurement, and it needs no git call at query time.

Cross-check against the sibling issue before implementing: a reader debugging a wrong answer needs both "which binary answered" and "which tree it had read", and they should be one block, not two unrelated fields.

Severity argument

This is the "two states rendering identically" failure at the outermost layer — the one the entire disclosure discipline in this repo exists to prevent. Every honest three-state field inside the product is undermined if the whole answer can silently come from a different build. And its first observed victim was a triage pass whose entire job was deciding what is true.

🤖 Filed by the triage lane, 2026-09-06, from a live misread. Installed binary 0.26.1 (4555887); tree f6a878a→45cf6e4.

Found by **dogfooding during the 2026-09-06 triage session that closed 22 issues**. It is not a hypothetical: it produced a concrete misread inside that session, on an issue the same session was verifying. Sibling of the finding filed alongside it — *the index discloses its root but never its commit*. Same family: **the answer does not disclose what produced it.** That one is about the *tree*; this one is about the *binary*. Fix them together or the disclosure has a hole either way. ## Measured The MCP server answering this session is: ``` code-index 0.26.1 (4555887) ``` The working tree it indexes was at `f6a878a`, and moved to `45cf6e4` mid-session — **roughly sixty commits past `4555887`**. Probed live, on the real installed binary: | symbol | answer | |---|---| | `search_symbols("plugin_add", kind: "method")` | `ref_count: 0`, `name_fallback_count: 0`, **no `name_fallback_unmeasured`** | | `search_symbols("context_pack", …)` (sibling `#[tool]` method) | correctly carries `name_fallback_unmeasured: "uses_may_be_generated"` | That asymmetry is **exactly the defect #118 describes**, and #118 was **fixed on master** in `2f16e22`: - fix: `crates/daemon/src/local_index.rs:5893-5917` — *"#118 — AN ANNOTATED ROW IS NOT ASKED"*, then `if annotated.contains(&i) { continue; }`, plus `:5971` - grading test: `crates/mcp-server/tests/zero_basis_e2e.rs:405` `an_annotated_declaration_is_not_measured_by_a_namesakes_call_sites` — **1 passed, exit 0**, with its RUN mutation recorded **So the tool said the bug was live while the tree said it was fixed, and nothing in the reply distinguished those two claims.** The session only resolved it by noticing the binary's own version string, out of band. Had it not, the honest outcome would have been to leave #118 open on false evidence — the failure mode this repo has already paid for twice ("issue text goes stale"). ## Mechanism, and why the existing disclosure does not cover it #83 shipped exactly the right thing for a *different* pair of endpoints: - `pub enum DaemonBuild { NoDaemonLeg, Matched, Skewed{client,daemon,pid}, Unknown{why} }` — `crates/daemon/src/access.rs:36` - read at call time — `crates/daemon/src/rpc_index.rs:837-885` - rendered into the payload — `render_daemon_build`, call site `crates/mcp-server/src/server.rs:4470-4500` That compares **client version ⇄ daemon version**. Both were `0.26.1` here, so the verdict was `Matched`, and `Matched` **emits nothing** — correctly, for the question it asks. The uncovered axis is **binary ⇄ tree**. A client and a daemon can agree perfectly with each other and both be sixty commits behind the source they are indexing. There is no field for it anywhere: no `project_overview` block, no `index_coverage` reason code, no per-row provenance. Note the version string is *structurally* incapable of carrying this on its own: `0.26.1` covers ~60 commits, so `--version` matching the tree's `Cargo.toml` proves nothing. The build hash `4555887` is the fact that matters, and it is printed to a human and never to a caller. ## Why existing gates cannot catch it **Every test builds its binary from the tree under test.** The test binary and the indexed tree are the same commit by construction, so the skew is *unrepresentable* in the harness. No fixture can currently disagree with itself. Compounding it, and found while verifying #83 in the same session: **`daemon_build` appears in no test file at all.** The skew disclosure that *does* exist is graded by a `render_daemon_build` unit test, never over the wire. So the one mechanism in this family is itself ungraded end to end. ## Repro 1. `cargo install --path .` (or unpack a release archive) at commit **A**. 2. Advance the working tree to commit **B**, where some resolver or disclosure behaviour changed. 3. Run the MCP server from the installed binary against that tree. 4. Ask a question whose answer differs between A and B. Today's instance, verbatim: `search_symbols("plugin_add", kind: "method")` against a tree containing `2f16e22`. The reply is **A's answer, presented as current, with no field saying so.** ## What must NOT be done - **Do not compare `--version` against the tree's `Cargo.toml` version.** It does not move per commit; it would report `Matched` across the whole sixty-commit window that produced this bug. - **Do not force a respawn, rebuild or refusal on mismatch.** #83 already argued this correctly: an older binary is not automatically wrong, and forcing a rebuild mid-session is disruptive. **Disclosure is the requirement; refusal is a separate policy argument.** - **Do not put it only in the daemon log.** That is precisely the channel #83 moved *away* from (`tracing::warn!` reaches no agent). - **Do not let absent read as "current".** Three states, as everywhere else here: absent = this build did not report; equal = verified; different = the finding. An older daemon that cannot report must produce `unavailable`, not silence. - **Do not grade it with a test that builds both sides from HEAD** — that is the vacuity that hides it today. The test has to construct a genuine skew (e.g. stamp a different build hash into the index rows, or run a binary built from an earlier `git archive`). ## Shape of the fix, stated as a requirement rather than a design A reply whose content can differ between binaries must carry **which binary produced it**. The natural carrier already half-exists: the build hash is compiled in and printed by `--version`; the index rows were written by *some* binary. Comparing *the binary that wrote the rows* against *the binary now serving them* is the measurement, and it needs no git call at query time. Cross-check against the sibling issue before implementing: a reader debugging a wrong answer needs **both** "which binary answered" and "which tree it had read", and they should be one block, not two unrelated fields. ## Severity argument This is the "two states rendering identically" failure at the **outermost layer** — the one the entire disclosure discipline in this repo exists to prevent. Every honest three-state field inside the product is undermined if the whole answer can silently come from a different build. And its first observed victim was a triage pass whose entire job was deciding what is true. 🤖 Filed by the triage lane, 2026-09-06, from a live misread. Installed binary `0.26.1 (4555887)`; tree `f6a878a`→`45cf6e4`.
Author
Member

Sibling filed: #182 — the index discloses its root but never its commit.

Same family, opposite direction, both violated in this one session:

  • #181 (this) — a stale binary answered about a current tree. Cost: #118 read as unfixed inside the session that had verified the fix.
  • #182 — a current binary answered about a different tree. Cost: an agent pinned to f6a878a was served 45cf6e4 content and caught it only because a test contradicted a file it had already read.

A reader debugging a wrong answer needs both facts — which binary answered and which tree state it was reading — and they should be one disclosure block, not two fields invented separately. Whoever picks up either should read the other first.

Sibling filed: **#182** — *the index discloses its root but never its commit*. Same family, opposite direction, both violated in this one session: - **#181 (this)** — a *stale binary* answered about a *current tree*. Cost: #118 read as unfixed inside the session that had verified the fix. - **#182** — a *current binary* answered about a *different tree*. Cost: an agent pinned to `f6a878a` was served `45cf6e4` content and caught it only because a test contradicted a file it had already read. A reader debugging a wrong answer needs both facts — *which binary answered* and *which tree state it was reading* — and they should be one disclosure block, not two fields invented separately. Whoever picks up either should read the other first.
Author
Member

CONFIRMED, and both of your measured claims reproduce on this tree. Fixed on lane/provenance (worktree /tmp/cosi-lane-provenance, based on fc329a8), together with #182 as one block.

The two claims, verified

1. daemon_build appears in no test file. True at 552e3a2 and at fc329a8: grep -rn "daemon_build\|DaemonBuild" crates/*/tests/ returned nothing. The one skew mechanism this product ships was ungraded end to end.

2. The version string is structurally incapable — and #83 was using it anyway. RpcIndex::daemon_build compared env!("CARGO_PKG_VERSION") against lock.version. Both are 0.26.1, so DaemonBuild::Matched was the verdict across the whole sixty-commit window, and Matched emits nothing. #83's disclosure was silent about exactly the skew it exists to report. CODE_INDEX_VERSION — the hash — reached the clap --version attribute of three binaries and no payload anywhere.

What shipped

answer_provenance, on every non-error reply and every JSON resource, from one function above the tool router (beside annotate_evidence_gaps, same placement argument: a surface that has to opt in is a surface that will one day forget to):

"answer_provenance": {
  "build": "0.26.1 (e56c6c7)",
  "indexed_trees": { "primary": { "head": "45cf6e4abcde", "uncommitted_changes": true } }
}

Plus daemon_build / daemon_build_unavailable, emitted only when that comparison disagrees or could not be made.

It STATES rather than COMPARES, and that is a correction to your "shape of the fix". You proposed comparing the binary that wrote the rows against the binary now serving them. That comparison would have been silent in your own incident: the installed 0.26.1 (4555887) both wrote and served, so writer == server and the verdict is "matched". What the reader needed was the two identities side by side — the answering build, and the tree it had read — so the reader can see that 4555887 is sixty commits behind 45cf6e4. The server cannot make that comparison in general: outside dogfooding, the indexed repository is not this repository and the build hash is not one of its commits at all. So the block states both and the comparison is the reader's. Your requirement sentence — "a reply whose content can differ between binaries must carry which binary produced it" — is what is implemented; the DB stamp is not, and is not needed for it.

DaemonBuild now compares BUILDS. The daemon records build = CODE_INDEX_VERSION in its registration (a new optional field, wire-compatible). DaemonBuild::compare is a pure function so the decision is gradable without a filesystem. A registration with no build hash — a daemon predating this — is Unknown, never Matched, which is your "an older daemon that cannot report must produce unavailable, not silence", verbatim. A different version with no hash is still Skewed: that much the old payload does establish.

Grading — you named the vacuity, so here is what was run

You wrote "do not grade it with a test that builds both sides from HEAD". Both sides are built from HEAD by construction here, so the recorded identity is made to disagree instead — your own prescription, "stamp a different build hash":

  • a_daemon_built_from_another_commit_is_disclosed_over_the_wire spawns a real daemon, asserts the agreeing case emits nothing (so "the block is always there" cannot pass it by accident), then rewrites daemon.toml's build line and asserts the skew appears in project_overview.daemon_build and in the per-reply block — because your misread happened on search_symbols, not on an orientation call.
  • a_daemon_that_records_no_build_reports_unavailable_not_a_match removes the line entirely.
  • the_build_is_the_answering_binarys_own_and_carries_a_hash is two-sided: it equals what that binary prints for --version, and it is not the bare crate version.

Mutations, run, all RED:

mutation red
SERVING_BUILD = env!("CARGO_PKG_VERSION") the_build_is_the_answering_binarys_own_and_carries_a_hash
revert daemon_build to lock.version == mine a_daemon_built_from_another_commit… + two_builds_of_one_version_are_a_skew_not_a_match
buildless registration → Matched a_daemon_that_records_no_build… + a_registration_without_a_build_cannot_report_a_match
daemon stops recording build a_daemon_built_from_another_commit…
drop the version-skew arm a_registration_without_a_build_still_reports_a_version_skew
move the annotator into project_overview every_published_tool_carries_the_block
delete the resource-leg insertion the_resource_leg_carries_the_block_too

What it costs — measured twice, from both ends

32 estimated tokens per reply. the_block_costs_what_it_says_it_costs reads the block's own slice of the served bytes (the first version re-serialized the parsed block and reported 27 — a budget test measuring its own formatting, which is the vacuity shape this repo keeps re-learning), and tests/bench/ratchet.json reads the same figure from the other end: +32.4 / +32.6 / +32.1 tokens per call across three corpus tiers, uniformly.

That breached the agent-task ratchet. It is recorded, not argued away — including ratio_vs_rg_only falling 0.706→0.599, 0.472→0.393, 0.722→0.621, which is the product genuinely spending more context than ripgrep for the same answers. Attribution is against a clean fc329a8, not against the stale record: +279/+193/+58 of the gap belongs to other lanes landing since 1aa6514; the rest is this block and nothing else.

One trim was taken: git rev-parse in a non-checkout prints 66 characters, now the code not_a_git_checkout — 14 of the 36 tokens per call on a non-checkout fixture, which moved plugin-wpf from 1.058x (over) to 1.035x (inside, so that band was left alone). Every deeper compaction destroys a state, so none was taken: dropping the hash restores the comparison you forbid, dropping the uncommitted flag is what #182 forbids, and collapsing to a code moves the meaning into prose.

This is the one decision worth second-guessing. 32 tokens on every call is 14–17% of these benchmark tiers. It was paid rather than trimmed; a reviewer who disagrees is disagreeing with a number that is now recorded rather than with a claim.

Also fixed, found by this block

context_pack promises budget.tokens_used measures the complete response, and two annotators insert after that arithmetic. The number was short by exactly the disclosure — right in the fixture with nothing to disclose, wrong in every reply that had something. Pre-existing with #107's evidence_gaps; an always-present block is what made it visible. Fixed generically (restate_self_measurement, called from both annotators) plus context_pack costing its own block in the irreducible envelope — without which safety_net_drops, the counter that allocator exists to keep at zero, fired.

Docs: code-index://docs/answer-provenance.

**CONFIRMED, and both of your measured claims reproduce on this tree.** Fixed on `lane/provenance` (worktree `/tmp/cosi-lane-provenance`, based on `fc329a8`), together with #182 as one block. ## The two claims, verified **1. `daemon_build` appears in no test file.** True at `552e3a2` and at `fc329a8`: `grep -rn "daemon_build\|DaemonBuild" crates/*/tests/` returned nothing. The one skew mechanism this product ships was ungraded end to end. **2. The version string is structurally incapable — and #83 was using it anyway.** `RpcIndex::daemon_build` compared `env!("CARGO_PKG_VERSION")` against `lock.version`. Both are `0.26.1`, so **`DaemonBuild::Matched` was the verdict across the whole sixty-commit window**, and `Matched` emits nothing. #83's disclosure was silent about exactly the skew it exists to report. `CODE_INDEX_VERSION` — the hash — reached the clap `--version` attribute of three binaries and no payload anywhere. ## What shipped **`answer_provenance`, on every non-error reply and every JSON resource**, from one function above the tool router (beside `annotate_evidence_gaps`, same placement argument: a surface that has to opt in is a surface that will one day forget to): ```json "answer_provenance": { "build": "0.26.1 (e56c6c7)", "indexed_trees": { "primary": { "head": "45cf6e4abcde", "uncommitted_changes": true } } } ``` Plus `daemon_build` / `daemon_build_unavailable`, emitted only when that comparison disagrees or could not be made. **It STATES rather than COMPARES, and that is a correction to your "shape of the fix".** You proposed comparing *the binary that wrote the rows* against *the binary now serving them*. That comparison would have been **silent in your own incident**: the installed `0.26.1 (4555887)` both wrote and served, so writer == server and the verdict is "matched". What the reader needed was the two identities side by side — the answering build, and the tree it had read — so the *reader* can see that `4555887` is sixty commits behind `45cf6e4`. The server cannot make that comparison in general: outside dogfooding, the indexed repository is not this repository and the build hash is not one of its commits at all. So the block states both and the comparison is the reader's. Your requirement sentence — *"a reply whose content can differ between binaries must carry which binary produced it"* — is what is implemented; the DB stamp is not, and is not needed for it. **`DaemonBuild` now compares BUILDS.** The daemon records `build = CODE_INDEX_VERSION` in its registration (a new optional field, wire-compatible). `DaemonBuild::compare` is a pure function so the decision is gradable without a filesystem. A registration with **no** build hash — a daemon predating this — is `Unknown`, never `Matched`, which is your *"an older daemon that cannot report must produce `unavailable`, not silence"*, verbatim. A different **version** with no hash is still `Skewed`: that much the old payload does establish. ## Grading — you named the vacuity, so here is what was run You wrote *"do not grade it with a test that builds both sides from HEAD"*. Both sides are built from HEAD by construction here, so the **recorded identity** is made to disagree instead — your own prescription, *"stamp a different build hash"*: - `a_daemon_built_from_another_commit_is_disclosed_over_the_wire` spawns a real daemon, asserts the agreeing case emits **nothing** (so "the block is always there" cannot pass it by accident), then rewrites `daemon.toml`'s `build` line and asserts the skew appears in `project_overview.daemon_build` **and** in the per-reply block — because your misread happened on `search_symbols`, not on an orientation call. - `a_daemon_that_records_no_build_reports_unavailable_not_a_match` removes the line entirely. - `the_build_is_the_answering_binarys_own_and_carries_a_hash` is two-sided: it equals what that binary prints for `--version`, **and** it is not the bare crate version. **Mutations, run, all RED:** | mutation | red | |---|---| | `SERVING_BUILD = env!("CARGO_PKG_VERSION")` | `the_build_is_the_answering_binarys_own_and_carries_a_hash` | | revert `daemon_build` to `lock.version == mine` | `a_daemon_built_from_another_commit…` + `two_builds_of_one_version_are_a_skew_not_a_match` | | buildless registration → `Matched` | `a_daemon_that_records_no_build…` + `a_registration_without_a_build_cannot_report_a_match` | | daemon stops recording `build` | `a_daemon_built_from_another_commit…` | | drop the version-skew arm | `a_registration_without_a_build_still_reports_a_version_skew` | | move the annotator into `project_overview` | `every_published_tool_carries_the_block` | | delete the resource-leg insertion | `the_resource_leg_carries_the_block_too` | ## What it costs — measured twice, from both ends **32 estimated tokens per reply.** `the_block_costs_what_it_says_it_costs` reads the block's own slice of the **served** bytes (the first version re-serialized the parsed block and reported 27 — a budget test measuring its own formatting, which is the vacuity shape this repo keeps re-learning), and `tests/bench/ratchet.json` reads the same figure from the other end: **+32.4 / +32.6 / +32.1 tokens per call** across three corpus tiers, uniformly. That breached the agent-task ratchet. It is **recorded, not argued away** — including `ratio_vs_rg_only` falling 0.706→0.599, 0.472→0.393, 0.722→0.621, which is the product genuinely spending more context than ripgrep for the same answers. Attribution is against a **clean `fc329a8`**, not against the stale record: +279/+193/+58 of the gap belongs to other lanes landing since `1aa6514`; the rest is this block and nothing else. One trim was taken: `git rev-parse` in a non-checkout prints 66 characters, now the code `not_a_git_checkout` — 14 of the 36 tokens per call on a non-checkout fixture, which moved `plugin-wpf` from 1.058x (over) to 1.035x (inside, so that band was left alone). Every deeper compaction destroys a state, so none was taken: dropping the hash restores the comparison you forbid, dropping the uncommitted flag is what #182 forbids, and collapsing to a code moves the meaning into prose. **This is the one decision worth second-guessing.** 32 tokens on every call is 14–17% of these benchmark tiers. It was paid rather than trimmed; a reviewer who disagrees is disagreeing with a number that is now recorded rather than with a claim. ## Also fixed, found by this block `context_pack` promises `budget.tokens_used` measures the **complete** response, and two annotators insert after that arithmetic. The number was short by exactly the disclosure — right in the fixture with nothing to disclose, wrong in every reply that had something. **Pre-existing with #107's `evidence_gaps`**; an always-present block is what made it visible. Fixed generically (`restate_self_measurement`, called from both annotators) plus `context_pack` costing its own block in the irreducible envelope — without which `safety_net_drops`, the counter that allocator exists to keep at zero, fired. Docs: `code-index://docs/answer-provenance`.
Author
Member

FIXED in fb37a49, merged as 4f866e5.

Replies now carry answer_provenance: the build hash the answering binary was compiled from, the tree head the index had read, and a dirty flag. answer_provenance_e2e is 10/10 including a_daemon_built_from_another_commit_is_disclosed_over_the_wire and two_checkouts_at_two_commits_do_not_report_the_same_tree.

One design point worth recording, because I got it wrong first and the lane refuted it: I proposed making the block conditional — emit it only when the build and the tree disagree. That is silent exactly where it is needed. Both incidents that motivated this issue were agreement failures: client and daemon agreed with each other at a commit 65 behind, the tree was clean, and everything comparable matched. A conditional keyed on "matches" would have emitted nothing in both. The fields are identities, not comparison results, and an identity has no nominal form to omit.

Closing.

FIXED in `fb37a49`, merged as `4f866e5`. Replies now carry `answer_provenance`: the build hash the answering binary was compiled from, the tree head the index had read, and a dirty flag. `answer_provenance_e2e` is 10/10 including `a_daemon_built_from_another_commit_is_disclosed_over_the_wire` and `two_checkouts_at_two_commits_do_not_report_the_same_tree`. One design point worth recording, because I got it wrong first and the lane refuted it: I proposed making the block **conditional** — emit it only when the build and the tree disagree. That is silent exactly where it is needed. Both incidents that motivated this issue were *agreement* failures: client and daemon agreed with each other at a commit 65 behind, the tree was clean, and everything comparable matched. A conditional keyed on "matches" would have emitted nothing in both. The fields are **identities, not comparison results**, and an identity has no nominal form to omit. Closing.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
h-dv/code-index#181
No description provided.