Skip to content

+ executing coverage for the ReFS offline block clone - #383

Merged
Hawkynt merged 2 commits into
mainfrom
feat/refs-clone-coverage
Sep 21, 2026
Merged

Hawkynt merged 2 commits into
mainfrom
feat/refs-clone-coverage

Conversation

@Hawkynt

@Hawkynt Hawkynt commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Why

RefsOfflineBlockCloner (263 lines) and RefsCowBlockRefcountEditor had no test that ever ran.

Their only caller was RefsBlockCloneExternalTests, which

  • sits in ExternalFsInterop, a tier the core CI filter excludes,
  • needs CWB_REFS_CLONE_IMAGE and CWB_REFS_FOREFST, which nothing sets,
  • has no fixture generator, and
  • runs under continue-on-error: true.

So it always reached Assert.Ignore. A primitive whose failure mode is silent cross-file extent corruption — two streams quietly sharing clusters they should not, or reference counts that disagree with reality — was covered by a placeholder.

The gap was structural rather than neglect: this package deliberately has no ReFS creator (the writer edits existing volumes only), so there was no image to drive the cloner against.

What is here

RefsSyntheticVolume builds a byte-exact unmounted ReFS 3.14 image — VBR, SUPB, two CHKP slots, Container Table, Object Table, Schema Table, Medium Allocator, Block Refcount and a root-directory object. Every tree is a single leaf page, so no B+ split, separator-key convention or 128 KiB Upcase Table is involved. It is a test fixture, not a mkfs.

RefsImageProbe decodes the result straight from raw bytes — checkpoint clocks, root descriptors, B+ rows, Block Refcount words, allocator bitmaps, extent tables — and shares no code with the reader, writer or CoW engine. Our reader is a weak oracle for our own writer; this is the second pair of eyes.

RefsBlockCloneTests — 14 tests, all in the core tier the gate actually runs:

Whole-file clone both files' extents name the same clusters, refcount rows say 2, contents read back
First clone, absent row the sparse row is materialised at count 2, not 1
First clone, zero slot an existing row is updated, not duplicated
Checkpoint discipline roots #0 and #6 publish together through the alternate slot; the superseded slot still describes the pre-clone volume; allocator root #1 accounts for the new CoW pages; the destination's former allocation is reclaimed only after the commit
Aborted publication a write failure injected into the alternate checkpoint leaves the volume byte-identical and still readable
Copy-on-write isolation writing one clone reallocates instead of overwriting the shared clusters, and drops their count
Fragmented source every run is carried across, none collapsed or dropped
Refusals unequal sizes · non-aligned sizes · resident streams · empty streams · repeated sharing · self-clone · unknown destination — each rejected without touching a byte

Proof the assertions bite

Every assertion was verified against a deliberate break of the code it covers:

Perturbation Failing assertion
drop the implicit-owner baseline in AddCloneReferences refcount is 2 (5 failures)
skip the sparse-row insertion in RefsCowBlockRefcountEditor a refcount row exists for the shared cluster (4 failures)
publish root #0 without root #6 root #6 moved in the same checkpoint (6 failures)
reclaim the former allocation before the commit allocator unchanged after an aborted clone (1 failure)
off-by-one on the cloned extent shared clusters and round-tripped content (5 failures)

The cloner's own VerifyClone self-check was disabled alongside the first, third and fifth of these, so the failures come from the new assertions rather than from production code catching itself.

Outcome

The cloner is correct on its stated profile. Driving it end to end found no defect.

Also

  • Deletes .github/workflows/refs-diagnostic.yml, which triggered only on pushes to refs-block-refcount-clone — a branch whose content was absorbed into Integrate fourteen filesystem and format maintenance branches #325 and which has since been deleted. It was never a gate; it built under continue-on-error and uploaded a log. No other workflow references the dead branch.
  • Reconciles Hawkynt.FileFormats.FileSystems/README.md, which still listed "Block Refcount row creation and clone semantics" as an open gap, contradicting the shipped code. It now describes what the clone does and states plainly that no public verb reaches this primitive — it is a library entry point, not something cwb can be asked to do.

Public surface is unchanged, so REFERENCE.md needs no regeneration.

RefsOfflineBlockCloner and RefsCowBlockRefcountEditor had no test that ever
ran. Their only caller was RefsBlockCloneExternalTests, which sits in the
ExternalFsInterop tier the core CI filter excludes, needs CWB_REFS_CLONE_IMAGE
and CWB_REFS_FOREFST that nothing sets, generates no fixture, and runs under
continue-on-error - so it always reached Assert.Ignore. A 263-line primitive
whose failure mode is silent cross-file extent corruption was therefore shipped
on the strength of a placeholder.

Root cause of the gap is structural, not neglect: this package deliberately has
no ReFS creator - the writer edits existing volumes only - so there was no image
to drive the cloner against, and nobody wrote one.

RefsSyntheticVolume now builds a byte-exact unmounted ReFS 3.14 image: VBR, SUPB,
two CHKP slots, Container Table, Object Table, Schema Table, Medium Allocator,
Block Refcount and a root-directory object, every tree a single leaf page so no
B+ split, separator-key convention or Upcase Table is involved. RefsImageProbe
decodes the result straight from raw bytes and shares no code with the reader,
writer or CoW engine, so the assertions are not our reader agreeing with our
writer.

Covered, running in the core tier: whole-file clone of two equal-sized
cluster-aligned extent-backed files; first-clone materialisation both of an
absent Block Refcount row and of a zero slot in an existing one; paired
publication of Object Table root #0 and Block Refcount root #6 through the
alternate checkpoint with the superseded slot left intact; allocator roots
accounting for the newly reserved CoW pages; reclamation of the destination's
former allocation only after the checkpoint is durable; an abort injected into
the checkpoint write leaving the volume byte-identical; copy-on-write isolation
when one clone is written afterwards; fragmented sources carrying every run; and
refusal of unequal sizes, non-aligned sizes, resident streams, empty streams,
repeated sharing, self-clone and unknown destinations.

Every assertion was verified to bite by perturbing the code it covers: removing
the implicit-owner baseline from AddCloneReferences, skipping the sparse-row
insertion, publishing root #0 without root #6, reclaiming before the commit, and
an off-by-one on the cloned extent each fail the tests that name them.

The cloner itself turned out to be correct on its stated profile.
.github/workflows/refs-diagnostic.yml triggered only on pushes to the branch
refs-block-refcount-clone, which no longer exists: its content was absorbed into
#325 and the remote branch has since been deleted, so the workflow can never
fire again.

It was never a gate in the first place. The job cloned the PNGCrushCS sibling,
restored and built the solution with continue-on-error, uploaded the build log
and re-raised the build result - a debugging aid for one red branch. That branch
was red three times on

  error CS0104: 'Category' is an ambiguous reference between
  System.ComponentModel.CategoryAttribute and NUnit.Framework.CategoryAttribute

which #325 fixed with a using alias, leaving the workflow with nothing to
diagnose. No other workflow or script references the dead branch.
@Hawkynt
Hawkynt force-pushed the feat/refs-clone-coverage branch from 067e530 to 307d979 Compare September 21, 2026 09:17
@Hawkynt
Hawkynt merged commit 6edf386 into main Sep 21, 2026
5 checks passed
@Hawkynt
Hawkynt deleted the feat/refs-clone-coverage branch September 21, 2026 10:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant