0.3.1 — the tools audit themselves
0.3.1 adds no capability. It turns three adversarial audits on tools that were already shipped, and fixes what they found: 39 verified defects, each reproduced against a real org. Then it fixes the 18 more that those fixes introduced, because a release that only reports the first number is telling you half of what happened.
The shape of the problem
This product sells one thing: a tool that will not answer confidently from data it does not have. Every defect below is a violation of that, committed by the product itself.
They cluster into three shapes. A tool asserting a zero it never checked. A tool naming a total it then does not enumerate. And a tool contradicting a sibling that answers the same question correctly — which turned out to be the highest-yield audit signal available: every cross-tool disagreement chased was a real defect in one of them.
What moved
| Measurement | Before | After |
|---|---|---|
| Apex classes reported as likely dead, of 186 | 85 | 0 |
| Classes reported as having no test, of which some had one | 58 | 19 |
| Save-order steps returned for a busy object | 5 of 57, marked complete | 57 of 57 |
| Share of a save response spent on the actual answer | 12% | 78% |
| Trigger-deactivation verdicts carrying information | 0 of 22 | 22 of 22 |
| Rows reachable by paging a code-quality audit | 94 of 647 | 647 of 647 |
| Rows reachable by paging an unused-field audit | 281 of 570 | 570 of 570 |
| Naming observations describing objects with no custom fields | 22 of 101 | 0 |
| Scheduled/batch classes reported as likely dead | 16 of 18 | 0 |
| "What runs when I save a contact?" answered end to end | no | yes |
Four that are worth naming individually
A verdict justified by something untrue about Salesforce
The dead-code tool told you it was safe to delete classes that run on a schedule. Its stated reason: such a class "must be enqueued, executed or scheduled by user Apex." That is not how the platform works. An admin scheduling a class through Setup creates a CronTrigger record —data, not metadata. It is never retrieved, becomes no node, mints no edge, and no refresh will ever close that gap.
On two real orgs, 16 of the 18 classes it called likely dead were exactly those. The code did what it was told; what it had been told about Salesforce was wrong — which is the one class of defect no amount of test coverage or graph completeness can catch.
They are now uncertain, at heuristic confidence, andCronTrigger is named as a blind spot that cannot be closed offline. The control matters as much as the fix: across all component types,definitely_dead is unchanged — 1,041 on one org and 979 on the other. The tool did not stop finding dead code; it stopped being certain where it had no right to be.
A reachability walk that certified its own blind spot
Three tools each carried their own hardcoded walk over a single edge type. A class reached by async dispatch, a static-field reference, or a page controller binding looked unreachable — and the soundness block attachedcomplete: true, because it was derived from a signal that knew nothing about which edge types had been skipped. A fourth tool walked the fuller set and disagreed with 81 of the 85 verdicts.
They now share one primitive, and usage is defined as a deny-list: every incoming edge type except structural and access edges. That direction is deliberate. An allow-list is what caused the bug — it was written before the async-dispatch edge type existed, and could never have learned about it.
A stale retrieval that overwrote the current one
A vault can end up holding two complete retrievals. Node writes are keyed on component id and replace on conflict, and the directory walk is alphabetical, so the older copy was written second and won. On a real org, three profiles reported a multi-factor-authentication bypass that the current retrieval no longer declared.
The canonical layout now wins, and every conflicted component carries asourceConflict field naming both paths, the copy that answered, and how it was chosen. Where the vault genuinely cannot tell which retrieval is current, it says so rather than picking — retrieval times are recorded per metadata family, never per path, so a newest-wins rule would be a guess wearing a timestamp.
The honesty payload was being truncated
The response trimmer learned to descend one level into the payload, which made the disclosure arrays reachable — the lists of what the tool did not check. On a tight budget it began shortening them, under a note claiming a true total was published somewhere it was not.
Disclosures are now never trim candidates. If a response cannot fit, it refuses and names the knobs that would narrow it. An honest refusal beats a quietly shortened list of blind spots, because a reader who does not notice the shortening ends up more confident than the evidence supports.
The 18 we caused
Fixing 39 honesty defects introduced 18 more. A search that gained pagination got a sort with no total order, so one row appeared twice and another never. Ten inputs were built and never advertised, so no schema-driven host could reach them — including the pagination that was the point of the work. A budget fix was undone by an enrichment block that reserved its share before the answer was seated.
Every one of those was invisible to the test suite. There were more than eight thousand passing tests at the moment the trimmer was silently shortening the list of things it had not checked. They were caught by a review pass reading the diff, and by an adversarial pass asking real questions against real vaults.
We are reporting that number because a release note claiming a clean sweep from the same team that shipped the original 39 would not be credible, and because the ratio is the argument for the process rather than against it.
What was actually wrong, underneath
Almost every defect was a second copy of something. Two constants with the same name and different text. A block duplicated across two files under a comment promising they would stay identical. A hand-copied JSON Schema beside the validator that actually runs. Two counters for one fact. Two byte limits that had to stay ordered, set independently, in the wrong order.
Every one of those was written by someone who knew about the duplication — several are documented as duplicates in their own comments. The comment was the mechanism, and comments do not hold. So the durable part of this release is not the fixes; it is what replaced those comments:
- A schema-parity gate over all 217 tools on four axes, with 27 pre-existing violations baselined and reasoned rather than hidden.
- A tool-local byte budget derived from the global one, so the ordering holds by construction instead of by convention.
- Drift tests that run two implementations of a shared predicate against the same fixture and assert they agree, in place of a promise that they will.
- A documentation pin that could not fire — its pattern could not match across a line break, so a stale count sat next to three correct ones and the file reported clean.
One question that did not work at all
"What runs when I save a contact?" — arguably the question this product exists to answer — failed end to end. The router bound the object name as typed, and seven object-scoped tools rejected a lower-case api name that two others accepted. Salesforce api names are case-insensitive; the product was not.
Fixed in one shared resolver rather than seven tools, with a private copy in an eighth deleted in favour of it. Resolution does not become identity: the id echoed back is always the vault's exact casing, and two ids differing only by case refuse rather than picking one. The question now returns 57 save-order steps.
Upgrading
Nothing in this release changes a tool's input contract in a way that breaks an existing call. Ten tools gained advertised inputs they already accepted, one tool dropped an input that was a pure synonym for the canonical one, and several tools now refuse selector combinations that previously resolved silently to something you did not ask for.
If your vault holds more than one retrieval of the same org — a source tree with both a flat layout and an SFDX layout — rebuild it. Until you do, the tools will now tell you which components are affected instead of quietly answering from whichever copy sorted last.