Skip to content

v0.2.5 — field-audit surface + delete-safety edge fixes + refresh data-loss fixes

Choose a tag to compare

@PranavNagrecha PranavNagrecha released this 29 Jul 19:10
· 208 commits to main since this release
b46af62

Closes five ways sfi.safe_to_delete_field could report a field safe when the platform refuses to delete it, and fixes four pre-existing refresh bugs found along the way — one of which deleted the vault it was refreshing and reported success.

Delete-safety gaps closed

Every one sat inside a metadata family the refresh had fully retrieved, so no coverageCaveat fired and the verdict presented as clean rather than hedged. A tool can only warn about the gaps it knows it has.

Gap Symptom
Flow record-trigger entry criteria Flow ships two XML spellings of one condition triplet; only <leftValueReference> was parsed. On the reference org: 449 filters across 160 of 275 flows, 100% in the unparsed <field> dialect
Roll-up coupling Held as a node property, never an edge — declared on the parent, so a child-field walk never reached it
Condition field refs Held as a property; firesWhen runs firer → context, so nothing reached the field
Formula __r traversals Skipped — a field read only via Parent__r.Field__c showed zero referrers
FlexiPage relatedListFieldAliases Bare names on the related object, invisible to the dotted sweep

85 fields on the reference org had zero dependency evidence before this release.

Citation honesty

A correct verdict with invented evidence is still a defect. Fixed: a roll-up summary cited on 127 fields where none exists; a traversalPath promised in a note that no renderer emitted; two of three roll-up roles described; 4 of 7 condition firer families named; and one validation rule counted as two blockers in two categories. Every citation now names the component to actually go change.

Refresh bugs (all pre-existing)

  • reconcileSourceDeletions deleted the vault it was refreshing. It compared raw paths across two layouts, so every in-scope file read as "deleted in the org" — 974 nodes, status: success, exit 0. Reproduced by executing the shipped code: 8 of 8 files deleted. Now layout-agnostic, with a wholesale-deletion guard that refuses and explains.
  • The additive retrieve had never worked. It named an --output-dir modern sf rejects. Both explicit targets are refused; the accepted form names none.
  • A failed report pull was swallowed, leaving a vault byte-identical to a successful one. Now recorded on the manifest and printed.
  • Report coverage asserted a confirmed zero it could never contradict — retrieved was counted after the usage fold drops those nodes, yet retrieveConfirmed: true was stamped anyway, about an org with 4,296 reports.

⚠️ Behaviour change

safe is harder to reach on a coverage-degraded vault. Four more condition-firer families are attested, and a pre-0.2.5 vault routes safereview until re-refreshed. Deliberate: an unretrieved family can hide a condition blocker. Re-run sfi refresh after upgrading.

New surface

salesforce-field-audit (26th skill) · salesforce-field-auditor + salesforce-field-refuter (the plugin's first subagents) · /sfi-field-audit · sfi.field_audit MCP prompt · field_360.rollups

209 tools · 26 skills · 5 slash commands · 2 subagents

Verification

9,895 tests, lint, all gates, CI on Node 20/22 + macOS. Real-org end-to-end through the MCP server: each fixed path returns blocking with a checkable citation, and a field with no dependencies still returns review — not blocking — so the tool still discriminates. All three refresh paths reconcile at identical counts.

Known limits

windows-build-test is skipped by repo config. Report coverage is honestly partial (1,959 of 4,296 retrieved, reported pending). The manifest edge tally is render-derived and under-counts; documented, not fixed.

📖 Can I delete this Salesforce field? — the method behind the release.