Code

The harness and the tests

Three files: the harness, the tests, and two new commands.

command what it does
algo top the best k: heap against "sort and take"
algo pq lesson 6's question: your heap against container/heap

heapbench.go also carries stdItems — the interface container/heap demands. Look at its signatures now; in step 6 they are the entire answer:

func (s *stdItems) Push(x any)  { *s = append(*s, x.(Item)) }
func (s *stdItems) Pop() any    { ... }

The tests

test what it requires
TestPopComesOutAscending the invariant holds after every Push; draining gives ascending order
TestHeightIsImpliedByLength Height() is floor(log2 n)+1 for every n up to 5,000
TestTheHeapIsNotSorted the array is NOT sorted — and is still a heap
TestTopKAgreesWithSortingAndCostsLess the same k ratings, in under 2n comparisons
TestTopKLosesWhenKApproachesN at k = n the heap loses to sorting

Two of them demand that something is not the case, and both protect the point of the lesson.

"Not sorted" guards against an improvement that would ruin everything. Turn Push into an insertion sort and every other test still passes, while the cost goes from O(log n) to O(n). A heap does not sort — that is not a shortcoming, it is exactly what it sells in exchange for the speed.

"Loses at k = n" is the honest boundary. The heap wins only while k is well under n; step 5 measures where it turns over. The test stops that being quietly left out.

The test file also carries four Benchmarks — step 6 needs them, because what it measures is something the counter cannot see:

go test -run XXX -bench 'Heap|TopK' -benchtime=20x -count=5