Skip to content

Audit INVARIANT comments so each claims only what its oracle pins (ADR-0027 trigger) #524

Open

Description

@brenpike

Summary

Audit every INVARIANT: comment in the repository and make each one claim only what its named oracle actually pins, per ADR-0027.

ADR-0027's promotion trigger has fired: a third review finding whose root was an INVARIANT: comment naming an oracle that does not pin the claim the comment makes. The ADR defers the corpus audit as a residual until that trigger fires. This issue is the promoted work.

Root cause

An INVARIANT: comment is a load-bearing prose assertion with nothing binding it to the behaviour it asserts. A comment can name a real, passing, relevant test that only pins part of its claim (or none of it). The reader trusts the broader claim; no build or test ever objects.

Instances that tripped the trigger

  1. bca45c2 — recorded in ADR-0027 as Instance update azure pipelines #1.
  2. 75e64a32 — local review finding on the Discarded messages — including Service Broker Error messages — commit the RECEIVE without ending the conversation #357/SQL error 208 classified as transient — a missing queue retries forever instead of failing fast #358 branch: the ServiceBrokerMessageClassifier ordering INVARIANT named a mutation that could not redden its oracle. Fixed in-branch.
  3. cb3be8b7 — local review finding on the Discarded messages — including Service Broker Error messages — commit the RECEIVE without ending the conversation #357/SQL error 208 classified as transient — a missing queue retries forever instead of failing fast #358 branch: the ServiceBrokerErrorPayload INVARIANT claimed only the documented Error document could project a value, while its named mutation pinned only the namespace allowlist. Fixed in-branch by re-keying the comment onto what the code produces.

Scope

  • Roughly 704 INVARIANT: occurrences across 237 .cs files (about 454 in production code, 250 in tests), across all modules.
  • For each comment: confirm the named oracle exists, apply the named mutation (or reason about it where a mutation is impractical), and confirm the oracle reddens. Where it does not, narrow the claim to what is pinned, name a real oracle, or state plainly that no test pins it.
  • Per ADR-0027's trigger wording, the response is to question what each comment is keyed on, not to add a check. A lint remains rejected on the merits.

Bounded impact

Comments do not execute. A stale or overclaiming INVARIANT changes no runtime behaviour; the risk is a reader making a change on a false belief about what is protected. Low urgency, documentation accuracy.

Suggested approach

Module by module, one PR per module, so each audit stays reviewable and ships with the module it touches.

Activity

  1. added
    effort:xltriage effort rating
    risk:lowtriage risk rating
    and removed
    effort:ltriage effort rating
    on Sep 24, 2026
  2. brenpike commented on Sep 24, 2026

    @brenpike
    OwnerAuthor

    Recorded residual from #395 (drop net8.0, single-target net10.0).

    About 40 existing INVARIANT: and mutation-evidence comments say a mutation was "measured on net8.0 and net10.0" or "on both target frameworks". After #395 only net10.0 exists. The main sites are in Chatter.MessageBrokers and Chatter.MessageBrokers.Reliability.EntityFramework: BrokeredMessageInbox.cs, BrokeredMessageOutbox.cs, OutboxProcessor.cs, InMemoryBrokeredMessageOutbox.cs, IPollableOutboxStore.cs, ReliabilityRetentionPurgeService.cs, UnitOfWork.cs, plus the EF integration suites.

    #395 deliberately leaves them alone:

    • They are still true. They record what was measured when the comment was written.
    • ADR-0027 only governs comments written or edited from now on.
    • Fixing them honestly means re-running each mutation on net10.0, which is about 40 mutations across modules. A find-and-replace would not do that.

    Bounded impact: documentation accuracy only. No runtime behavior and no test oracle depends on the wording. This audit should cover them when it re-verifies each INVARIANT.

  3. brenpike commented on Sep 29, 2026

    @brenpike
    OwnerAuthor

    Further instances found during the #533 local review, recorded here as the existing home rather than as a new issue.

    Branch-authored blocks (fixed on the #533 branch). Across four review iterations, the new INVARIANT: blocks in src/Chatter.MessageBrokers.RabbitMQ/src/Chatter.MessageBrokers.RabbitMQ/Receiving/RabbitMqReceiver.cs repeatedly claimed more than their oracles pin. Examples: a universal negative ("reads x-acquired-count on no delivery shape"), a bundled settlement block with one mutation for three claims, and a "derived once" clause that ignored a second read site in BuildClassicRedeliveryHeaders. Each round was fixed in-branch. A structural re-keying (native counters consumed at the receive capture point, one claim per INVARIANT: with measured mutations) closed the specific leak and the universal negative. It did not close the general class. Each rewrite of free prose can introduce a fresh clause broader than its oracles. That matches the root cause above, and ADR-0027 (amended on the #533 branch) records these as further instances of the trigger shape.

    Pre-existing blocks in scope for this audit. Codex also flagged six INVARIANT: blocks in the same file that are byte-identical to master and untouched by #533. At the #533 branch HEAD they sit at roughly :270-278, :362-368, :544-553, :575-578, :605-608 and :653-656. Per ADR-0027 they were not rewritten on that branch, and they belong to this audit.

    Bounded impact. Comment prose only. No runtime behaviour depends on these comments, and the full test suite is green on the #533 branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions