[fuchsia_inspect] Implement implicit root nodes.

Design: go/inspect-root
Change-Id: I2c65c4563fba73405aa1ab99b9ddbf0a45391d9d
diff --git a/public/dart/fuchsia_inspect/lib/src/testing/matcher.dart b/public/dart/fuchsia_inspect/lib/src/testing/matcher.dart
index 890c11c..be9b845 100644
--- a/public/dart/fuchsia_inspect/lib/src/testing/matcher.dart
+++ b/public/dart/fuchsia_inspect/lib/src/testing/matcher.dart
@@ -46,12 +46,7 @@
   /// Retrieve the root node matcher, which can be used to match against
   /// nested properties and children.
   NodeMatcher node() {
-    if (Block.read(_holder, 1).type == BlockType.nodeValue) {
-      return NodeMatcher._valid(this, 1);
-    } else {
-      _addError('No root node found at index 1');
-      return NodeMatcher._invalid(this);
-    }
+    return NodeMatcher._valid(this, 0);
   }
 
   // Internal method to check if the given index is valid and can be
diff --git a/public/dart/fuchsia_inspect/lib/src/vmo/block.dart b/public/dart/fuchsia_inspect/lib/src/vmo/block.dart
index e5b02c0..51eff4f 100644
--- a/public/dart/fuchsia_inspect/lib/src/vmo/block.dart
+++ b/public/dart/fuchsia_inspect/lib/src/vmo/block.dart
@@ -104,17 +104,6 @@
     _vmo.writeInt64Direct(_payloadOffset, _payloadBits.value);
   }
 
-  /// Initializes the root [BlockType.nodeValue] block.
-  ///
-  /// Throws [StateError] if this block wasn't [BlockType.reserved].
-  void becomeRoot() {
-    _checkType(BlockType.reserved);
-    becomeValue(parentIndex: rootParentIndex, nameIndex: rootNameIndex);
-    _header.write(orderBits, 0);
-    becomeNode();
-    _writeAllBits();
-  }
-
   /// Converts a [BlockType.anyValue] block to a [BlockType.nodeValue] block.
   ///
   /// Throws [StateError] if this block wasn't [BlockType.anyValue].
diff --git a/public/dart/fuchsia_inspect/lib/src/vmo/vmo_fields.dart b/public/dart/fuchsia_inspect/lib/src/vmo/vmo_fields.dart
index fcaddf5..e3ad98b 100644
--- a/public/dart/fuchsia_inspect/lib/src/vmo/vmo_fields.dart
+++ b/public/dart/fuchsia_inspect/lib/src/vmo/vmo_fields.dart
@@ -24,17 +24,8 @@
 /// Version for HEADER block.
 const int headerVersionNumber = 0;
 
-/// Index of the one-and-only root node (16 bytes).
-const int rootNodeIndex = 1;
-
-/// Each Node needs a parent; Root's parent is 0, which is never a real node.
-const int rootParentIndex = 0;
-
-/// Index of the NAME of the one-and-only root node (32 bytes).
-const int rootNameIndex = 2;
-
-/// First index availalbe for the heap.
-const int heapStartIndex = 4;
+/// First index available for the heap.
+const int heapStartIndex = 2;
 
 /// Size of VMO-block's header bitfield in bytes.
 const int headerSizeBytes = 8;
diff --git a/public/dart/fuchsia_inspect/lib/src/vmo/vmo_writer.dart b/public/dart/fuchsia_inspect/lib/src/vmo/vmo_writer.dart
index 813ddb8..4a0e71a 100644
--- a/public/dart/fuchsia_inspect/lib/src/vmo/vmo_writer.dart
+++ b/public/dart/fuchsia_inspect/lib/src/vmo/vmo_writer.dart
@@ -18,9 +18,6 @@
 /// Index 0 will never be allocated, so it's the designated 'invalid' value.
 const int invalidIndex = 0;
 
-/// Name of the root node.
-const String rootName = 'root';
-
 /// An Inspect-format VMO with accessors.
 ///
 /// This writes Values (Nodes, Metrics, and Properties) to
@@ -46,9 +43,6 @@
   VmoWriter(this._vmo, Function heapFactory) {
     _vmo.beginWork();
     _headerBlock = Block.create(_vmo, headerIndex)..becomeHeader();
-    Block.create(_vmo, rootNodeIndex, order: defaultBlockOrder).becomeRoot();
-    Block.create(_vmo, rootNameIndex, order: defaultBlockOrder)
-        .becomeName(rootName);
     _heap = heapFactory(_vmo);
     _vmo.commit();
   }
@@ -62,8 +56,8 @@
   /// Creates a [VmoWriter] with a given VMO.
   factory VmoWriter.withVmo(VmoHolder vmo) => VmoWriter(vmo, _heapCreate);
 
-  /// Gets the top Node of the Inspect tree (always at index 1).
-  int get rootNode => rootNodeIndex;
+  /// Gets the top Node of the Inspect tree (always set to index 0, which is the header).
+  int get rootNode => 0;
 
   /// The underlying VMO
   Vmo get vmo => _vmo.vmo;
@@ -221,7 +215,10 @@
     }
     nameBlock.becomeName(name);
     block.becomeValue(parentIndex: parent, nameIndex: nameBlock.index);
-    Block.read(_vmo, parent).childCount += 1;
+    if (parent != 0) {
+      // Only increment child count if the parent is not the special header block.
+      Block.read(_vmo, parent).childCount += 1;
+    }
     return block;
   }
 
@@ -315,6 +312,11 @@
   // If the parent is a TOMBSTONE and has no children then free it.
   // TOMBSTONES have no parent, so there's no recursion.
   void _unparent(Block value) {
+    if (value.parentIndex == 0) {
+      // Never delete the header node.
+      return;
+    }
+
     var parent = Block.read(_vmo, value.parentIndex);
     if (--parent.childCount == 0 && parent.type == BlockType.tombstone) {
       _heap.freeBlock(parent);
diff --git a/public/dart/fuchsia_inspect/test/vmo/block_test.dart b/public/dart/fuchsia_inspect/test/vmo/block_test.dart
index 78f7860..f0a0afc 100644
--- a/public/dart/fuchsia_inspect/test/vmo/block_test.dart
+++ b/public/dart/fuchsia_inspect/test/vmo/block_test.dart
@@ -22,8 +22,6 @@
         block.unlock();
       });
       _accepts(
-          'becomeRoot', [BlockType.reserved], (block) => block.becomeRoot());
-      _accepts(
           'becomeNode', [BlockType.anyValue], (block) => block.becomeNode());
       _accepts('becomeProperty', [BlockType.anyValue],
           (block) => block.becomeProperty());
@@ -159,13 +157,6 @@
           '00 0000 49 4E 53 50  0200 0000 0000 0000');
     });
 
-    test('Becoming the special root node', () {
-      final vmo = FakeVmoHolder(64);
-      Block.create(vmo, 1).becomeRoot();
-      compare(vmo, 16,
-          '${hexChar(BlockType.nodeValue.value)} 0 00 0000 2000 0000 0000');
-    });
-
     test('Becoming and modifying an intValue via free, reserved, anyValue', () {
       final vmo = FakeVmoHolder(64);
       final block = Block.create(vmo, 2)..becomeFree(5);
diff --git a/public/dart/fuchsia_inspect/test/vmo/heap_test.dart b/public/dart/fuchsia_inspect/test/vmo/heap_test.dart
index eadb586..f3704c9 100644
--- a/public/dart/fuchsia_inspect/test/vmo/heap_test.dart
+++ b/public/dart/fuchsia_inspect/test/vmo/heap_test.dart
@@ -15,15 +15,15 @@
 // In the VMO data structure, indexes 0..3 are reserved for VMO HEADER block,
 // root-node block, and root-node's name.
 //
-// A 128-byte heap holds indexes 0..7 (at 16 bytes per index).
+// A 96-byte heap holds indexes 0..5 (at 16 bytes per index).
 // Since allocated blocks are 32 bytes, the first allocated block will be at
-// index 4, and the second will be at index 6.
+// index 2, and the second will be at index 4.
 //
 // Two allocated blocks should be enough to test the data structure
-// algorithms, so the heap will be conveniently small at 128 bytes, and
-// we'll expect to see 4 and 6 as valid allocated indexes.
-const int _heapSizeBytes = 128;
-const List<int> _allocatedIndexes = [4, 6];
+// algorithms, so the heap will be conveniently small at 96 bytes, and
+// we'll expect to see 2 and 4 as valid allocated indexes.
+const int _heapSizeBytes = 96;
+const List<int> _allocatedIndexes = [2, 4];
 
 void main() {
   group('In the Heap', () {
@@ -33,12 +33,10 @@
       var f = hexChar(BlockType.free.value);
       compare(vmo, 0x00, '0  0 000000 00000000  00000000 00000000');
       compare(vmo, 0x10, '0  0 000000 00000000  00000000 00000000');
-      compare(vmo, 0x20, '0  0 000000 00000000  00000000 00000000');
+      compare(vmo, 0x20, '$f 1 000000 00000000  00000000 00000000');
       compare(vmo, 0x30, '0  0 000000 00000000  00000000 00000000');
       compare(vmo, 0x40, '$f 1 0_0000 00000000  00000000 00000000');
       compare(vmo, 0x50, '0  0 000000 00000000  00000000 00000000');
-      compare(vmo, 0x60, '$f 1 0_0000 00000000  00000000 00000000');
-      compare(vmo, 0x70, '0  0 000000 00000000  00000000 00000000');
     });
 
     test('allocate changes VMO contents correctly', () {
@@ -47,10 +45,10 @@
       var blocks = _allocateEverything(heap);
       expect(blocks, hasLength(2));
       var r = hexChar(BlockType.reserved.value);
+      compare(vmo, 0x20, '$r 1 0_0000 00000000  00000000 00000000');
+      compare(vmo, 0x30, '0  0 000000 00000000  00000000 00000000');
       compare(vmo, 0x40, '$r 1 0_0000 00000000  00000000 00000000');
       compare(vmo, 0x50, '0  0 000000 00000000  00000000 00000000');
-      compare(vmo, 0x60, '$r 1 0_0000 00000000  00000000 00000000');
-      compare(vmo, 0x70, '0  0 000000 00000000  00000000 00000000');
     });
 
     test('free and re-allocate work correctly', () {
@@ -80,7 +78,7 @@
   }
   // Make sure we're actually getting unique blocks
   expect(Set.of(blocks.map((block) => block.index)), hasLength(blocks.length));
-  // With a heapSize-byte VMO, valid indexes are only 4 and 6 (see comment above).
+  // With a heapSize-byte VMO, valid indexes are only 2 and 4 (see comment above).
   for (var block in blocks) {
     expect(block.index, isIn(_allocatedIndexes));
   }
diff --git a/public/dart/fuchsia_inspect/test/vmo/little_big_slab_test.dart b/public/dart/fuchsia_inspect/test/vmo/little_big_slab_test.dart
index 61449b7..8e9230d 100644
--- a/public/dart/fuchsia_inspect/test/vmo/little_big_slab_test.dart
+++ b/public/dart/fuchsia_inspect/test/vmo/little_big_slab_test.dart
@@ -17,12 +17,6 @@
 // root-node block, and root-node's name.
 //
 // A 128-byte heap holds indexes 0..7 (at 16 bytes per index).
-// Since allocated blocks are 32 bytes, the first allocated block will be at
-// index 4, and the second will be at index 6.
-//
-// Two allocated blocks should be enough to test the data structure
-// algorithms, so the heap will be conveniently small at 128 bytes, and
-// we'll expect to see 4 and 6 as valid allocated indexes.
 const int _heapSizeBytes = 128;
 
 void main() {
@@ -33,7 +27,7 @@
       var f = hexChar(BlockType.free.value);
       compare(vmo, 0x00, '0  0 000000 00000000  00000000 00000000');
       compare(vmo, 0x10, '0  0 000000 00000000  00000000 00000000');
-      compare(vmo, 0x20, '0  0 000000 00000000  00000000 00000000');
+      compare(vmo, 0x20, '$f 1 000000 00000000  00000000 00000000');
       compare(vmo, 0x30, '0  0 000000 00000000  00000000 00000000');
       compare(vmo, 0x40, '$f 1 0_0000 00000000  00000000 00000000');
       compare(vmo, 0x50, '0  0 000000 00000000  00000000 00000000');
@@ -42,13 +36,13 @@
     });
 
     test('allocate changes VMO contents correctly', () {
-      const List<int> _allocatedIndexes = [4, 6];
+      const List<int> _allocatedIndexes = [2, 4, 6];
 
       var vmo = FakeVmoHolder(_heapSizeBytes);
       var heap = LittleBigSlab(vmo, smallOrder: 1, bigOrder: 3);
       var blocks =
           _allocateEverything(heap, allocatedIndexes: _allocatedIndexes);
-      expect(blocks, hasLength(2));
+      expect(blocks, hasLength(3));
       var r = hexChar(BlockType.reserved.value);
       compare(vmo, 0x40, '$r 1 0_0000 00000000  00000000 00000000');
       compare(vmo, 0x50, '0  0 000000 00000000  00000000 00000000');
@@ -57,7 +51,7 @@
     });
 
     test('free and re-allocate work correctly', () {
-      const List<int> _allocatedIndexes = [4, 6];
+      const List<int> _allocatedIndexes = [2, 4, 6];
 
       var vmo = FakeVmoHolder(_heapSizeBytes);
       var heap = LittleBigSlab(vmo, smallOrder: 1, bigOrder: 5);
@@ -70,9 +64,12 @@
           _allocateEverything(heap, allocatedIndexes: _allocatedIndexes);
       expect(lastBlock, hasLength(1));
       // Free in reverse order to mix up the list
-      heap..freeBlock(blocks.removeLast())..freeBlock(lastBlock.removeLast());
+      heap
+        ..freeBlock(blocks.removeLast())
+        ..freeBlock(blocks.removeLast())
+        ..freeBlock(lastBlock.removeLast());
       blocks = _allocateEverything(heap, allocatedIndexes: _allocatedIndexes);
-      // Should get two blocks again
+      // Should get three blocks again
       expect(blocks, hasLength(_allocatedIndexes.length));
 
       // At this point, it is not possible to allocate a continuous big block
@@ -81,13 +78,13 @@
   });
   group('Tests specific to the little big slab allocator:', () {
     test('Allocate a big slab', () {
-      const List<int> _allocatedIndexes = [4, 6];
+      const List<int> _allocatedIndexes = [2, 4, 6];
 
       var vmo = FakeVmoHolder(_heapSizeBytes);
       var heap = LittleBigSlab(vmo, smallOrder: 1, bigOrder: 2);
       var blocks = _allocateEverything(heap,
           sizeHint: 128, allocatedIndexes: _allocatedIndexes);
-      expect(blocks, hasLength(1));
+      expect(blocks, hasLength(2));
       var r = hexChar(BlockType.reserved.value);
       compare(vmo, 0x40, '$r 2 0_0000 00000000  00000000 00000000');
       compare(vmo, 0x50, '0  0 000000 00000000  00000000 00000000');
@@ -98,7 +95,7 @@
     // Allocates the entire heap in small blocks.  This exercises block splits,
     // as well as heap grow.
     test('Allocate and grow heap', () {
-      const List<int> _allocatedIndexes = [4, 6, 8, 10, 12, 14];
+      const List<int> _allocatedIndexes = [2, 4, 6, 8, 10, 12, 14];
 
       const int heapSizeBytes = 256;
       var vmo = FakeVmoHolder(heapSizeBytes);
@@ -109,6 +106,8 @@
           sizeHint: 16, allocatedIndexes: _allocatedIndexes);
       expect(blocks, hasLength(_allocatedIndexes.length));
       var r = hexChar(BlockType.reserved.value);
+      compare(vmo, 0x20, '$r 1 0_0000 00000000  00000000 00000000');
+      compare(vmo, 0x30, '0  0 000000 00000000  00000000 00000000');
       compare(vmo, 0x40, '$r 1 0_0000 00000000  00000000 00000000');
       compare(vmo, 0x50, '0  0 000000 00000000  00000000 00000000');
       compare(vmo, 0x60, '$r 1 0_0000 00000000  00000000 00000000');
@@ -124,7 +123,7 @@
     });
 
     test('free and re-allocate work correctly', () {
-      List<int> _allocatedIndexes = [4];
+      List<int> _allocatedIndexes = [2, 4];
 
       var vmo = FakeVmoHolder(_heapSizeBytes);
       var heap = LittleBigSlab(vmo, smallOrder: 1, bigOrder: 2);
@@ -132,17 +131,20 @@
           sizeHint: 128, allocatedIndexes: _allocatedIndexes);
       expect(blocks, hasLength(_allocatedIndexes.length));
 
-      // Frees the only block, now the heap is all free.
-      heap.freeBlock(blocks.removeLast());
+      // Frees the only blocks, now the heap is all free.
+      heap..freeBlock(blocks.removeLast())..freeBlock(blocks.removeLast());
 
       // Allocate a smaller block now: it will convert the one big block into
       // two smaller ones.
-      _allocatedIndexes = [4, 6];
+      _allocatedIndexes = [2, 4, 6];
       blocks = _allocateEverything(heap, allocatedIndexes: _allocatedIndexes);
       expect(blocks, hasLength(_allocatedIndexes.length));
       // Free in reverse order to mix up the list
-      heap..freeBlock(blocks.removeLast())..freeBlock(blocks.removeLast());
-      // Should get two blocks again
+      heap
+        ..freeBlock(blocks.removeLast())
+        ..freeBlock(blocks.removeLast())
+        ..freeBlock(blocks.removeLast());
+      // Should get three blocks again
       blocks = _allocateEverything(heap, allocatedIndexes: _allocatedIndexes);
       expect(blocks, hasLength(_allocatedIndexes.length));
     });
@@ -159,7 +161,7 @@
   }
   // Make sure we're actually getting unique blocks
   expect(Set.of(blocks.map((block) => block.index)), hasLength(blocks.length));
-  // With a heapSize-byte VMO, valid indexes are only 4 and 6 (see comment above).
+  // With a heapSize-byte VMO, valid indexes are only 2, 4, and 6.
   for (var block in blocks) {
     expect(block.index, isIn(allocatedIndexes));
   }
diff --git a/public/dart/fuchsia_inspect/test/vmo/vmo_writer_test.dart b/public/dart/fuchsia_inspect/test/vmo/vmo_writer_test.dart
index 7ab3f71..c348eb4 100644
--- a/public/dart/fuchsia_inspect/test/vmo/vmo_writer_test.dart
+++ b/public/dart/fuchsia_inspect/test/vmo/vmo_writer_test.dart
@@ -33,15 +33,9 @@
         createWriter(vmo);
         final f = hexChar(BlockType.free.value);
         final h = hexChar(BlockType.header.value);
-        final n = hexChar(BlockType.nodeValue.value);
-        final u = hexChar(BlockType.nameUtf8.value);
-        String byte(char) => ascii(char).toRadixString(16).padLeft(2, '0');
-        final r = byte('r');
-        final t = byte('t');
-        final o = byte('o');
         compare(vmo, 0x00, '$h 0 000000 494E5350  00000000 00000000');
-        compare(vmo, 0x10, '$n 0 000000 20000000  00000000 00000000');
-        compare(vmo, 0x20, '$u 1 040000 00000000  $r$o$o$t 00000000');
+        compare(vmo, 0x10, '0  0 000000 00000000  00000000 00000000');
+        compare(vmo, 0x20, '$f 1 0_0000 00000000  00000000 00000000');
         compare(vmo, 0x30, '0  0 000000 00000000  00000000 00000000');
         compare(vmo, 0x40, '$f 2 0_0000 00000000  00000000 00000000');
         compare(vmo, 0x50, '0  0 000000 00000000  00000000 00000000');
@@ -49,8 +43,11 @@
         compare(vmo, 0x70, '0  0 000000 00000000  00000000 00000000');
         compare(vmo, 0x80, '$f 2 0_0000 00000000  00000000 00000000');
         compare(vmo, 0x90, '0  0 000000 00000000  00000000 00000000');
+        compare(vmo, 0xa0, '0  0 000000 00000000  00000000 00000000');
+        compare(vmo, 0xb0, '0  0 000000 00000000  00000000 00000000');
+        compare(vmo, 0xc0, '$f 2 0_0000 00000000  00000000 00000000');
         // Number of free blocks has been verified manually here.
-        expect(countFreeBlocks(vmo), 3, reason: dumpBlocks(vmo));
+        expect(countFreeBlocks(vmo), 5, reason: dumpBlocks(vmo));
       });
 
       test('failed createNode leaves VMO sequence number even (valid VMO)', () {
@@ -85,14 +82,10 @@
         final writer = createWriter(vmo);
         final checker = Checker(vmo)..check(0, []);
         final child = writer.createNode(writer.rootNode, 'child');
-        checker.check(1, [
-          Test(_nameFor(vmo, child), toByteData('child')),
-          Test(writer.rootNode, 1)
-        ]);
+        checker.check(2, [Test(_nameFor(vmo, child), toByteData('child'))]);
         writer.deleteEntity(child);
         // Deleting a node without children should free it and its name.
-        // root node should have 0 children.
-        checker.check(-2, [Test(writer.rootNode, 0)]);
+        checker.check(-2, []);
       });
 
       test('make, modify, and free IntMetric', () {
@@ -100,10 +93,9 @@
         final writer = createWriter(vmo);
         final checker = Checker(vmo)..check(0, []);
         final intMetric = writer.createMetric(writer.rootNode, 'intMetric', 1);
-        checker.check(1, [
+        checker.check(2, [
           Test(_nameFor(vmo, intMetric), toByteData('intMetric')),
-          Test(intMetric, 1, reason: 'int value wrong'),
-          Test(writer.rootNode, 1, reason: 'childCount wrong')
+          Test(intMetric, 1, reason: 'int value wrong')
         ]);
         writer.addMetric(intMetric, 2);
         checker.check(0, [Test(intMetric, 3)]);
@@ -112,7 +104,7 @@
         writer.setMetric(intMetric, 2);
         checker.check(0, [Test(intMetric, 2)]);
         writer.deleteEntity(intMetric);
-        checker.check(-2, [Test(writer.rootNode, 0)]);
+        checker.check(-2, []);
       });
 
       test('make, modify, and free DoubleMetric', () {
@@ -121,10 +113,9 @@
         final checker = Checker(vmo)..check(0, []);
         final doubleMetric =
             writer.createMetric(writer.rootNode, 'doubleMetric', 1.5);
-        checker.check(1, [
+        checker.check(2, [
           Test(_nameFor(vmo, doubleMetric), toByteData('doubleMetric')),
-          Test(doubleMetric, 1.5, reason: 'double value wrong'),
-          Test(writer.rootNode, 1, reason: 'childCount wrong')
+          Test(doubleMetric, 1.5, reason: 'double value wrong')
         ]);
         writer.addMetric(doubleMetric, 2.0);
         checker.check(0, [Test(doubleMetric, 3.5)]);
@@ -133,7 +124,7 @@
         writer.setMetric(doubleMetric, 1.5);
         checker.check(0, [Test(doubleMetric, 1.5)]);
         writer.deleteEntity(doubleMetric);
-        checker.check(-2, [Test(writer.rootNode, 0)]);
+        checker.check(-2, []);
       });
 
       test('make, modify, and free Property', () {
@@ -142,17 +133,14 @@
         final checker = Checker(vmo)..check(0, []);
 
         final property = writer.createProperty(writer.rootNode, 'prop');
-        checker.check(1, [
-          Test(_nameFor(vmo, property), toByteData('prop')),
-          Test(writer.rootNode, 1)
-        ]);
+        checker.check(2, [Test(_nameFor(vmo, property), toByteData('prop'))]);
         final bytes = ByteData(8)..setFloat64(0, 1.23);
         writer.setProperty(property, bytes);
-        checker.check(1, [Test(_extentFor(vmo, property), bytes)]);
+        // Same number of free blocks, since a large one is split.
+        checker.check(0, [Test(_extentFor(vmo, property), bytes)]);
         writer.deleteEntity(property);
-        // Property, its extent, and its name should be freed. Its parent should
-        // have one fewer children (0 in this case).
-        checker.check(-3, [Test(writer.rootNode, 0)]);
+        // Property, its extent, and its name should be freed.
+        checker.check(-3, []);
       });
 
       test('Node delete permutations', () {
@@ -160,16 +148,16 @@
         final writer = createWriter(vmo);
         final checker = Checker(vmo)..check(0, []);
         final parent = writer.createNode(writer.rootNode, 'parent');
-        checker.check(1, [Test(writer.rootNode, 1)]);
+        checker.check(2, []);
         final child = writer.createNode(parent, 'child');
-        checker.check(2, [Test(writer.rootNode, 1), Test(parent, 1)]);
+        checker.check(1, [Test(parent, 1)]);
         final metric = writer.createMetric(child, 'metric', 1);
-        checker.check(1, [Test(child, 1), Test(parent, 1)]);
+        checker.check(2, [Test(child, 1), Test(parent, 1)]);
         writer.deleteEntity(child);
         // Now child should be a tombstone; only its name should be freed.
         checker.check(-1, [Test(child, 1), Test(parent, 0)]);
         writer.deleteEntity(parent);
-        checker.check(-2, [Test(writer.rootNode, 0)]);
+        checker.check(-2, []);
         writer.deleteEntity(metric);
         // Metric, its name, and child should be freed.
         checker.check(-3, []);
@@ -179,7 +167,6 @@
         checker.check(2, [
           Test(_nameFor(vmo, newMetric), toByteData('newIntMetric')),
           Test(newMetric, 42),
-          Test(writer.rootNode, 1)
         ]);
       });
 
@@ -273,7 +260,7 @@
         // Note that the node and property names are truncated.
         final node = writer.createNode(writer.rootNode,
             'N012345678901234567890123456789012345678901234567890123456789000');
-        checker.check(1, [
+        checker.check(2, [
           Test(
               _nameFor(vmo, node),
               toByteData(
@@ -282,7 +269,7 @@
 
         final property = writer.createProperty(node,
             'PP012345678901234567890123456789012345678901234567890123456789000');
-        checker.check(2, [
+        checker.check(1, [
           Test(
               _nameFor(vmo, property),
               toByteData(
@@ -302,21 +289,15 @@
         createWriter(vmo);
         final f = hexChar(BlockType.free.value);
         final h = hexChar(BlockType.header.value);
-        final n = hexChar(BlockType.nodeValue.value);
-        final u = hexChar(BlockType.nameUtf8.value);
-        String byte(char) => ascii(char).toRadixString(16).padLeft(2, '0');
-        final r = byte('r');
-        final t = byte('t');
-        final o = byte('o');
         compare(vmo, 0x00, '$h 0 000000 494E5350  00000000 00000000');
-        compare(vmo, 0x10, '$n 0 000000 20000000  00000000 00000000');
-        compare(vmo, 0x20, '$u 1 040000 00000000  $r$o$o$t 00000000');
+        compare(vmo, 0x10, '0  0 000000 00000000  00000000 00000000');
+        compare(vmo, 0x20, '$f 1 0_0000 00000000  00000000 00000000');
         compare(vmo, 0x30, '0  0 000000 00000000  00000000 00000000');
         compare(vmo, 0x40, '$f 1 0_0000 00000000  00000000 00000000');
         compare(vmo, 0x50, '0  0 000000 00000000  00000000 00000000');
         compare(vmo, 0x60, '$f 1 0_0000 00000000  00000000 00000000');
         compare(vmo, 0x70, '0  0 000000 00000000  00000000 00000000');
-        expect(countFreeBlocks(vmo), 6, reason: dumpBlocks(vmo));
+        expect(countFreeBlocks(vmo), 8, reason: dumpBlocks(vmo));
       });
 
       test('failed createNode leaves VMO sequence number even (valid VMO)', () {
@@ -351,14 +332,11 @@
         final writer = createWriter(vmo);
         final checker = Checker(vmo)..check(0, []);
         final child = writer.createNode(writer.rootNode, 'child');
-        checker.check(2, [
-          Test(_nameFor(vmo, child), toByteData('child')),
-          Test(writer.rootNode, 1)
-        ]);
+        checker.check(2, [Test(_nameFor(vmo, child), toByteData('child'))]);
         writer.deleteEntity(child);
         // Deleting a node without children should free it and its name.
         // root node should have 0 children.
-        checker.check(-2, [Test(writer.rootNode, 0)]);
+        checker.check(-2, []);
       });
 
       test('make, modify, and free IntMetric', () {
@@ -368,8 +346,7 @@
         final intMetric = writer.createMetric(writer.rootNode, 'intMetric', 1);
         checker.check(2, [
           Test(_nameFor(vmo, intMetric), toByteData('intMetric')),
-          Test(intMetric, 1, reason: 'int value wrong'),
-          Test(writer.rootNode, 1, reason: 'childCount wrong')
+          Test(intMetric, 1, reason: 'int value wrong')
         ]);
         writer.addMetric(intMetric, 2);
         checker.check(0, [Test(intMetric, 3)]);
@@ -378,7 +355,7 @@
         writer.setMetric(intMetric, 2);
         checker.check(0, [Test(intMetric, 2)]);
         writer.deleteEntity(intMetric);
-        checker.check(-2, [Test(writer.rootNode, 0)]);
+        checker.check(-2, []);
       });
 
       test('make, modify, and free DoubleMetric', () {
@@ -389,8 +366,7 @@
             writer.createMetric(writer.rootNode, 'doubleMetric', 1.5);
         checker.check(2, [
           Test(_nameFor(vmo, doubleMetric), toByteData('doubleMetric')),
-          Test(doubleMetric, 1.5, reason: 'double value wrong'),
-          Test(writer.rootNode, 1, reason: 'childCount wrong')
+          Test(doubleMetric, 1.5, reason: 'double value wrong')
         ]);
         writer.addMetric(doubleMetric, 2.0);
         checker.check(0, [Test(doubleMetric, 3.5)]);
@@ -399,7 +375,7 @@
         writer.setMetric(doubleMetric, 1.5);
         checker.check(0, [Test(doubleMetric, 1.5)]);
         writer.deleteEntity(doubleMetric);
-        checker.check(-2, [Test(writer.rootNode, 0)]);
+        checker.check(-2, []);
       });
 
       test('make, modify, and free Property', () {
@@ -408,17 +384,14 @@
         final checker = Checker(vmo)..check(0, []);
 
         final property = writer.createProperty(writer.rootNode, 'prop');
-        checker.check(2, [
-          Test(_nameFor(vmo, property), toByteData('prop')),
-          Test(writer.rootNode, 1)
-        ]);
+        checker.check(2, [Test(_nameFor(vmo, property), toByteData('prop'))]);
         final bytes = ByteData(8)..setFloat64(0, 1.23);
         writer.setProperty(property, bytes);
         checker.check(1, [Test(_extentFor(vmo, property), bytes)]);
         writer.deleteEntity(property);
         // Property, its extent, and its name should be freed. Its parent should
         // have one fewer children (0 in this case).
-        checker.check(-3, [Test(writer.rootNode, 0)]);
+        checker.check(-3, []);
       });
 
       test('Node delete permutations', () {
@@ -426,9 +399,9 @@
         final writer = createWriter(vmo);
         final checker = Checker(vmo)..check(0, []);
         final parent = writer.createNode(writer.rootNode, 'parent');
-        checker.check(2, [Test(writer.rootNode, 1)]);
+        checker.check(2, []);
         final child = writer.createNode(parent, 'child');
-        checker.check(2, [Test(writer.rootNode, 1), Test(parent, 1)]);
+        checker.check(2, [Test(parent, 1)]);
         final metric = writer.createMetric(child, 'metric', 1);
         checker.check(2, [Test(child, 1), Test(parent, 1)]);
         writer.deleteEntity(child);
@@ -436,7 +409,7 @@
         checker.check(-1, [Test(child, 1), Test(parent, 0)]);
         writer.deleteEntity(parent);
         // Parent, plus its name, should be freed; root should have no children.
-        checker.check(-2, [Test(writer.rootNode, 0)]);
+        checker.check(-2, []);
         writer.deleteEntity(metric);
         // Metric, its name, and child should be freed.
         checker.check(-3, []);
@@ -445,8 +418,7 @@
             writer.createMetric(writer.rootNode, 'newIntMetric', 42);
         checker.check(2, [
           Test(_nameFor(vmo, newMetric), toByteData('newIntMetric')),
-          Test(newMetric, 42),
-          Test(writer.rootNode, 1)
+          Test(newMetric, 42)
         ]);
       });