[gold] Make the Keys field unexported, replace with function.

This is a precursor to having options be seperate from
normal keys on a Trace.

Also remove .Trim() from Tile and Trace which appears
unused (outside a test or two)

Change-Id: Id00483ca28e658088d7fa8115125d0db7a4c6a16
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/304796
Reviewed-by: Leandro Lovisolo <lovisolo@google.com>
diff --git a/golden/cmd/trace_tool/trace_tool.go b/golden/cmd/trace_tool/trace_tool.go
index 345e60a..a108ab5 100644
--- a/golden/cmd/trace_tool/trace_tool.go
+++ b/golden/cmd/trace_tool/trace_tool.go
@@ -201,7 +201,7 @@
 		sklog.Fatalf("Could not get traces: %s", err)
 	}
 	for id, trace := range traceMap {
-		if trace.Keys["extra_config"] == "Direct3D" && trace.Keys["cpu_or_gpu_value"] == "RadeonHD7770" {
+		if trace.Keys()["extra_config"] == "Direct3D" && trace.Keys()["cpu_or_gpu_value"] == "RadeonHD7770" {
 			sklog.Infof("trace %s has digests %q", id, trace.Digests)
 		}
 	}
diff --git a/golden/go/blame/blame_test.go b/golden/go/blame/blame_test.go
index c6aecf3..63f32b8 100644
--- a/golden/go/blame/blame_test.go
+++ b/golden/go/blame/blame_test.go
@@ -182,17 +182,15 @@
 
 	tile := bug_revert.MakeTestTile()
 
-	tile.Traces[",device=alpha,name=test_one,source_type=gm,"] = &tiling.Trace{
-		Digests: types.DigestSlice{
+	tile.Traces[",device=alpha,name=test_one,source_type=gm,"] = tiling.NewTrace(
+		[]types.Digest{
 			bug_revert.AlfaPositiveDigest, bug_revert.AlfaPositiveDigest, bug_revert.BravoUntriagedDigest,
 			bug_revert.AlfaPositiveDigest, bug_revert.AlfaPositiveDigest,
-		},
-		Keys: map[string]string{
+		}, map[string]string{
 			"device":              bug_revert.AlphaDevice,
 			types.PrimaryKeyField: string(bug_revert.TestOne),
 			types.CorpusField:     "gm",
-		},
-	}
+		})
 
 	blamer, err := New(tile, bug_revert.MakeTestExpectations())
 	require.NoError(t, err)
diff --git a/golden/go/digest_counter/digest_counter_test.go b/golden/go/digest_counter/digest_counter_test.go
index 59460a6..ceb598d 100644
--- a/golden/go/digest_counter/digest_counter_test.go
+++ b/golden/go/digest_counter/digest_counter_test.go
@@ -131,22 +131,20 @@
 	return &tiling.Tile{
 		// Commits, Scale and Tile Index omitted (should not affect things)
 		Traces: map[tiling.TraceID]*tiling.Trace{
-			x86TestAlphaTraceID: {
-				Digests: types.DigestSlice{FirstDigest, FirstDigest, SecondDigest},
-				Keys: map[string]string{
+			x86TestAlphaTraceID: tiling.NewTrace(
+				[]types.Digest{FirstDigest, FirstDigest, SecondDigest},
+				map[string]string{
 					"config":              "x86",
 					types.PrimaryKeyField: string(AlphaTest),
 					types.CorpusField:     "gm",
-				},
-			},
-			x64TestAlphaTraceID: {
-				Digests: types.DigestSlice{ThirdDigest, FirstDigest, tiling.MissingDigest},
-				Keys: map[string]string{
+				}),
+			x64TestAlphaTraceID: tiling.NewTrace(
+				[]types.Digest{ThirdDigest, FirstDigest, tiling.MissingDigest},
+				map[string]string{
 					"config":              "x86_64",
 					types.PrimaryKeyField: string(AlphaTest),
 					types.CorpusField:     "image",
-				},
-			},
+				}),
 		},
 	}
 }
diff --git a/golden/go/paramsets/paramsets.go b/golden/go/paramsets/paramsets.go
index 6a4f247..ddda6e0 100644
--- a/golden/go/paramsets/paramsets.go
+++ b/golden/go/paramsets/paramsets.go
@@ -30,16 +30,16 @@
 
 	for id, dc := range digestCountsByTrace {
 		if tr, ok := tile.Traces[id]; ok {
-			test := types.TestName(tr.Params()[types.PrimaryKeyField])
+			test := types.TestName(tr.Keys()[types.PrimaryKeyField])
 			for digest := range dc {
 				if foundTest, ok := ret[test]; !ok {
 					ret[test] = map[types.Digest]paramtools.ParamSet{
-						digest: paramtools.NewParamSet(tr.Params()),
+						digest: paramtools.NewParamSet(tr.Keys()),
 					}
 				} else if foundDigest, ok := foundTest[digest]; !ok {
-					foundTest[digest] = paramtools.NewParamSet(tr.Params())
+					foundTest[digest] = paramtools.NewParamSet(tr.Keys())
 				} else {
-					foundDigest.AddParams(tr.Params())
+					foundDigest.AddParams(tr.Keys())
 				}
 			}
 		}
diff --git a/golden/go/paramsets/paramsets_test.go b/golden/go/paramsets/paramsets_test.go
index 9ffd3dd..81339ac 100644
--- a/golden/go/paramsets/paramsets_test.go
+++ b/golden/go/paramsets/paramsets_test.go
@@ -159,46 +159,41 @@
 		Traces: map[tiling.TraceID]*tiling.Trace{
 			// These trace ids have been shortened for test terseness.
 			// A real trace id would be like ",config=8888,source_type=gm,name=foo,"
-			"a": {
-				Digests: types.DigestSlice{DigestA, DigestB},
-				Keys: map[string]string{
+			"a": tiling.NewTrace(
+				[]types.Digest{DigestA, DigestB},
+				map[string]string{
 					"config":              "8888",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(testOne),
-				},
-			},
-			"b": {
-				Digests: types.DigestSlice{DigestC, DigestD, DigestA},
-				Keys: map[string]string{
+				}),
+			"b": tiling.NewTrace(
+				[]types.Digest{DigestC, DigestD, DigestA},
+				map[string]string{
 					"config":              "565",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(testOne),
-				},
-			},
-			"c": {
-				Digests: types.DigestSlice{DigestE, tiling.MissingDigest},
-				Keys: map[string]string{
+				}),
+			"c": tiling.NewTrace(
+				[]types.Digest{DigestE, tiling.MissingDigest},
+				map[string]string{
 					"config":              "gpu",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(testOne),
-				},
-			},
-			"e": {
-				Digests: types.DigestSlice{DigestF, DigestG, DigestG},
-				Keys: map[string]string{
+				}),
+			"e": tiling.NewTrace(
+				[]types.Digest{DigestF, DigestG, DigestG},
+				map[string]string{
 					"config":              "565",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(testTwo),
-				},
-			},
-			"f": {
-				Digests: types.DigestSlice{DigestF, tiling.MissingDigest},
-				Keys: map[string]string{
+				}),
+			"f": tiling.NewTrace(
+				[]types.Digest{DigestF, tiling.MissingDigest},
+				map[string]string{
 					"config":              "gpu",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(testTwo),
-				},
-			},
+				}),
 		},
 	}
 }
diff --git a/golden/go/search/search.go b/golden/go/search/search.go
index 3037355..5bfa780 100644
--- a/golden/go/search/search.go
+++ b/golden/go/search/search.go
@@ -264,11 +264,11 @@
 				continue
 			}
 			if _, ok := byTrace[traceID][digest]; ok {
-				result.ParamSet.AddParams(trace.Params())
+				result.ParamSet.AddParams(trace.Keys())
 				result.TraceGroup.Traces = append(result.TraceGroup.Traces, frontend.Trace{
 					ID:       traceID,
 					RawTrace: trace,
-					Params:   trace.Params(),
+					Params:   trace.Keys(),
 				})
 			}
 		}
@@ -417,7 +417,7 @@
 			existing.TraceGroup.Traces = append(existing.TraceGroup.Traces, frontend.Trace{
 				ID:       tp.ID,
 				RawTrace: tp.Trace,
-				Params:   tp.Trace.Params(),
+				Params:   tp.Trace.Keys(),
 			})
 		}
 	}
@@ -678,14 +678,14 @@
 			}
 			resultsByGroupingAndDigest[key] = existing
 		}
-		existing.ParamSet.AddParams(trace.Params())
+		existing.ParamSet.AddParams(trace.Keys())
 		// It is tempting to think we could just convert the RawTrace into the frontend.Trace right
 		// here, but in fact we need all the traces for a given digest (i.e. in a given TraceGroup)
 		// to be able to do that. Specifically, we want to be able to share the digest indices.
 		existing.TraceGroup.Traces = append(existing.TraceGroup.Traces, frontend.Trace{
 			ID:       traceID,
 			RawTrace: trace,
-			Params:   trace.Params(),
+			Params:   trace.Keys(),
 		})
 	}
 
diff --git a/golden/go/search/util.go b/golden/go/search/util.go
index ff489f2..af47525 100644
--- a/golden/go/search/util.go
+++ b/golden/go/search/util.go
@@ -58,7 +58,7 @@
 			id, trace := tp.ID, tp.Trace
 			// Check if the query matches.
 			if trace.Matches(q.TraceValues) {
-				params := trace.Params()
+				params := trace.Keys()
 				reducedTr := traceView(trace)
 				digests := digestsFromTrace(id, reducedTr, q.OnlyIncludeDigestsProducedAtHead, digestCountsByTrace)
 
@@ -135,7 +135,7 @@
 	}
 
 	ret := func(trace *tiling.Trace) *tiling.Trace {
-		return tiling.NewTrace(trace.Digests[startIdx:endIdx], trace.Params())
+		return tiling.NewTrace(trace.Digests[startIdx:endIdx], trace.Keys())
 	}
 	return ret, nil
 }
diff --git a/golden/go/search/util_test.go b/golden/go/search/util_test.go
index 5304b43..780ef17 100644
--- a/golden/go/search/util_test.go
+++ b/golden/go/search/util_test.go
@@ -105,7 +105,7 @@
 		// Run through all the traces and make sure they are properly trimmed
 		for _, trace := range data.MakeTestTile().Traces {
 			reducedTr := fn(trace)
-			assert.Equal(t, trace.Digests[tc.trimmedStartIndex:tc.trimmedEndIndex+1], reducedTr.Digests, "test case %s with trace %v", tc.name, trace.Keys)
+			assert.Equal(t, trace.Digests[tc.trimmedStartIndex:tc.trimmedEndIndex+1], reducedTr.Digests, "test case %s with trace %v", tc.name, trace.Keys())
 		}
 	}
 }
diff --git a/golden/go/summary/summary_test.go b/golden/go/summary/summary_test.go
index 89eb0f4..5280597 100644
--- a/golden/go/summary/summary_test.go
+++ b/golden/go/summary/summary_test.go
@@ -584,46 +584,41 @@
 		Traces: map[tiling.TraceID]*tiling.Trace{
 			// These trace ids have been shortened for test terseness.
 			// A real trace id would be like "8888:gm:test_first"
-			"a": {
-				Digests: types.DigestSlice{"aaa", "bbb"},
-				Keys: map[string]string{
+			"a": tiling.NewTrace(
+				[]types.Digest{"aaa", "bbb"},
+				map[string]string{
 					"config":              "8888",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(FirstTest),
-				},
-			},
-			"b": {
-				Digests: types.DigestSlice{"ccc", "ddd"},
-				Keys: map[string]string{
+				}),
+			"b": tiling.NewTrace(
+				[]types.Digest{"ccc", "ddd"},
+				map[string]string{
 					"config":              "565",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(FirstTest),
-				},
-			},
-			"c": {
-				Digests: types.DigestSlice{"eee", tiling.MissingDigest},
-				Keys: map[string]string{
+				}),
+			"c": tiling.NewTrace(
+				[]types.Digest{"eee", tiling.MissingDigest},
+				map[string]string{
 					"config":              "gpu",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(FirstTest),
-				},
-			},
-			"d": {
-				Digests: types.DigestSlice{"fff", "ggg"},
-				Keys: map[string]string{
+				}),
+			"d": tiling.NewTrace(
+				[]types.Digest{"fff", "ggg"},
+				map[string]string{
 					"config":              "8888",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(SecondTest),
-				},
-			},
-			"e": {
-				Digests: types.DigestSlice{"jjj", tiling.MissingDigest},
-				Keys: map[string]string{
+				}),
+			"e": tiling.NewTrace(
+				[]types.Digest{"jjj", tiling.MissingDigest},
+				map[string]string{
 					"config":              "8888",
 					types.CorpusField:     "image",
 					types.PrimaryKeyField: string(ThirdTest),
-				},
-			},
+				}),
 		},
 		Commits: []tiling.Commit{
 			{
@@ -647,38 +642,34 @@
 		Traces: map[tiling.TraceID]*tiling.Trace{
 			// These trace ids have been shortened for test terseness.
 			// A real trace id would be like "8888:gm:test_first"
-			"a": {
-				Digests: types.DigestSlice{"aaa", "bbb"},
-				Keys: map[string]string{
+			"a": tiling.NewTrace(
+				[]types.Digest{"aaa", "bbb"},
+				map[string]string{
 					"config":              "8888",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(FirstTest),
-				},
-			},
-			"c": {
-				Digests: types.DigestSlice{"eee", tiling.MissingDigest},
-				Keys: map[string]string{
+				}),
+			"c": tiling.NewTrace(
+				[]types.Digest{"eee", tiling.MissingDigest},
+				map[string]string{
 					"config":              "gpu",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(FirstTest),
-				},
-			},
-			"d": {
-				Digests: types.DigestSlice{"fff", "ggg"},
-				Keys: map[string]string{
+				}),
+			"d": tiling.NewTrace(
+				[]types.Digest{"fff", "ggg"},
+				map[string]string{
 					"config":              "8888",
 					types.CorpusField:     "gm",
 					types.PrimaryKeyField: string(SecondTest),
-				},
-			},
-			"e": {
-				Digests: types.DigestSlice{"jjj", tiling.MissingDigest},
-				Keys: map[string]string{
+				}),
+			"e": tiling.NewTrace(
+				[]types.Digest{"jjj", tiling.MissingDigest},
+				map[string]string{
 					"config":              "8888",
 					types.CorpusField:     "image",
 					types.PrimaryKeyField: string(ThirdTest),
-				},
-			},
+				}),
 		},
 		Commits: []tiling.Commit{
 			{
diff --git a/golden/go/tilesource/tilesource.go b/golden/go/tilesource/tilesource.go
index 04186b1..fc20485 100644
--- a/golden/go/tilesource/tilesource.go
+++ b/golden/go/tilesource/tilesource.go
@@ -153,9 +153,9 @@
 	// Build the paramset in the process.
 	paramSet := paramtools.ParamSet{}
 	for traceID, trace := range tile.Traces {
-		if s.PubliclyViewableParams.Matches(trace.Params()) {
+		if s.PubliclyViewableParams.Matches(trace.Keys()) {
 			ret.Traces[traceID] = trace
-			paramSet.AddParams(trace.Params())
+			paramSet.AddParams(trace.Keys())
 		}
 	}
 	paramSet.Normalize()
diff --git a/golden/go/tiling/tiling.go b/golden/go/tiling/tiling.go
index 500b34e..a25eeb8 100644
--- a/golden/go/tiling/tiling.go
+++ b/golden/go/tiling/tiling.go
@@ -3,7 +3,6 @@
 import (
 	"time"
 
-	"go.skia.org/infra/go/skerr"
 	"go.skia.org/infra/golden/go/types"
 )
 
@@ -40,34 +39,6 @@
 	return 0
 }
 
-// Trim trims the measurements to just the range from [begin, end).
-//
-// Just like a Go [:] slice this is inclusive of begin and exclusive of end.
-// The length on the Traces will then become end-begin.
-func (t *Tile) Trim(begin, end int) (*Tile, error) {
-	length := end - begin
-	if end < begin || end > len(t.Commits) || begin < 0 {
-		return nil, skerr.Fmt("Invalid Trim range [%d, %d) of [0, %d]", begin, end, length)
-	}
-	ret := &Tile{
-		Traces:   map[TraceID]*Trace{},
-		ParamSet: t.ParamSet,
-		Commits:  make([]Commit, length),
-	}
-
-	for i := 0; i < length; i++ {
-		ret.Commits[i] = t.Commits[i+begin]
-	}
-	for k, v := range t.Traces {
-		t := v.DeepCopy()
-		if err := t.Trim(begin, end); err != nil {
-			return nil, skerr.Wrapf(err, "trimming trace %s", k)
-		}
-		ret.Traces[k] = t
-	}
-	return ret, nil
-}
-
 const (
 	// MissingDigest is a sentinel value meaning no digest is available at the given commit.
 	MissingDigest = types.Digest("")
diff --git a/golden/go/tiling/trace.go b/golden/go/tiling/trace.go
index db99a88..433fbc0 100644
--- a/golden/go/tiling/trace.go
+++ b/golden/go/tiling/trace.go
@@ -14,10 +14,15 @@
 // Trace represents all the Digests of a single test across a series
 // of Commits.
 type Trace struct {
-	// The JSON keys are named this way to maintain backwards compatibility
-	// with JSON already written to disk.
-	Keys    map[string]string `json:"Params_"`
-	Digests []types.Digest    `json:"Values"`
+	// Digests represents the images seen over the last N commits. Index 0 is the oldest data, index
+	// len-1 is the newest data.
+	Digests []types.Digest
+	// Keys describe how the digest was produced. These keys and values contribute to the trace id
+	// (that is, they contribute to uniqueness).
+	keys map[string]string
+	// Options describe other parameters. These do not contribute to the trace id, but are searchable.
+	// TODO(kjlubick)
+	// Options map[string]string
 
 	// cache these values so as not to incur the non-zero map lookup cost (~15 ns) repeatedly.
 	testName types.TestName
@@ -31,7 +36,7 @@
 func NewEmptyTrace(numDigests int, keys map[string]string) *Trace {
 	g := &Trace{
 		Digests: make([]types.Digest, numDigests),
-		Keys:    keys,
+		keys:    keys,
 
 		// Prefetch these now, while we have the chance.
 		testName: types.TestName(keys[types.PrimaryKeyField]),
@@ -47,7 +52,7 @@
 func NewTrace(digests []types.Digest, keys map[string]string) *Trace {
 	return &Trace{
 		Digests: digests,
-		Keys:    keys,
+		keys:    keys,
 
 		// Prefetch these now, while we have the chance.
 		testName: types.TestName(keys[types.PrimaryKeyField]),
@@ -55,15 +60,15 @@
 	}
 }
 
-// Params implements the tiling.Trace interface.
-func (g *Trace) Params() map[string]string {
-	return g.Keys
+// Keys returns the key value pairs associated with this trace.
+func (g *Trace) Keys() map[string]string {
+	return g.keys
 }
 
 // Matches returns true if the given Trace matches the given query.
 func (g *Trace) Matches(query paramtools.ParamSet) bool {
 	for k, values := range query {
-		if p, ok := g.Params()[k]; !ok || !util.In(p, values) {
+		if p, ok := g.Keys()[k]; !ok || !util.In(p, values) {
 			return false
 		}
 	}
@@ -74,7 +79,7 @@
 // trace, of which there should always be exactly one.
 func (g *Trace) TestName() types.TestName {
 	if g.testName == "" {
-		g.testName = types.TestName(g.Keys[types.PrimaryKeyField])
+		g.testName = types.TestName(g.keys[types.PrimaryKeyField])
 	}
 	return g.testName
 }
@@ -83,7 +88,7 @@
 // trace, of which there should always be exactly one.
 func (g *Trace) Corpus() string {
 	if g.corpus == "" {
-		g.corpus = g.Keys[types.CorpusField]
+		g.corpus = g.keys[types.CorpusField]
 	}
 	return g.corpus
 }
@@ -98,25 +103,14 @@
 	return g.Digests[i] == MissingDigest
 }
 
-// DeepCopy implements the tiling.Trace interface.
-func (g *Trace) DeepCopy() *Trace {
-	nd := make([]types.Digest, len(g.Digests))
-	copy(nd, g.Digests)
-	nk := make(map[string]string, len(g.Keys))
-	for k, v := range g.Keys {
-		nk[k] = v
-	}
-	return NewTrace(nd, nk)
-}
-
 // Merge implements the tiling.Trace interface.
 func (g *Trace) Merge(next *Trace) *Trace {
 	n := len(g.Digests) + len(next.Digests)
 	n1 := len(g.Digests)
 
-	merged := NewEmptyTrace(n, g.Keys)
-	for k, v := range next.Keys {
-		merged.Keys[k] = v
+	merged := NewEmptyTrace(n, g.keys)
+	for k, v := range next.keys {
+		merged.keys[k] = v
 	}
 	copy(merged.Digests, g.Digests)
 
@@ -156,21 +150,6 @@
 	g.Digests = newDigests
 }
 
-// Trim implements the tiling.Trace interface.
-func (g *Trace) Trim(begin, end int) error {
-	if end < begin || end > g.Len() || begin < 0 {
-		return fmt.Errorf("Invalid Trim range [%d, %d) of [0, %d]", begin, end, g.Len())
-	}
-	n := end - begin
-	newDigests := make([]types.Digest, n)
-
-	for i := 0; i < n; i++ {
-		newDigests[i] = g.Digests[i+begin]
-	}
-	g.Digests = newDigests
-	return nil
-}
-
 // AtHead returns the last digest in the trace (HEAD) or the empty string otherwise.
 func (g *Trace) AtHead() types.Digest {
 	if idx := g.LastIndex(); idx >= 0 {
@@ -192,7 +171,7 @@
 
 // String prints a human friendly version of this trace.
 func (g *Trace) String() string {
-	return fmt.Sprintf("Keys: %#v, Digests: %q", g.Keys, g.Digests)
+	return fmt.Sprintf("Keys: %#v, Digests: %q", g.keys, g.Digests)
 }
 
 // TraceIDFromParams deterministically returns a TraceID that uniquely encodes
diff --git a/golden/go/tiling/trace_test.go b/golden/go/tiling/trace_test.go
index 8f57b36..c191f87 100644
--- a/golden/go/tiling/trace_test.go
+++ b/golden/go/tiling/trace_test.go
@@ -16,7 +16,7 @@
 	// Test NewTrace.
 	g := NewEmptyTrace(N, nil)
 	assert.Equal(t, N, g.Len(), "wrong digests size")
-	assert.Equal(t, 0, len(g.Keys), "wrong keys initial size")
+	assert.Equal(t, 0, len(g.keys), "wrong keys initial size")
 	g.Digests[0] = "a digest"
 
 	assert.True(t, g.IsMissing(1), "values start missing")
@@ -55,23 +55,6 @@
 	assert.Equal(t, types.Digest("foo"), g.Digests[0], "Grow didn't FillAfter correctly")
 }
 
-func TestTrace_Trim(t *testing.T) {
-	unittest.SmallTest(t)
-	const N = 5
-	g := NewEmptyTrace(N, nil)
-	g.Digests[1] = "foo"
-	require.NoError(t, g.Trim(1, 3))
-	assert.Equal(t, types.Digest("foo"), g.Digests[0], "Trim didn't copy correctly")
-	assert.Equal(t, 2, g.Len(), "Trim wrong length")
-
-	assert.Error(t, g.Trim(-1, 1))
-	assert.Error(t, g.Trim(1, 3))
-	assert.Error(t, g.Trim(2, 1))
-
-	require.NoError(t, g.Trim(1, 1))
-	assert.Equal(t, 0, g.Len(), "final size wrong")
-}
-
 func TestTraceIDFromParams_ValidKeysAndValues_Success(t *testing.T) {
 	unittest.SmallTest(t)
 
diff --git a/golden/go/tracestore/bt_tracestore/bt_tracestore_test.go b/golden/go/tracestore/bt_tracestore/bt_tracestore_test.go
index 7d1a083..930635b 100644
--- a/golden/go/tracestore/bt_tracestore/bt_tracestore_test.go
+++ b/golden/go/tracestore/bt_tracestore/bt_tracestore_test.go
@@ -73,7 +73,7 @@
 	for id, traceA := range a.Traces {
 		assert.Contains(t, b.Traces, id)
 		traceB := b.Traces[id]
-		assert.Equal(t, traceA.Keys, traceB.Keys)
+		assert.Equal(t, traceA.Keys(), traceB.Keys())
 		assert.Equal(t, traceA.Digests, traceB.Digests)
 	}
 }
@@ -93,7 +93,7 @@
 			}
 			e := tracestore.Entry{
 				Digest: trace.Digests[i],
-				Params: trace.Keys,
+				Params: trace.Keys(),
 			}
 			if options {
 				if i == 0 {
@@ -134,7 +134,7 @@
 	require.NoError(t, err)
 	putTestTile(t, traceStore, commits, false /*=options*/)
 
-	alphaParams := data.MakeTestTile().Traces[data.AnglerAlphaTraceID].Params()
+	alphaParams := data.MakeTestTile().Traces[data.AnglerAlphaTraceID].Keys()
 	require.NotEmpty(t, alphaParams)
 
 	veryOldDigest := types.Digest("00069e4bb9c71ba0f7e2c7e03bf96699")
@@ -327,7 +327,7 @@
 	}
 	for _, trace := range traces {
 		require.Len(t, trace.Digests, len(commits), "test data should have one digest per commit")
-		dev := trace.Keys["device"]
+		dev := trace.Keys()["device"]
 		byDevice[dev] = append(byDevice[dev], trace)
 	}
 	require.Len(t, byDevice, 3, "test data should have exactly 3 devices")
@@ -341,7 +341,7 @@
 			for _, gTrace := range gTraces {
 				entries = append(entries, &tracestore.Entry{
 					Digest: gTrace.Digests[i],
-					Params: gTrace.Keys,
+					Params: gTrace.Keys(),
 				})
 			}
 
@@ -408,7 +408,7 @@
 				defer wg.Done()
 				e := tracestore.Entry{
 					Digest: trace.Digests[i],
-					Params: trace.Keys,
+					Params: trace.Keys(),
 				}
 				err := traceStore.Put(ctx, commits[i].Hash, []*tracestore.Entry{&e}, now)
 				require.NoError(t, err)
@@ -493,9 +493,7 @@
 	realCommitIndices = []int{501, 557}
 	totalCommits = 1101
 	mvcs, lCommits = mockSparseVCSWithCommits(commits, realCommitIndices, totalCommits)
-	expectedTile = data.MakeTestTile()
-	expectedTile, err := expectedTile.Trim(1, 3)
-	require.NoError(t, err)
+	expectedTile = makeTrimmedTile()
 	testDenseTile(t, expectedTile, mvcs, commits, lCommits, realCommitIndices)
 
 	// All commits are on the first commit of their tile
@@ -523,6 +521,72 @@
 	testDenseTile(t, expectedTile, mvcs, commits, lCommits, realCommitIndices)
 }
 
+func makeTrimmedTile() *tiling.Tile {
+	return &tiling.Tile{
+		Commits: data.MakeTestCommits(),
+		Traces: map[tiling.TraceID]*tiling.Trace{
+			data.AnglerAlphaTraceID: tiling.NewTrace(
+				types.DigestSlice{data.AlphaNegativeDigest, data.AlphaPositiveDigest},
+				map[string]string{
+					"device":              data.AnglerDevice,
+					types.PrimaryKeyField: string(data.AlphaTest),
+					types.CorpusField:     data.GMCorpus,
+				},
+			),
+			data.AnglerBetaTraceID: tiling.NewTrace(
+				types.DigestSlice{data.BetaPositiveDigest, data.BetaPositiveDigest},
+				map[string]string{
+					"device":              data.AnglerDevice,
+					types.PrimaryKeyField: string(data.BetaTest),
+					types.CorpusField:     data.GMCorpus,
+				},
+			),
+
+			data.BullheadAlphaTraceID: tiling.NewTrace(
+				types.DigestSlice{data.AlphaNegativeDigest, data.AlphaUntriagedDigest},
+				map[string]string{
+					"device":              data.BullheadDevice,
+					types.PrimaryKeyField: string(data.AlphaTest),
+					types.CorpusField:     data.GMCorpus,
+				},
+			),
+			data.BullheadBetaTraceID: tiling.NewTrace(
+				types.DigestSlice{data.BetaPositiveDigest, data.BetaPositiveDigest},
+				map[string]string{
+					"device":              data.BullheadDevice,
+					types.PrimaryKeyField: string(data.BetaTest),
+					types.CorpusField:     data.GMCorpus,
+				},
+			),
+
+			data.CrosshatchAlphaTraceID: tiling.NewTrace(
+				types.DigestSlice{data.AlphaNegativeDigest, data.AlphaPositiveDigest},
+				map[string]string{
+					"device":              data.CrosshatchDevice,
+					types.PrimaryKeyField: string(data.AlphaTest),
+					types.CorpusField:     data.GMCorpus,
+				},
+			),
+			data.CrosshatchBetaTraceID: tiling.NewTrace(
+				types.DigestSlice{tiling.MissingDigest, tiling.MissingDigest},
+				map[string]string{
+					"device":              data.CrosshatchDevice,
+					types.PrimaryKeyField: string(data.BetaTest),
+					types.CorpusField:     data.GMCorpus,
+				},
+			),
+		},
+
+		// Summarizes all the keys and values seen in this tile
+		// The values should be in alphabetical order (see paramset.Normalize())
+		ParamSet: map[string][]string{
+			"device":              {data.AnglerDevice, data.BullheadDevice, data.CrosshatchDevice},
+			types.PrimaryKeyField: {string(data.AlphaTest), string(data.BetaTest)},
+			types.CorpusField:     {data.GMCorpus},
+		},
+	}
+}
+
 // testDenseTile takes the data from tile, Puts it into BT, then pulls the tile given
 // the commit layout in VCS and returns it.
 func testDenseTile(t *testing.T, tile *tiling.Tile, mvcs *mock_vcs.VCS, commits []tiling.Commit, lCommits []*vcsinfo.LongCommit, realCommitIndices []int) {
@@ -552,7 +616,7 @@
 		for i := len(trace.Digests) - 1; i >= 0; i-- {
 			e := tracestore.Entry{
 				Digest: trace.Digests[i],
-				Params: trace.Keys,
+				Params: trace.Keys(),
 			}
 			err := traceStore.Put(ctx, commits[i].Hash, []*tracestore.Entry{&e}, now)
 			require.NoError(t, err)
@@ -933,11 +997,11 @@
 		// optionsOne applied.
 		if id == data.CrosshatchBetaTraceID {
 			for k, v := range makeOptionsOne() {
-				trace.Keys[k] = v
+				trace.Keys()[k] = v
 			}
 		} else {
 			for k, v := range makeOptionsTwo() {
-				trace.Keys[k] = v
+				trace.Keys()[k] = v
 			}
 		}
 		tile.Traces[id] = trace
diff --git a/golden/go/tracestore/bt_tracestore/types.go b/golden/go/tracestore/bt_tracestore/types.go
index 6bea097..0084598 100644
--- a/golden/go/tracestore/bt_tracestore/types.go
+++ b/golden/go/tracestore/bt_tracestore/types.go
@@ -241,7 +241,7 @@
 			newDigests[i] = trace.Digests[idx]
 		}
 
-		r[id] = tiling.NewTrace(newDigests, trace.Keys)
+		r[id] = tiling.NewTrace(newDigests, trace.Keys())
 	}
 	return r
 }
diff --git a/golden/go/web/web_test.go b/golden/go/web/web_test.go
index eb44fcf..9c9fd41 100644
--- a/golden/go/web/web_test.go
+++ b/golden/go/web/web_test.go
@@ -234,11 +234,12 @@
 // real objects work correctly, so we should feel safe to use them here.
 func makeBugRevertIndex(endIndex int) *indexer.SearchIndex {
 	tile := bug_revert.MakeTestTile()
-	// Trim is [start, end)
-	tile, err := tile.Trim(0, endIndex)
-	if err != nil {
-		panic(err) // this means our static data is horribly broken
+
+	// Trim down the traces to end sooner (to make the data "more interesting")
+	for _, trace := range tile.Traces {
+		trace.Digests = trace.Digests[:endIndex]
 	}
+	tile.Commits = tile.Commits[:endIndex]
 
 	cpxTile := tiling.NewComplexTile(tile)
 	dc := digest_counter.New(tile)