veyron2/naming: rename and rationalise routines for 'terminal' names.

Replaced the 'Fixed' family of functions with ones with more meaningful
names: MakeTerminal, MakeResolveable, a test for a terminal name,
Terminal and a test for Validity. These are designed to be more composable
than the functions they replace, allbeit at the cost of in some cases asking
the caller to invoke them in combination. If these combinations turn out to be
required in user code then utility routines can easily be added.
Remove functions that are called only once (Depth) or never (StripSuffix).

Improved the documentation to better explain terminal and non-terminal
(i.e. resolveable) names.

Improved the unit tests to hopefully make them easier to comprehend.

Change-Id: Ied88d1524167b07218f962d645d0875af0f10c30
diff --git a/examples/fortune/fortune/main.go b/examples/fortune/fortune/main.go
index 77ff1e5..2a92eb6 100644
--- a/examples/fortune/fortune/main.go
+++ b/examples/fortune/fortune/main.go
@@ -29,7 +29,7 @@
 
 	// Construct a new stub that binds to serverEndpoint without
 	// using the name service
-	s, err := fortune.BindFortune(naming.JoinAddressNameFixed(*address, "fortune"))
+	s, err := fortune.BindFortune(naming.JoinAddressName(*address, "//fortune"))
 	if err != nil {
 		log.Fatal("error binding to server: ", err)
 	}
diff --git a/examples/unresolve/test_util.go b/examples/unresolve/test_util.go
index 94895f2..9ea4cd5 100644
--- a/examples/unresolve/test_util.go
+++ b/examples/unresolve/test_util.go
@@ -111,7 +111,8 @@
 	}
 	var reply []string
 	for _, s := range servers {
-		reply = append(reply, naming.Join(naming.MakeNotFixed(s), "the/future"))
+		r := naming.MakeResolvable(s)
+		reply = append(reply, naming.Join(r, "the/future"))
 	}
 	return reply, nil
 }
@@ -150,7 +151,8 @@
 	}
 	var reply []string
 	for _, s := range servers {
-		reply = append(reply, naming.Join(naming.MakeNotFixed(s), "fortune"))
+		r := naming.MakeResolvable(s)
+		reply = append(reply, naming.Join(r, "fortune"))
 	}
 	return reply, nil
 }
diff --git a/examples/unresolve/unresolve_test.go b/examples/unresolve/unresolve_test.go
index eeafcb3..f7c2e1a 100644
--- a/examples/unresolve/unresolve_test.go
+++ b/examples/unresolve/unresolve_test.go
@@ -59,6 +59,17 @@
 // mounts itself as "g" under mounttable B, and defines its own UnresolveStep.
 // [ This demonstrates defining UnresolveStep for a service that is not
 // IDL-based. ]
+//
+// The MountTables used here are configured to use an internal prefix (mt)
+// for dispatching RPCs. This means that the client code has to manipulate
+// the names to ensure that resolution is terminated in the appropriate
+// places in the name since the MountTable expects to be invoked as
+// /<address>/mt.METHODS rather than just /<address>.METHODS.
+// In addition, since this test invokes methods directly on the MountTable
+// it needs to use a terminal name to force resolution to stop at the MountTable
+// itself, rather than using the MountTable to resolve the name. In practice,
+// this means that names of the form /<endpoint>//mt/... must be used to
+// invoke methods on the MountTable served on <endpoint>/mt.
 
 func TestHelperProcess(t *testing.T) {
 	blackbox.HelperProcess(t)
@@ -95,10 +106,15 @@
 	if len(aOA) == 0 {
 		t.Fatalf("aOA is empty")
 	}
+	// A's object addess, aOA, is /<address>/mt
 	vlog.Infof("aOA=%v", aOA)
+
 	idA := rt.R().Identity()
 	vlog.Infof("idA=%v", idA)
+
 	// Create mounttable B.
+	// Mounttable B uses A as a root, that is, Publish calls made for
+	// services running in B will appear in A, as mt/<suffix used in publish>
 	b := blackbox.HelperCommand(t, "childMT", "b")
 	defer shutdown(b)
 
@@ -107,8 +123,20 @@
 	b.Cmd.Env = append(b.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("MOUNTTABLE_ROOT=%v", aOA))
 	b.Cmd.Start()
 	b.Expect("ready")
-	bOA := naming.Join(resolveStep(t, naming.MakeFixed(naming.Join(aOA, "b"))), "mt")
+
+	// We want to obtain the name for the MountTable mounted in A as mt/b,
+	// in particular, we want the OA of B's Mounttable service.
+	// We do so by asking Mounttable A to resolve //mt/b using its
+	// ResolveStep method. The name (//mt/b) has to be terminal since we are
+	// invoking a methond on the MountTable rather asking the MountTable to
+	// resolve the name!
+	aAddr, _ := naming.SplitAddressName(aOA)
+	aName := naming.JoinAddressName(aAddr, "//mt/b")
+	bName := resolveStep(t, aName)
+
+	bOA := naming.Join(bName, "mt")
 	vlog.Infof("bOA=%v", bOA)
+	bAddr, _ := naming.SplitAddressName(bOA)
 
 	// Create server C.
 	c := blackbox.HelperCommand(t, "childFortune", "c")
@@ -118,7 +146,7 @@
 	c.Cmd.Env = append(c.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("MOUNTTABLE_ROOT=%v", bOA))
 	c.Cmd.Start()
 	c.Expect("ready")
-	cEP := resolveStep(t, naming.MakeFixed(naming.Join(bOA, "c")))
+	cEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/c"))
 	vlog.Infof("cEP=%v", cEP)
 
 	// Create server D.
@@ -129,7 +157,7 @@
 	d.Cmd.Env = append(d.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("MOUNTTABLE_ROOT=%v", bOA))
 	d.Cmd.Start()
 	d.Expect("ready")
-	dEP := resolveStep(t, naming.MakeFixed(naming.Join(bOA, "d")))
+	dEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/d"))
 	vlog.Infof("dEP=%v", dEP)
 
 	// Create server E.
@@ -140,7 +168,7 @@
 	e.Cmd.Env = append(e.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("MOUNTTABLE_ROOT=%v", bOA))
 	e.Cmd.Start()
 	e.Expect("ready")
-	eEP := resolveStep(t, naming.MakeFixed(naming.Join(bOA, "e1")))
+	eEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/e1"))
 	vlog.Infof("eEP=%v", eEP)
 
 	// Create server F.
@@ -151,7 +179,7 @@
 	f.Cmd.Env = append(f.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("MOUNTTABLE_ROOT=%v", naming.Join(aOA, "b/mt")))
 	f.Cmd.Start()
 	f.Expect("ready")
-	fEP := resolveStep(t, naming.MakeFixed(naming.Join(bOA, "f")))
+	fEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/f"))
 	vlog.Infof("fEP=%v", fEP)
 
 	// Create server G.
@@ -162,7 +190,7 @@
 	g.Cmd.Env = append(g.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("MOUNTTABLE_ROOT=%v", bOA))
 	g.Cmd.Start()
 	g.Expect("ready")
-	gEP := resolveStep(t, naming.MakeFixed(naming.Join(bOA, "g")))
+	gEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/g"))
 	vlog.Infof("gEP=%v", gEP)
 
 	// Check that things resolve correctly.
@@ -171,13 +199,15 @@
 	idFile = testutil.SaveIdentityToFile(testutil.NewBlessedIdentity(idA, "test"))
 	defer os.Remove(idFile)
 	os.Setenv("VEYRON_IDENTITY", idFile)
+
 	r, _ := rt.New(veyron2.MountTableRoots([]string{aOA}))
+
 	resolveCases := []struct {
 		name, resolved string
 	}{
 		{"b/mt/c", cEP},
 		{"b/mt/d", dEP},
-		{"b/mt/I/want/to/know", naming.JoinAddressNameFixed(dEP, "tell/me")},
+		{"b/mt/I/want/to/know", naming.MakeTerminal(naming.Join(dEP, "tell/me"))},
 		{"b/mt/e1", eEP},
 		{"b/mt/e2", eEP},
 		{"b/mt/f", fEP},
@@ -231,10 +261,11 @@
 		}
 
 		// Go up the tree, unresolve another step.
-		if want, got := c.unresStep2, unresolveStep(t, createMTClient(naming.MakeFixed(c.unresStep1))); want != got {
+		if want, got := c.unresStep2, unresolveStep(t, createMTClient(naming.MakeTerminal(c.unresStep1))); want != got {
 			t.Errorf("mt.UnresolveStep expected %q, got %q instead", want, got)
 		}
 	}
+
 	// We handle (E) separately since its UnresolveStep returns two names
 	// instead of one.
 
@@ -256,20 +287,19 @@
 	}
 
 	// Try unresolve step on a random name in B.
-	if want, got := naming.Join(aOA, "b/mt/some/random/name"),
-		unresolveStep(t, createMTClient(naming.MakeFixed(naming.Join(bOA, "some/random/name")))); want != got {
+	if want, got := naming.JoinAddressName(aAddr, "mt/b/mt/some/random/name"),
+		unresolveStep(t, createMTClient(naming.JoinAddressName(bAddr, "//mt/some/random/name"))); want != got {
 		t.Errorf("b.UnresolveStep expected %q, got %q instead", want, got)
 	}
 
 	// Try unresolve step on a random name in A.
-	if unres, err := createMTClient(naming.MakeFixed(naming.Join(aOA, "another/random/name"))).UnresolveStep(); err != nil {
+	if unres, err := createMTClient(naming.JoinAddressName(aAddr, "//mt/another/random/name")).UnresolveStep(); err != nil {
 		t.Errorf("UnresolveStep failed with %v", err)
 	} else if len(unres) > 0 {
 		t.Errorf("b.UnresolveStep expected no results, got %q instead", unres)
 	}
 
 	// Verify that full unresolve works.
-
 	unresolveCases := []struct {
 		name, want string
 	}{
diff --git a/runtimes/google/ipc/publisher.go b/runtimes/google/ipc/publisher.go
index 4ee1dad..18a1f81 100644
--- a/runtimes/google/ipc/publisher.go
+++ b/runtimes/google/ipc/publisher.go
@@ -271,7 +271,7 @@
 			continue
 		}
 		for _, s := range mtServers {
-			ret = append(ret, naming.MakeNotFixed(s))
+			ret = append(ret, naming.MakeResolvable(s))
 		}
 	}
 	return ret
diff --git a/runtimes/google/naming/mounttable/all_test.go b/runtimes/google/naming/mounttable/all_test.go
index 951e79b..4549328 100644
--- a/runtimes/google/naming/mounttable/all_test.go
+++ b/runtimes/google/naming/mounttable/all_test.go
@@ -93,6 +93,26 @@
 	mt5Prefix = "mt5"
 )
 
+func testResolveToMountTable(t *testing.T, mt naming.MountTable, name, want string) {
+	servers, err := mt.ResolveToMountTable(name)
+	if err != nil {
+		boom(t, "Failed to ResolveToMountTable %q: %s", name, err)
+	}
+	if len(servers) != 1 || servers[0] != want {
+		boom(t, "ResolveToMountTable %q returned wrong servers: got %v, want %v", name, servers, want)
+	}
+}
+
+func testResolve(t *testing.T, mt naming.MountTable, name, want string) {
+	servers, err := mt.Resolve(name)
+	if err != nil {
+		boom(t, "Failed to Resolve %q: %s", name, err)
+	}
+	if len(servers) != 1 || servers[0] != want {
+		boom(t, "Resolve %q returned wrong servers: got %v, want %v", name, servers, want)
+	}
+}
+
 func runServer(t *testing.T) (ipc.Server, naming.Endpoint) {
 	// We are also running a server on this runtime using stubs so we must
 	// use rt.Init(). If the server were in a separate address as per usual,
@@ -146,14 +166,17 @@
 }
 
 func TestNamespace(t *testing.T) {
-	// Run a mounttable server
+	// Run a MountTable server, which is serving MountTables on:
+	// /<estr>/{mt1,mt2,mt3,mt4,mt5}
 	server, ep := runServer(t)
 	defer server.Stop()
 
-	estr := naming.JoinAddressNameFixed(ep.String(), "")
+	estr := ep.String()
 
 	// Run a client, creating a new runtime for it and intializing its
-	// mount table roots to point to the server created above.
+	// MountTable root to point to the server created above on /<ep>/mt1.
+	// This means that any relative names mounted using this local MountTable
+	// will appear below mt1.
 	r, err := rt.New(veyron2.MountTableRoots([]string{naming.JoinAddressName(estr, mt1Prefix)}))
 	if err != nil {
 		boom(t, "Failed to create client runtime: %s", err)
@@ -164,7 +187,8 @@
 	ttl := time.Duration(100) * time.Second
 	// Mount using a relative name starting with //.  This means don't walk out of the
 	// namespace's root mount table even if there is already something mounted at mt2.
-	if err := mt.Mount("//mt2", naming.JoinAddressName(estr, mt2Prefix), ttl); err != nil {
+	mt2Name := naming.JoinAddressName(estr, mt2Prefix)
+	if err := mt.Mount("//mt2", mt2Name, ttl); err != nil {
 		boom(t, "Failed to Mount //mt2: %s", err)
 	}
 	// Mount using the relative name not starting with //.  This means walk through mt3
@@ -174,9 +198,32 @@
 	// NB: if we mount two replica mount table servers at the same place in the namespace,
 	// we MUST use the // form or it will try to mount the second inside the first rather
 	// than at the same place as the first.
-	if err := mt.Mount("mt3", naming.JoinAddressName(estr, mt3Prefix), ttl); err != nil {
+	mt3Name := naming.JoinAddressName(estr, mt3Prefix)
+	if err := mt.Mount("mt3", mt3Name, ttl); err != nil {
 		boom(t, "Failed to Mount mt3: %s", err)
 	}
+
+	mt1MT := naming.MakeTerminal(naming.JoinAddressName(estr, mt1Prefix))
+	mt2MT := naming.MakeTerminal(naming.JoinAddressName(estr, naming.Join(mt1Prefix, mt2Prefix)))
+	mt3MT := naming.MakeTerminal(naming.JoinAddressName(estr, naming.Join(mt1Prefix, mt3Prefix)))
+
+	// After the mounts above we have MountTables at /<estr>/mt1{//mt2,//mt3},
+	// with server addresses as per below.
+	testResolveToMountTable(t, mt, "", mt1MT)
+	testResolveToMountTable(t, mt, "mt2", mt2MT)
+	testResolveToMountTable(t, mt, "mt3", mt3MT)
+	testResolveToMountTable(t, mt, "//mt3", naming.JoinAddressName(estr, "//mt1//mt3"))
+
+	// We can resolve to the MountTables using rooted, terminal names
+	// as follows, both mt1 and mt1/{mt2,mt3} are served by the
+	// top-level MountTable
+	testResolve(t, mt, naming.JoinAddressName(estr, "//mt1"), mt1MT)
+	testResolve(t, mt, naming.JoinAddressName(estr, "//mt1/mt2"), mt2MT)
+	testResolve(t, mt, naming.JoinAddressName(estr, "//mt1/mt3"), mt3MT)
+
+	// returns [mt2, mt3]
+	vlog.Infof("GLOB: %s", doGlob(t, mt, "*"))
+
 	// Perform two mounts that have to actually walk through other mount tables.
 	if err := mt.Mount("mt2/mt4", naming.JoinAddressName(estr, mt4Prefix), ttl); err != nil {
 		boom(t, "Failed to Mount mt2/mt4: %s", err)
@@ -184,8 +231,15 @@
 	if err := mt.Mount("mt3/mt4", naming.JoinAddressName(estr, mt4Prefix), ttl); err != nil {
 		boom(t, "Failed to Mount mt3/mt4: %s", err)
 	}
-	// Perform a mount that uses a global name as the mount point rather than one relative
-	// to our namespace's root.
+
+	// After the mounts above we now have /<estr>{/mt1/mt2/mt4,/mt1/mt3/mt4}.
+	testResolveToMountTable(t, mt, "mt2/mt4", naming.JoinAddressName(estr, "//mt2/mt4"))
+	testResolveToMountTable(t, mt, "mt3/mt4", naming.JoinAddressName(estr, "//mt3/mt4"))
+
+	testResolve(t, mt, naming.JoinAddressName(estr, "//mt1/mt2/mt4"), naming.JoinAddressName(estr, "//mt1/mt2/mt4"))
+
+	// Perform a mount that uses a global name as the mount point rather than
+	// one relative to our namespace's root.
 	global := naming.JoinAddressName(estr, "mt3/mt4/mt5")
 	if err := mt.Mount(global, naming.JoinAddressName(estr, mt5Prefix), ttl); err != nil {
 		boom(t, "Failed to Mount %s: %s", global, err)
@@ -196,14 +250,18 @@
 		boom(t, "Failed to Mount joke1: %s", err)
 	}
 	// This mounts the raw server endpoint as joke2 -- like Publish would.
-	if err := mt.Mount("joke2", estr, ttl); err != nil {
+	if err := mt.Mount("joke2", naming.JoinAddressName(estr, ""), ttl); err != nil {
 		boom(t, "Failed to Mount joke2: %s", err)
 	}
 	// This mounts the raw server endpoint as joke3 in mt3 -- like Publish would.
-	if err := mt.Mount("mt3/joke3", estr, ttl); err != nil {
+	if err := mt.Mount("mt3/joke3", naming.JoinAddressName(estr, ""), ttl); err != nil {
 		boom(t, "Failed to Mount joke3: %s", err)
 	}
 
+	// After the mounts above we have:
+	// /<estr>/mt3/mt4/mt5 - the global mount above
+	// /<estr>/mt1/{joke1,joke2,mt3/joker3}
+
 	// Now try resolving inside the namespace.   This guarantees both that the mounts did
 	// what we expected AND that we can actually resolve the results.
 
@@ -213,37 +271,26 @@
 		boom(t, "Should have failed to mt3/mt4/mt5")
 	}
 
-	// ResolveToMountTable of mt3/mt4/mt5 does not go all the way to the root of mt5.
-	servers, err := mt.ResolveToMountTable("mt3/mt4/mt5")
-	if err != nil {
-		boom(t, "Failed to ResolveToMountTable mt3/mt4/mt5: %s", err)
-	}
-	if len(servers) == 0 || servers[0] != naming.JoinAddressNameFixed(estr, "mt4/mt5") {
-		boom(t, "ResolveToMountTable mt3/mt4/mt5 returned wrong servers: %v", servers)
-	}
+	// Resolving m3/mt4/mt5 to a MountTable using the local MountTable gives
+	// us /<estr>//mt4/mt5.
+	testResolveToMountTable(t, mt, "mt3/mt4/mt5", naming.JoinAddressName(estr, "//mt4/mt5"))
+	testResolveToMountTable(t, mt, "mt3/mt4//mt5", naming.JoinAddressName(estr, "//mt4//mt5"))
 
-	servers, err = mt.ResolveToMountTable("mt3/mt4//mt5")
-	if err != nil {
-		boom(t, "Failed to ResolveToMountTable mt3/mt4//mt5: %s", err)
-	}
-	if len(servers) == 0 || servers[0] != naming.JoinAddressNameFixed(estr, "mt4//mt5") {
-		boom(t, "ResolveToMountTable mt3/mt4//mt5 returned wrong servers: %v", servers)
-	}
+	// But looking up mt4/mt5 in the local MountTable will give us
+	// /<estr>//mt1/mt4/mt5 since the localMountTable has mt1 as its root!
+	testResolveToMountTable(t, mt, "mt4/mt5", naming.JoinAddressName(estr, "//mt1/mt4/mt5"))
 
-	servers, err = mt.ResolveToMountTable("mt3//mt4/mt5")
-	if err != nil {
-		boom(t, "Failed to ResolveToMountTable mt3//mt4/mt5: %s", err)
-	}
-	if len(servers) == 0 || servers[0] != naming.JoinAddressNameFixed(estr, "mt3//mt4/mt5") {
-		boom(t, "ResolveToMountTable mt3//mt4/mt5 returned wrong servers: %v", servers)
-	}
+	// Looking mt3//mt4/mt5 will return the MountTable that serves //mt4/mt5.
+	testResolveToMountTable(t, mt, "mt3//mt4/mt5", naming.JoinAddressName(estr, "//mt3//mt4/mt5"))
+	// And the MountTable that serves //mt4/mt5 is /<epstr>//mt1/mt4/mt5
+	testResolveToMountTable(t, mt, "//mt4/mt5", naming.JoinAddressName(estr, "//mt1//mt4/mt5"))
 
 	jokeTests := []struct {
 		name, resolved, resolvedToMT string
 	}{
-		{"joke1", naming.JoinAddressNameFixed(estr, "joke1"), naming.JoinAddressNameFixed(estr, "mt1/joke1")},
-		{"joke2", estr, naming.JoinAddressNameFixed(estr, "mt1/joke2")},
-		{"mt3/joke3", estr, naming.JoinAddressNameFixed(estr, "mt3/joke3")},
+		{"joke1", naming.JoinAddressName(estr, "//joke1"), naming.JoinAddressName(estr, "//mt1/joke1")},
+		{"joke2", naming.JoinAddressName(estr, ""), naming.JoinAddressName(estr, "//mt1/joke2")},
+		{"mt3/joke3", naming.JoinAddressName(estr, ""), naming.JoinAddressName(estr, "//mt3/joke3")},
 	}
 	for _, test := range jokeTests {
 		servers, err := mt.Resolve(test.name)
diff --git a/runtimes/google/naming/mounttable/glob.go b/runtimes/google/naming/mounttable/glob.go
index d7e489d..65e2732 100644
--- a/runtimes/google/naming/mounttable/glob.go
+++ b/runtimes/google/naming/mounttable/glob.go
@@ -117,6 +117,15 @@
 	return reply
 }
 
+// depth returns the directory depth of a given name.
+func depth(name string) int {
+	name = strings.Trim(name, "/")
+	if name == "" {
+		return 0
+	}
+	return strings.Count(name, "/") - strings.Count(name, "//") + 1
+}
+
 func (ns *namespace) globLoop(servers []string, prefix string, pattern *glob.Glob, reply chan naming.MountEntry) {
 	defer close(reply)
 
@@ -129,7 +138,7 @@
 		e := le.Value.(*naming.MountEntry)
 
 		// Get the pattern elements below the current path.
-		suffix := pattern.Split(naming.Depth(e.Name))
+		suffix := pattern.Split(depth(e.Name))
 
 		// Perform a glob at the server.
 		foundRoot, err := ns.globAtServer(e, suffix, l)
diff --git a/runtimes/google/naming/mounttable/glob_test.go b/runtimes/google/naming/mounttable/glob_test.go
new file mode 100644
index 0000000..38a2f81
--- /dev/null
+++ b/runtimes/google/naming/mounttable/glob_test.go
@@ -0,0 +1,27 @@
+package mounttable
+
+import (
+	"testing"
+)
+
+func TestDepth(t *testing.T) {
+	cases := []struct {
+		name  string
+		depth int
+	}{
+		{"", 0},
+		{"foo", 1},
+		{"foo/", 1},
+		{"foo/bar", 2},
+		{"foo//bar", 2},
+		{"/foo/bar", 2},
+		{"//", 0},
+		{"//foo//bar", 2},
+		{"/foo/bar//baz//baf/", 4},
+	}
+	for _, c := range cases {
+		if got, want := depth(c.name), c.depth; want != got {
+			t.Errorf("%q: unexpected depth: %d not %d", c.name, got, want)
+		}
+	}
+}
diff --git a/runtimes/google/naming/mounttable/namespace.go b/runtimes/google/naming/mounttable/namespace.go
index a5b94c0..7a8bb00 100644
--- a/runtimes/google/naming/mounttable/namespace.go
+++ b/runtimes/google/naming/mounttable/namespace.go
@@ -9,9 +9,6 @@
 	"veyron2/verror"
 )
 
-// TODO(caprita): This library should be moved out of the runtime
-// implementation.
-
 // namespace is an implementation of naming.MountTable.
 type namespace struct {
 	sync.RWMutex
diff --git a/runtimes/google/naming/mounttable/resolve.go b/runtimes/google/naming/mounttable/resolve.go
index ef4853b..3efe3c7 100644
--- a/runtimes/google/naming/mounttable/resolve.go
+++ b/runtimes/google/naming/mounttable/resolve.go
@@ -22,7 +22,10 @@
 	// Try each server till one answers.
 	finalErr := errors.New("no servers to resolve query")
 	for _, name := range names {
-		name = naming.MakeFixed(name)
+		// We want to resolve the name against the MountTable specified in its
+		// address, without recursing through ourselves. To this we force
+		// the entire name component to be terminal.
+		name = naming.MakeTerminal(name)
 		call, err := client.StartCall(name, "ResolveStep", nil, callTimeout)
 		if err != nil {
 			finalErr = err
@@ -52,18 +55,18 @@
 	return nil, finalErr
 }
 
-func fixed(names []string) bool {
+func terminal(names []string) bool {
 	for _, name := range names {
-		if !naming.Fixed(name) {
+		if !naming.Terminal(name) {
 			return false
 		}
 	}
 	return true
 }
 
-func makeFixed(names []string) (ret []string) {
+func makeTerminal(names []string) (ret []string) {
 	for _, name := range names {
-		ret = append(ret, naming.MakeFixed(name))
+		ret = append(ret, naming.MakeTerminal(name))
 	}
 	return
 }
@@ -78,7 +81,7 @@
 	// Iterate walking through mount table servers.
 	for remaining := maxDepth; remaining > 0; remaining-- {
 		vlog.VI(2).Infof("Resolve loop %s", names)
-		if fixed(names) {
+		if terminal(names) {
 			return names, nil
 		}
 		var err error
@@ -95,7 +98,7 @@
 			// Any other failure (server not found, no ResolveStep
 			// method, etc.) are a sign that iterative resolution can
 			// stop.
-			return makeFixed(curr), nil
+			return makeTerminal(curr), nil
 		}
 	}
 	return nil, naming.ErrResolutionDepthExceeded
@@ -103,8 +106,8 @@
 
 // ResolveToMountTable implements veyron2/naming.MountTable.
 func (ns *namespace) ResolveToMountTable(name string) ([]string, error) {
-	vlog.VI(2).Infof("ResolveToMountTable %s", name)
 	names := ns.rootName(name)
+	vlog.VI(2).Infof("ResolveToMountTable %s -> rootNames %s", name, names)
 	if len(names) == 0 {
 		return nil, naming.ErrNoMountTable
 	}
@@ -115,23 +118,25 @@
 		curr := names
 		if names, err = resolveAgainstMountTable(ns.rt.Client(), names); err != nil {
 			if verror.Equal(naming.ErrNoSuchNameRoot, err) {
-				return makeFixed(last), nil
+				return makeTerminal(last), nil
 			}
 			if verror.Equal(naming.ErrNoSuchName, err) {
-				return makeFixed(curr), nil
+				return makeTerminal(curr), nil
 			}
-			// Lots of reasons why another can happen.  We are trying to single out "this isn't
-			// a mount table".  TODO(p); make this less of a hack, make a specific verror code
-			// that means "we are up but don't implement what you are asking for".
+			// Lots of reasons why another error can happen.  We are trying
+			// to single out "this isn't a mount table".
+			// TODO(p); make this less of a hack, make a specific verror code
+			// that means "we are up but don't implement what you are
+			// asking for".
 			if notAnMT(err) {
-				return makeFixed(last), nil
+				return makeTerminal(last), nil
 			}
 			// TODO(caprita): If the server is unreachable for
 			// example, we may still want to return its parent
 			// mounttable rather than an error.
 			return nil, err
 		}
-		if fixed(curr) {
+		if terminal(curr) {
 			return curr, nil
 		}
 		last = curr
@@ -151,7 +156,7 @@
 func unresolveAgainstServer(client ipc.Client, names []string) ([]string, error) {
 	finalErr := errors.New("no servers to unresolve")
 	for _, name := range names {
-		name = naming.MakeFixed(name)
+		name = naming.MakeTerminal(name)
 		call, err := client.StartCall(name, "UnresolveStep", nil, callTimeout)
 		if err != nil {
 			finalErr = err
diff --git a/services/mgmt/content/content/impl/impl_test.go b/services/mgmt/content/content/impl/impl_test.go
index ae264f5..c24fee0 100644
--- a/services/mgmt/content/content/impl/impl_test.go
+++ b/services/mgmt/content/content/impl/impl_test.go
@@ -99,7 +99,7 @@
 	cmd.Init(nil, &stdout, &stderr)
 
 	// Test the 'delete' command.
-	if err := cmd.Execute([]string{"delete", naming.JoinAddressNameFixed(endpoint.String(), "exists")}); err != nil {
+	if err := cmd.Execute([]string{"delete", naming.JoinAddressName(endpoint.String(), "//exists")}); err != nil {
 		t.Fatalf("%v", err)
 	}
 	if expected, got := "Content deleted successfully", strings.TrimSpace(stdout.String()); got != expected {
@@ -115,7 +115,7 @@
 	defer os.Remove(dir)
 	file := path.Join(dir, "testfile")
 	defer os.Remove(file)
-	if err := cmd.Execute([]string{"download", naming.JoinAddressNameFixed(endpoint.String(), "exists"), file}); err != nil {
+	if err := cmd.Execute([]string{"download", naming.JoinAddressName(endpoint.String(), "//exists"), file}); err != nil {
 		t.Fatalf("%v", err)
 	}
 	if expected, got := "Content downloaded to file "+file, strings.TrimSpace(stdout.String()); got != expected {
diff --git a/services/mounttable/lib/mounttable.go b/services/mounttable/lib/mounttable.go
index f4a908f..a1ced6e 100644
--- a/services/mounttable/lib/mounttable.go
+++ b/services/mounttable/lib/mounttable.go
@@ -52,7 +52,8 @@
 }
 
 // dummyAuth allows all RPCs.
-type dummyAuth struct { }
+type dummyAuth struct{}
+
 func (dummyAuth) Authorize(security.Context) error {
 	return nil
 }
@@ -66,7 +67,7 @@
 
 // LookupServer implements ipc.Dispatcher.Lookup.
 func (mt *mountTable) Lookup(name string) (ipc.Invoker, security.Authorizer, error) {
-	vlog.VI(2).Infof("*********************Lookup %s\n", name)
+	vlog.VI(2).Infof("*********************Lookup %s", name)
 	mt.RLock()
 	defer mt.RUnlock()
 	ms := &mountContext{
@@ -174,6 +175,7 @@
 	if ttlsecs == 0 {
 		ttlsecs = 10 * 365 * 24 * 60 * 60 // a really long time
 	}
+	vlog.VI(2).Infof("*********************Mount %q -> %s", ms.name, server)
 
 	// Make sure the server name is reasonable.
 	epString, _ := naming.SplitAddressName(server)
diff --git a/services/mounttable/mounttable/impl/impl_test.go b/services/mounttable/mounttable/impl/impl_test.go
index fdd5125..37c758b 100644
--- a/services/mounttable/mounttable/impl/impl_test.go
+++ b/services/mounttable/mounttable/impl/impl_test.go
@@ -90,7 +90,7 @@
 	cmd.Init(nil, &stdout, &stderr)
 
 	// Test the 'glob' command.
-	if err := cmd.Execute([]string{"glob", naming.JoinAddressNameFixed(endpoint.String(), ""), "*"}); err != nil {
+	if err := cmd.Execute([]string{"glob", naming.JoinAddressName(endpoint.String(), ""), "*"}); err != nil {
 		t.Fatalf("%v", err)
 	}
 	if expected, got := "name1 server1 (TTL 2m3s)\nname2 server2 (TTL 7m36s) server3 (TTL 13m9s)", strings.TrimSpace(stdout.String()); got != expected {
@@ -99,7 +99,7 @@
 	stdout.Reset()
 
 	// Test the 'mount' command.
-	if err := cmd.Execute([]string{"mount", naming.JoinAddressNameFixed(endpoint.String(), ""), "server", "123s"}); err != nil {
+	if err := cmd.Execute([]string{"mount", naming.JoinAddressName(endpoint.String(), ""), "server", "123s"}); err != nil {
 		t.Fatalf("%v", err)
 	}
 	if expected, got := "Name mounted successfully.", strings.TrimSpace(stdout.String()); got != expected {
@@ -108,7 +108,7 @@
 	stdout.Reset()
 
 	// Test the 'unmount' command.
-	if err := cmd.Execute([]string{"unmount", naming.JoinAddressNameFixed(endpoint.String(), ""), "server"}); err != nil {
+	if err := cmd.Execute([]string{"unmount", naming.JoinAddressName(endpoint.String(), ""), "server"}); err != nil {
 		t.Fatalf("%v", err)
 	}
 	if expected, got := "Name unmounted successfully.", strings.TrimSpace(stdout.String()); got != expected {
@@ -117,7 +117,7 @@
 	stdout.Reset()
 
 	// Test the 'resolvestep' command.
-	if err := cmd.Execute([]string{"resolvestep", naming.JoinAddressNameFixed(endpoint.String(), "name")}); err != nil {
+	if err := cmd.Execute([]string{"resolvestep", naming.JoinAddressName(endpoint.String(), "//name")}); err != nil {
 		t.Fatalf("%v", err)
 	}
 	if expected, got := `Servers: [{server1 123}] Suffix: "name"`, strings.TrimSpace(stdout.String()); got != expected {