Merge changes Ia2ec1b81,Ibc831ae8

* changes:
  Performance and scale.
  Use struct{}
diff --git a/tools/compliance/Android.bp b/tools/compliance/Android.bp
index afb3080..bbeb76f 100644
--- a/tools/compliance/Android.bp
+++ b/tools/compliance/Android.bp
@@ -48,7 +48,6 @@
 bootstrap_go_package {
     name: "compliance-module",
     srcs: [
-        "actionset.go",
         "condition.go",
         "conditionset.go",
         "doc.go",
diff --git a/tools/compliance/actionset.go b/tools/compliance/actionset.go
deleted file mode 100644
index 656c5de..0000000
--- a/tools/compliance/actionset.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package compliance
-
-import (
-	"fmt"
-	"sort"
-	"strings"
-)
-
-// actionSet maps `actOn` target nodes to the license conditions the actions resolve.
-type actionSet map[*TargetNode]*LicenseConditionSet
-
-// String returns a string representation of the set.
-func (as actionSet) String() string {
-	var sb strings.Builder
-	fmt.Fprintf(&sb, "{")
-	osep := ""
-	for actsOn, cs := range as {
-		cl := cs.AsList()
-		sort.Sort(cl)
-		fmt.Fprintf(&sb, "%s%s -> %s", osep, actsOn.name, cl.String())
-		osep = ", "
-	}
-	fmt.Fprintf(&sb, "}")
-	return sb.String()
-}
-
-// byName returns the subset of `as` actions where the condition name is in `names`.
-func (as actionSet) byName(names ConditionNames) actionSet {
-	result := make(actionSet)
-	for actsOn, cs := range as {
-		bn := cs.ByName(names)
-		if bn.IsEmpty() {
-			continue
-		}
-		result[actsOn] = bn
-	}
-	return result
-}
-
-// byActsOn returns the subset of `as` where `actsOn` is in the `reachable` target node set.
-func (as actionSet) byActsOn(reachable *TargetNodeSet) actionSet {
-	result := make(actionSet)
-	for actsOn, cs := range as {
-		if !reachable.Contains(actsOn) || cs.IsEmpty() {
-			continue
-		}
-		result[actsOn] = cs.Copy()
-	}
-	return result
-}
-
-// copy returns another actionSet with the same value as `as`
-func (as actionSet) copy() actionSet {
-	result := make(actionSet)
-	for actsOn, cs := range as {
-		if cs.IsEmpty() {
-			continue
-		}
-		result[actsOn] = cs.Copy()
-	}
-	return result
-}
-
-// addSet adds all of the actions of `other` if not already present.
-func (as actionSet) addSet(other actionSet) {
-	for actsOn, cs := range other {
-		as.add(actsOn, cs)
-	}
-}
-
-// add makes the action on `actsOn` to resolve the conditions in `cs` a member of the set.
-func (as actionSet) add(actsOn *TargetNode, cs *LicenseConditionSet) {
-	if acs, ok := as[actsOn]; ok {
-		acs.AddSet(cs)
-	} else {
-		as[actsOn] = cs.Copy()
-	}
-}
-
-// addCondition makes the action on `actsOn` to resolve `lc` a member of the set.
-func (as actionSet) addCondition(actsOn *TargetNode, lc LicenseCondition) {
-	if _, ok := as[actsOn]; !ok {
-		as[actsOn] = newLicenseConditionSet()
-	}
-	as[actsOn].Add(lc)
-}
-
-// isEmpty returns true if no action to resolve a condition exists.
-func (as actionSet) isEmpty() bool {
-	for _, cs := range as {
-		if !cs.IsEmpty() {
-			return false
-		}
-	}
-	return true
-}
-
-// conditions returns the set of conditions resolved by the action set.
-func (as actionSet) conditions() *LicenseConditionSet {
-	result := newLicenseConditionSet()
-	for _, cs := range as {
-		result.AddSet(cs)
-	}
-	return result
-}
diff --git a/tools/compliance/cmd/checkshare.go b/tools/compliance/cmd/checkshare.go
index efac8dc..5114a28 100644
--- a/tools/compliance/cmd/checkshare.go
+++ b/tools/compliance/cmd/checkshare.go
@@ -30,8 +30,8 @@
 
 Reports on stderr any targets where policy says that the source both
 must and must not be shared. The error report indicates the target, the
-license condition with origin that has a source privacy policy, and the
-license condition with origin that has a source sharing policy.
+license condition that has a source privacy policy, and the license
+condition that has a source sharing policy.
 
 Any given target may appear multiple times with different combinations
 of conflicting license conditions.
diff --git a/tools/compliance/cmd/checkshare_test.go b/tools/compliance/cmd/checkshare_test.go
index 8ea7748..5036aa5 100644
--- a/tools/compliance/cmd/checkshare_test.go
+++ b/tools/compliance/cmd/checkshare_test.go
@@ -23,15 +23,12 @@
 
 type outcome struct {
 	target           string
-	privacyOrigin    string
 	privacyCondition string
-	shareOrigin      string
 	shareCondition   string
 }
 
 func (o *outcome) String() string {
-	return fmt.Sprintf("%s %s from %s and must share from %s %s",
-		o.target, o.privacyCondition, o.privacyOrigin, o.shareCondition, o.shareOrigin)
+	return fmt.Sprintf("%s %s and must share from %s", o.target, o.privacyCondition, o.shareCondition)
 }
 
 type outcomeList []*outcome
@@ -180,9 +177,7 @@
 			expectedOutcomes: outcomeList{
 				&outcome{
 					target:           "testdata/proprietary/bin/bin2.meta_lic",
-					privacyOrigin:    "testdata/proprietary/bin/bin2.meta_lic",
 					privacyCondition: "proprietary",
-					shareOrigin:      "testdata/proprietary/lib/libb.so.meta_lic",
 					shareCondition:   "restricted",
 				},
 			},
@@ -195,9 +190,7 @@
 			expectedOutcomes: outcomeList{
 				&outcome{
 					target:           "testdata/proprietary/bin/bin2.meta_lic",
-					privacyOrigin:    "testdata/proprietary/bin/bin2.meta_lic",
 					privacyCondition: "proprietary",
-					shareOrigin:      "testdata/proprietary/lib/libb.so.meta_lic",
 					shareCondition:   "restricted",
 				},
 			},
@@ -210,9 +203,7 @@
 			expectedOutcomes: outcomeList{
 				&outcome{
 					target:           "testdata/proprietary/lib/liba.so.meta_lic",
-					privacyOrigin:    "testdata/proprietary/lib/liba.so.meta_lic",
 					privacyCondition: "proprietary",
-					shareOrigin:      "testdata/proprietary/lib/libb.so.meta_lic",
 					shareCondition:   "restricted",
 				},
 			},
@@ -225,9 +216,7 @@
 			expectedOutcomes: outcomeList{
 				&outcome{
 					target:           "testdata/proprietary/bin/bin2.meta_lic",
-					privacyOrigin:    "testdata/proprietary/bin/bin2.meta_lic",
 					privacyCondition: "proprietary",
-					shareOrigin:      "testdata/proprietary/lib/libb.so.meta_lic",
 					shareCondition:   "restricted",
 				},
 			},
@@ -277,10 +266,8 @@
 				cFields := strings.Split(ts, " ")
 				actualOutcomes = append(actualOutcomes, &outcome{
 					target:           cFields[0],
-					privacyOrigin:    cFields[3],
 					privacyCondition: cFields[1],
-					shareOrigin:      cFields[9],
-					shareCondition:   cFields[8],
+					shareCondition:   cFields[6],
 				})
 			}
 			if len(actualOutcomes) != len(tt.expectedOutcomes) {
diff --git a/tools/compliance/cmd/dumpgraph_test.go b/tools/compliance/cmd/dumpgraph_test.go
index b7d66f7..3055022 100644
--- a/tools/compliance/cmd/dumpgraph_test.go
+++ b/tools/compliance/cmd/dumpgraph_test.go
@@ -327,13 +327,13 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/restricted/", labelConditions: true},
 			expectedOut: []string{
-				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted static",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted_allows_dynamic_linking static",
 				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal static",
 				"bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted dynamic",
 				"bin/bin2.meta_lic:notice lib/libd.so.meta_lic:notice dynamic",
 				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice static",
 				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice static",
-				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted static",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted_allows_dynamic_linking static",
 				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted static",
 			},
 		},
@@ -996,7 +996,7 @@
 				matchTarget("bin/bin1.meta_lic", "notice"),
 				matchTarget("bin/bin2.meta_lic", "notice"),
 				matchTarget("highest.apex.meta_lic", "notice"),
-				matchTarget("lib/liba.so.meta_lic", "restricted"),
+				matchTarget("lib/liba.so.meta_lic", "restricted_allows_dynamic_linking"),
 				matchTarget("lib/libb.so.meta_lic", "restricted"),
 				matchTarget("lib/libc.a.meta_lic", "reciprocal"),
 				matchTarget("lib/libd.so.meta_lic", "notice"),
diff --git a/tools/compliance/cmd/dumpresolutions.go b/tools/compliance/cmd/dumpresolutions.go
index 36fbb7d..318cd91 100644
--- a/tools/compliance/cmd/dumpresolutions.go
+++ b/tools/compliance/cmd/dumpresolutions.go
@@ -36,7 +36,7 @@
 )
 
 type context struct {
-	conditions      []string
+	conditions      []compliance.LicenseCondition
 	graphViz        bool
 	labelConditions bool
 	stripPrefix     string
@@ -50,9 +50,9 @@
 resolution in the graph. When -dot flag given, outputs nodes and edges
 in graphviz directed graph format.
 
-If one or more '-c condition' conditions are given, outputs the joined
-set of resolutions for all of the conditions. Otherwise, outputs the
-result of the bottom-up and top-down resolve only.
+If one or more '-c condition' conditions are given, outputs the
+resolution for the union of the conditions. Otherwise, outputs the
+resolution for all conditions.
 
 In plain text mode, when '-label_conditions' is requested, the Target
 and Origin have colon-separated license conditions appended:
@@ -86,13 +86,17 @@
 		os.Exit(2)
 	}
 
+	lcs := make([]compliance.LicenseCondition, 0, len(*conditions))
+	for _, name := range *conditions {
+		lcs = append(lcs, compliance.RecognizedConditionNames[name])
+	}
 	ctx := &context{
-		conditions:      append([]string{}, *conditions...),
+		conditions:      lcs,
 		graphViz:        *graphViz,
 		labelConditions: *labelConditions,
 		stripPrefix:     *stripPrefix,
 	}
-	err := dumpResolutions(ctx, os.Stdout, os.Stderr, flag.Args()...)
+	_, err := dumpResolutions(ctx, os.Stdout, os.Stderr, flag.Args()...)
 	if err != nil {
 		if err == failNoneRequested {
 			flag.Usage()
@@ -104,36 +108,31 @@
 }
 
 // dumpResolutions implements the dumpresolutions utility.
-func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) error {
+func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) (*compliance.LicenseGraph, error) {
 	if len(files) < 1 {
-		return failNoneRequested
+		return nil, failNoneRequested
 	}
 
 	// Read the license graph from the license metadata files (*.meta_lic).
 	licenseGraph, err := compliance.ReadLicenseGraph(os.DirFS("."), stderr, files)
 	if err != nil {
-		return fmt.Errorf("Unable to read license metadata file(s) %q: %v\n", files, err)
+		return nil, fmt.Errorf("Unable to read license metadata file(s) %q: %v\n", files, err)
 	}
 	if licenseGraph == nil {
-		return failNoLicenses
+		return nil, failNoLicenses
 	}
 
-	// resolutions will contain the requested set of resolutions.
-	var resolutions *compliance.ResolutionSet
-
-	resolutions = compliance.ResolveTopDownConditions(licenseGraph)
+	compliance.ResolveTopDownConditions(licenseGraph)
+	cs := compliance.AllLicenseConditions
 	if len(ctx.conditions) > 0 {
-		rlist := make([]*compliance.ResolutionSet, 0, len(ctx.conditions))
+		cs = compliance.NewLicenseConditionSet()
 		for _, c := range ctx.conditions {
-			rlist = append(rlist, compliance.WalkResolutionsForCondition(licenseGraph, resolutions, compliance.ConditionNames{c}))
-		}
-		if len(rlist) == 1 {
-			resolutions = rlist[0]
-		} else {
-			resolutions = compliance.JoinResolutionSets(rlist...)
+			cs = cs.Plus(c)
 		}
 	}
 
+	resolutions := compliance.WalkResolutionsForCondition(licenseGraph, cs)
+
 	// nodes maps license metadata file names to graphViz node names when graphViz requested.
 	nodes := make(map[string]string)
 	n := 0
@@ -142,11 +141,7 @@
 	targetOut := func(target *compliance.TargetNode, sep string) string {
 		tOut := strings.TrimPrefix(target.Name(), ctx.stripPrefix)
 		if ctx.labelConditions {
-			conditions := make([]string, 0, target.LicenseConditions().Count())
-			for _, lc := range target.LicenseConditions().AsList() {
-				conditions = append(conditions, lc.Name())
-			}
-			sort.Strings(conditions)
+			conditions := target.LicenseConditions().Names()
 			if len(conditions) > 0 {
 				tOut += sep + strings.Join(conditions, sep)
 			}
@@ -168,26 +163,16 @@
 	// outputResolution prints a resolution in the requested format to `stdout`, where one can read
 	// a resolution as `tname` resolves `oname`'s conditions named in `cnames`.
 	// `tname` is the name of the target the resolution applies to.
-	// `oname` is the name of the target where the conditions originate.
 	// `cnames` is the list of conditions to resolve.
-	outputResolution := func(tname, aname, oname string, cnames []string) {
+	outputResolution := func(tname, aname string, cnames []string) {
 		if ctx.graphViz {
 			// ... one edge per line labelled with \\n-separated annotations.
 			tNode := nodes[tname]
 			aNode := nodes[aname]
-			oNode := nodes[oname]
-			fmt.Fprintf(stdout, "\t%s -> %s; %s -> %s [label=\"%s\"];\n", tNode, aNode, aNode, oNode, strings.Join(cnames, "\\n"))
+			fmt.Fprintf(stdout, "\t%s -> %s [label=\"%s\"];\n", tNode, aNode, strings.Join(cnames, "\\n"))
 		} else {
 			// ... one edge per line with names in a colon-separated tuple.
-			fmt.Fprintf(stdout, "%s %s %s %s\n", tname, aname, oname, strings.Join(cnames, ":"))
-		}
-	}
-
-	// outputSingleton prints `tname` to plain text in the unexpected event that `tname` is the name of
-	// a target in `resolutions.AppliesTo()` but has no conditions to resolve.
-	outputSingleton := func(tname, aname string) {
-		if !ctx.graphViz {
-			fmt.Fprintf(stdout, "%s %s\n", tname, aname)
+			fmt.Fprintf(stdout, "%s %s %s\n", tname, aname, strings.Join(cnames, ":"))
 		}
 	}
 
@@ -200,16 +185,11 @@
 		fmt.Fprintf(stdout, "strict digraph {\n\trankdir=LR;\n")
 		for _, target := range targets {
 			makeNode(target)
-			rl := compliance.ResolutionList(resolutions.Resolutions(target))
+			rl := resolutions.Resolutions(target)
 			sort.Sort(rl)
 			for _, r := range rl {
 				makeNode(r.ActsOn())
 			}
-			conditions := rl.AllConditions().AsList()
-			sort.Sort(conditions)
-			for _, lc := range conditions {
-				makeNode(lc.Origin())
-			}
 		}
 	}
 
@@ -222,7 +202,7 @@
 			tname = targetOut(target, ":")
 		}
 
-		rl := compliance.ResolutionList(resolutions.Resolutions(target))
+		rl := resolutions.Resolutions(target)
 		sort.Sort(rl)
 		for _, r := range rl {
 			var aname string
@@ -232,38 +212,11 @@
 				aname = targetOut(r.ActsOn(), ":")
 			}
 
-			conditions := r.Resolves().AsList()
-			sort.Sort(conditions)
-
-			// poname is the previous origin name or "" if no previous
-			poname := ""
-
 			// cnames accumulates the list of condition names originating at a single origin that apply to `target`.
-			cnames := make([]string, 0, len(conditions))
+			cnames := r.Resolves().Names()
 
-			// Output 1 line for each attachesTo+actsOn+origin combination.
-			for _, condition := range conditions {
-				var oname string
-				if ctx.graphViz {
-					oname = condition.Origin().Name()
-				} else {
-					oname = targetOut(condition.Origin(), ":")
-				}
-
-				// Detect when origin changes and output prior origin's conditions.
-				if poname != oname && poname != "" {
-					outputResolution(tname, aname, poname, cnames)
-					cnames = cnames[:0]
-				}
-				poname = oname
-				cnames = append(cnames, condition.Name())
-			}
-			// Output last origin's conditions or a singleton if no origins.
-			if poname == "" {
-				outputSingleton(tname, aname)
-			} else {
-				outputResolution(tname, aname, poname, cnames)
-			}
+			// Output 1 line for each attachesTo+actsOn combination.
+			outputResolution(tname, aname, cnames)
 		}
 	}
 	// If graphViz output, rank the root nodes together, and complete the directed graph.
@@ -280,5 +233,5 @@
 		}
 		fmt.Fprintf(stdout, "}\n}\n")
 	}
-	return nil
+	return licenseGraph, nil
 }
diff --git a/tools/compliance/cmd/dumpresolutions_test.go b/tools/compliance/cmd/dumpresolutions_test.go
index cab1cc8..d904671 100644
--- a/tools/compliance/cmd/dumpresolutions_test.go
+++ b/tools/compliance/cmd/dumpresolutions_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"bytes"
+	"compliance"
 	"fmt"
 	"strings"
 	"testing"
@@ -34,20 +35,18 @@
 			name:      "apex",
 			roots:     []string{"highest.apex.meta_lic"},
 			expectedOut: []string{
-				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
-				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
-				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
-				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
-				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
-				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/highest.apex.meta_lic testdata/firstparty/highest.apex.meta_lic notice",
-				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
-				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
-				"testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
-				"testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
-				"testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/highest.apex.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+				"testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -56,20 +55,18 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/firstparty/"},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
-				"lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic notice",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic notice",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -77,22 +74,22 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/firstparty/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic notice",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic notice",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -100,7 +97,7 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions: compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/firstparty/",
 			},
 			expectedOut: []string{},
@@ -110,7 +107,7 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions: compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/firstparty/",
 			},
 			expectedOut: []string{},
@@ -120,7 +117,7 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions:  append(compliance.ImpliesPrivate.AsList(),compliance.ImpliesShared.AsList()...),
 				stripPrefix: "testdata/firstparty/",
 			},
 			expectedOut: []string{},
@@ -131,20 +128,18 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/firstparty/", labelConditions: true},
 			expectedOut: []string{
-				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
-				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice",
-				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice",
-				"lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
-				"lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
-				"lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice",
-				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice notice",
+				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:notice notice",
+				"lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
 			},
 		},
 		{
@@ -152,20 +147,18 @@
 			name:      "container",
 			roots:     []string{"container.zip.meta_lic"},
 			expectedOut: []string{
-				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
-				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
-				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
-				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
-				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
-				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/container.zip.meta_lic testdata/firstparty/container.zip.meta_lic notice",
-				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
-				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
-				"testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
-				"testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
-				"testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/container.zip.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+				"testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -173,11 +166,8 @@
 			name:      "application",
 			roots:     []string{"application.meta_lic"},
 			expectedOut: []string{
-				"testdata/firstparty/application.meta_lic testdata/firstparty/application.meta_lic testdata/firstparty/application.meta_lic notice",
-				"testdata/firstparty/application.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/bin/bin3.meta_lic testdata/firstparty/bin/bin3.meta_lic testdata/firstparty/bin/bin3.meta_lic notice",
-				"testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
+				"testdata/firstparty/application.meta_lic testdata/firstparty/application.meta_lic notice",
+				"testdata/firstparty/application.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
 			},
 		},
 		{
@@ -185,11 +175,9 @@
 			name:      "binary",
 			roots:     []string{"bin/bin1.meta_lic"},
 			expectedOut: []string{
-				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
-				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
-				"testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
-				"testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
 			},
 		},
 		{
@@ -197,7 +185,7 @@
 			name:      "library",
 			roots:     []string{"lib/libd.so.meta_lic"},
 			expectedOut: []string{
-				"testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic notice",
+				"testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic notice",
 			},
 		},
 		{
@@ -205,20 +193,18 @@
 			name:      "apex",
 			roots:     []string{"highest.apex.meta_lic"},
 			expectedOut: []string{
-				"testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
-				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
-				"testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice",
-				"testdata/notice/highest.apex.meta_lic testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
-				"testdata/notice/highest.apex.meta_lic testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice",
-				"testdata/notice/highest.apex.meta_lic testdata/notice/highest.apex.meta_lic testdata/notice/highest.apex.meta_lic notice",
-				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
-				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
-				"testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
-				"testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
-				"testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+				"testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/bin/bin2.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/highest.apex.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+				"testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -227,20 +213,18 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/notice/"},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
-				"lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic notice",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic notice",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -248,22 +232,22 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/notice/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic notice",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic notice",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -271,7 +255,7 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions: compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/notice/",
 			},
 			expectedOut: []string{},
@@ -281,7 +265,7 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions: compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/notice/",
 			},
 			expectedOut: []string{},
@@ -291,7 +275,7 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions:  append(compliance.ImpliesShared.AsList(),compliance.ImpliesPrivate.AsList()...),
 				stripPrefix: "testdata/notice/",
 			},
 			expectedOut: []string{},
@@ -302,20 +286,18 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/notice/", labelConditions: true},
 			expectedOut: []string{
-				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
-				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice",
-				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice",
-				"lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
-				"lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
-				"lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice",
-				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice notice",
+				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:notice notice",
+				"lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
 			},
 		},
 		{
@@ -323,20 +305,18 @@
 			name:      "container",
 			roots:     []string{"container.zip.meta_lic"},
 			expectedOut: []string{
-				"testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
-				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
-				"testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice",
-				"testdata/notice/container.zip.meta_lic testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
-				"testdata/notice/container.zip.meta_lic testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice",
-				"testdata/notice/container.zip.meta_lic testdata/notice/container.zip.meta_lic testdata/notice/container.zip.meta_lic notice",
-				"testdata/notice/container.zip.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/container.zip.meta_lic testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
-				"testdata/notice/container.zip.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
-				"testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
-				"testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
-				"testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+				"testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/bin/bin2.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/container.zip.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+				"testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -344,11 +324,8 @@
 			name:      "application",
 			roots:     []string{"application.meta_lic"},
 			expectedOut: []string{
-				"testdata/notice/application.meta_lic testdata/notice/application.meta_lic testdata/notice/application.meta_lic notice",
-				"testdata/notice/application.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/bin/bin3.meta_lic testdata/notice/bin/bin3.meta_lic testdata/notice/bin/bin3.meta_lic notice",
-				"testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
+				"testdata/notice/application.meta_lic testdata/notice/application.meta_lic notice",
+				"testdata/notice/application.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
 			},
 		},
 		{
@@ -356,11 +333,9 @@
 			name:      "binary",
 			roots:     []string{"bin/bin1.meta_lic"},
 			expectedOut: []string{
-				"testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
-				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
-				"testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
-				"testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
 			},
 		},
 		{
@@ -368,7 +343,7 @@
 			name:      "library",
 			roots:     []string{"lib/libd.so.meta_lic"},
 			expectedOut: []string{
-				"testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic notice",
+				"testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic notice",
 			},
 		},
 		{
@@ -376,20 +351,18 @@
 			name:      "apex",
 			roots:     []string{"highest.apex.meta_lic"},
 			expectedOut: []string{
-				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
-				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
-				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
-				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
-				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
-				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/highest.apex.meta_lic notice",
-				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
-				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
-				"testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
-				"testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
-				"testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic notice",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/highest.apex.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+				"testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -398,20 +371,18 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/reciprocal/"},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
-				"lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic reciprocal",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -419,17 +390,17 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/reciprocal/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -437,15 +408,15 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions: compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/reciprocal/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic reciprocal",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/liba.so.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
 			},
 		},
 		{
@@ -453,7 +424,7 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions: compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/reciprocal/",
 			},
 			expectedOut: []string{},
@@ -463,15 +434,15 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions: append(compliance.ImpliesShared.AsList(),compliance.ImpliesPrivate.AsList()...),
 				stripPrefix: "testdata/reciprocal/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic reciprocal",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/liba.so.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
 			},
 		},
 		{
@@ -480,20 +451,18 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/reciprocal/", labelConditions: true},
 			expectedOut: []string{
-				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:reciprocal lib/liba.so.meta_lic:reciprocal reciprocal",
-				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal",
-				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:reciprocal lib/liba.so.meta_lic:reciprocal reciprocal",
-				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal",
-				"lib/liba.so.meta_lic:reciprocal lib/liba.so.meta_lic:reciprocal lib/liba.so.meta_lic:reciprocal reciprocal",
-				"lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
-				"lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal",
-				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:reciprocal reciprocal",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal reciprocal",
+				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:reciprocal reciprocal",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal reciprocal",
+				"lib/liba.so.meta_lic:reciprocal lib/liba.so.meta_lic:reciprocal reciprocal",
+				"lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
 			},
 		},
 		{
@@ -501,20 +470,18 @@
 			name:      "container",
 			roots:     []string{"container.zip.meta_lic"},
 			expectedOut: []string{
-				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
-				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
-				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
-				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
-				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
-				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/container.zip.meta_lic notice",
-				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
-				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
-				"testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
-				"testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
-				"testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic notice",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/container.zip.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+				"testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
 			},
 		},
 		{
@@ -522,11 +489,8 @@
 			name:      "application",
 			roots:     []string{"application.meta_lic"},
 			expectedOut: []string{
-				"testdata/reciprocal/application.meta_lic testdata/reciprocal/application.meta_lic testdata/reciprocal/application.meta_lic notice",
-				"testdata/reciprocal/application.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/bin/bin3.meta_lic testdata/reciprocal/bin/bin3.meta_lic testdata/reciprocal/bin/bin3.meta_lic notice",
-				"testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
+				"testdata/reciprocal/application.meta_lic testdata/reciprocal/application.meta_lic notice",
+				"testdata/reciprocal/application.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
 			},
 		},
 		{
@@ -534,11 +498,9 @@
 			name:      "binary",
 			roots:     []string{"bin/bin1.meta_lic"},
 			expectedOut: []string{
-				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
-				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
-				"testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
-				"testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
 			},
 		},
 		{
@@ -546,7 +508,7 @@
 			name:      "library",
 			roots:     []string{"lib/libd.so.meta_lic"},
 			expectedOut: []string{
-				"testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic notice",
+				"testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic notice",
 			},
 		},
 		{
@@ -554,33 +516,19 @@
 			name:      "apex",
 			roots:     []string{"highest.apex.meta_lic"},
 			expectedOut: []string{
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
-				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice",
-				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic notice",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
-				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
-				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice:restricted",
+				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin2.meta_lic notice:restricted",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic notice:restricted:restricted_allows_dynamic_linking",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -589,33 +537,19 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/restricted/"},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"bin/bin1.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted",
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"bin/bin2.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"highest.apex.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"lib/libc.a.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted",
-				"lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted",
-				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice:restricted",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice:restricted",
+				"highest.apex.meta_lic highest.apex.meta_lic notice:restricted:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -623,15 +557,15 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/restricted/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
 			},
 		},
 		{
@@ -639,26 +573,23 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions: compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/restricted/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted",
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic highest.apex.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+				"bin/bin1.meta_lic bin/bin1.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin1.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted",
+				"highest.apex.meta_lic highest.apex.meta_lic restricted:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -666,7 +597,7 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions: compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/restricted/",
 			},
 			expectedOut: []string{},
@@ -676,26 +607,23 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions:  append(compliance.ImpliesShared.AsList(),compliance.ImpliesPrivate.AsList()...),
 				stripPrefix: "testdata/restricted/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted",
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic highest.apex.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+				"bin/bin1.meta_lic bin/bin1.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin1.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted",
+				"highest.apex.meta_lic highest.apex.meta_lic restricted:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -704,33 +632,19 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/restricted/", labelConditions: true},
 			expectedOut: []string{
-				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted restricted",
-				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted restricted",
-				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/liba.so.meta_lic:restricted restricted",
-				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal",
-				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
-				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
-				"bin/bin2.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/liba.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal",
-				"highest.apex.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted restricted",
-				"lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
-				"lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal lib/liba.so.meta_lic:restricted restricted",
-				"lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal",
-				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice:restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted_allows_dynamic_linking restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal reciprocal:restricted_allows_dynamic_linking",
+				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice:restricted",
+				"bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice notice:restricted",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice:restricted:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted_allows_dynamic_linking restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal reciprocal:restricted_allows_dynamic_linking",
+				"lib/liba.so.meta_lic:restricted_allows_dynamic_linking lib/liba.so.meta_lic:restricted_allows_dynamic_linking restricted_allows_dynamic_linking",
+				"lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
 			},
 		},
 		{
@@ -738,33 +652,19 @@
 			name:      "container",
 			roots:     []string{"container.zip.meta_lic"},
 			expectedOut: []string{
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
-				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice",
-				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic notice",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
-				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
-				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice:restricted",
+				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin2.meta_lic notice:restricted",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic notice:restricted:restricted_allows_dynamic_linking",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -772,16 +672,8 @@
 			name:      "application",
 			roots:     []string{"application.meta_lic"},
 			expectedOut: []string{
-				"testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic notice",
-				"testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/application.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/application.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/application.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/bin/bin3.meta_lic testdata/restricted/bin/bin3.meta_lic testdata/restricted/bin/bin3.meta_lic restricted",
-				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
-				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic notice:restricted:restricted_allows_dynamic_linking",
+				"testdata/restricted/application.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted:restricted_allows_dynamic_linking",
 			},
 		},
 		{
@@ -789,14 +681,9 @@
 			name:      "binary",
 			roots:     []string{"bin/bin1.meta_lic"},
 			expectedOut: []string{
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
-				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted",
-				"testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
 			},
 		},
 		{
@@ -804,7 +691,7 @@
 			name:      "library",
 			roots:     []string{"lib/libd.so.meta_lic"},
 			expectedOut: []string{
-				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice",
+				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice",
 			},
 		},
 		{
@@ -812,27 +699,19 @@
 			name:      "apex",
 			roots:     []string{"highest.apex.meta_lic"},
 			expectedOut: []string{
-				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
-				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
-				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/highest.apex.meta_lic testdata/proprietary/highest.apex.meta_lic notice",
-				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/highest.apex.meta_lic notice:restricted",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -841,27 +720,19 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/proprietary/"},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic by_exception_only:proprietary",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic by_exception_only:proprietary",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic by_exception_only:proprietary",
-				"bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"bin/bin2.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic by_exception_only:proprietary",
-				"highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic by_exception_only:proprietary",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic by_exception_only:proprietary",
-				"highest.apex.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic by_exception_only:proprietary",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic by_exception_only:proprietary",
-				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted",
-				"lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic proprietary:by_exception_only",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic proprietary:by_exception_only",
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"highest.apex.meta_lic highest.apex.meta_lic notice:restricted",
+				"highest.apex.meta_lic lib/liba.so.meta_lic proprietary:by_exception_only",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic proprietary:by_exception_only",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary:by_exception_only",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -869,13 +740,13 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/proprietary/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice",
-				"highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice",
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
 			},
 		},
 		{
@@ -883,16 +754,16 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions: compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/proprietary/",
 			},
 			expectedOut: []string{
-				"bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted",
+				"highest.apex.meta_lic highest.apex.meta_lic restricted",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -900,17 +771,17 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions: compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/proprietary/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic proprietary",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic proprietary",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic proprietary",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic proprietary",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic proprietary",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic proprietary",
+				"bin/bin2.meta_lic bin/bin2.meta_lic proprietary",
+				"highest.apex.meta_lic bin/bin2.meta_lic proprietary",
+				"highest.apex.meta_lic lib/liba.so.meta_lic proprietary",
+				"highest.apex.meta_lic lib/libc.a.meta_lic proprietary",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
 			},
 		},
 		{
@@ -918,23 +789,21 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions:  append(compliance.ImpliesShared.AsList(),compliance.ImpliesPrivate.AsList()...),
 				stripPrefix: "testdata/proprietary/",
 			},
 			expectedOut: []string{
-				"bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
-				"bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic proprietary",
-				"bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic proprietary",
-				"bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic proprietary",
-				"highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
-				"highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
-				"highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic proprietary",
-				"lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
-				"lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic proprietary",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic proprietary",
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted:proprietary",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted:proprietary",
+				"highest.apex.meta_lic highest.apex.meta_lic restricted",
+				"highest.apex.meta_lic lib/liba.so.meta_lic proprietary",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic proprietary",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -943,27 +812,19 @@
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx:       context{stripPrefix: "testdata/proprietary/", labelConditions: true},
 			expectedOut: []string{
-				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
-				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
-				"bin/bin2.meta_lic:by_exception_only:proprietary bin/bin2.meta_lic:by_exception_only:proprietary bin/bin2.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
-				"bin/bin2.meta_lic:by_exception_only:proprietary bin/bin2.meta_lic:by_exception_only:proprietary lib/libb.so.meta_lic:restricted restricted",
-				"bin/bin2.meta_lic:by_exception_only:proprietary lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
-				"bin/bin2.meta_lic:by_exception_only:proprietary lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice bin/bin2.meta_lic:by_exception_only:proprietary bin/bin2.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
-				"highest.apex.meta_lic:notice bin/bin2.meta_lic:by_exception_only:proprietary lib/libb.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
-				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
-				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
-				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
-				"highest.apex.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
-				"lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
-				"lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary by_exception_only:proprietary",
-				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
-				"lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"bin/bin2.meta_lic:proprietary:by_exception_only bin/bin2.meta_lic:proprietary:by_exception_only restricted:proprietary:by_exception_only",
+				"bin/bin2.meta_lic:proprietary:by_exception_only lib/libb.so.meta_lic:restricted restricted",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:proprietary:by_exception_only restricted:proprietary:by_exception_only",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice:restricted",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"lib/liba.so.meta_lic:proprietary:by_exception_only lib/liba.so.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
 			},
 		},
 		{
@@ -971,27 +832,19 @@
 			name:      "container",
 			roots:     []string{"container.zip.meta_lic"},
 			expectedOut: []string{
-				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
-				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
-				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/container.zip.meta_lic testdata/proprietary/container.zip.meta_lic notice",
-				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/container.zip.meta_lic notice:restricted",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
 			},
 		},
 		{
@@ -999,15 +852,8 @@
 			name:      "application",
 			roots:     []string{"application.meta_lic"},
 			expectedOut: []string{
-				"testdata/proprietary/application.meta_lic testdata/proprietary/application.meta_lic testdata/proprietary/application.meta_lic notice",
-				"testdata/proprietary/application.meta_lic testdata/proprietary/application.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/application.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/application.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/application.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/bin/bin3.meta_lic testdata/proprietary/bin/bin3.meta_lic testdata/proprietary/bin/bin3.meta_lic restricted",
-				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
-				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+				"testdata/proprietary/application.meta_lic testdata/proprietary/application.meta_lic notice:restricted",
+				"testdata/proprietary/application.meta_lic testdata/proprietary/lib/liba.so.meta_lic restricted:proprietary:by_exception_only",
 			},
 		},
 		{
@@ -1015,11 +861,9 @@
 			name:      "binary",
 			roots:     []string{"bin/bin1.meta_lic"},
 			expectedOut: []string{
-				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
-				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary",
-				"testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
 			},
 		},
 		{
@@ -1027,7 +871,7 @@
 			name:      "library",
 			roots:     []string{"lib/libd.so.meta_lic"},
 			expectedOut: []string{
-				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice",
+				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice",
 			},
 		},
 	}
@@ -1046,7 +890,7 @@
 			for _, r := range tt.roots {
 				rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
 			}
-			err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...)
+			_, err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...)
 			if err != nil {
 				t.Fatalf("dumpresolutions: error = %v, stderr = %v", err, stderr)
 				return
@@ -1076,7 +920,7 @@
 }
 
 type matcher interface {
-	matchString(*testContext) string
+	matchString(*testContext, *compliance.LicenseGraph) string
 	typeString() string
 }
 
@@ -1085,10 +929,23 @@
 	conditions []string
 }
 
-func (tm *targetMatcher) matchString(ctx *testContext) string {
+// newTestCondition constructs a test license condition in the license graph.
+func newTestCondition(lg *compliance.LicenseGraph, conditionName... string) compliance.LicenseConditionSet {
+	cs := compliance.NewLicenseConditionSet()
+	for _, name := range conditionName {
+		cs = cs.Plus(compliance.RecognizedConditionNames[name])
+	}
+	if cs.IsEmpty() && len(conditionName) != 0 {
+		panic(fmt.Errorf("attempt to create unrecognized condition: %q", conditionName))
+	}
+	return cs
+}
+
+func (tm *targetMatcher) matchString(ctx *testContext, lg *compliance.LicenseGraph) string {
+	cs := newTestCondition(lg, tm.conditions...)
 	m := tm.target
-	if len(tm.conditions) > 0 {
-		m += "\\n" + strings.Join(tm.conditions, "\\n")
+	if !cs.IsEmpty() {
+		m += "\\n" + strings.Join(cs.Names(), "\\n")
 	}
 	m = ctx.nodes[tm.target] + " [label=\"" + m + "\"];"
 	return m
@@ -1101,14 +958,13 @@
 type resolutionMatcher struct {
 	appliesTo  string
 	actsOn     string
-	origin     string
 	conditions []string
 }
 
-func (rm *resolutionMatcher) matchString(ctx *testContext) string {
-	return ctx.nodes[rm.appliesTo] + " -> " + ctx.nodes[rm.actsOn] + "; " +
-		ctx.nodes[rm.actsOn] + " -> " + ctx.nodes[rm.origin] +
-		" [label=\"" + strings.Join(rm.conditions, "\\n") + "\"];"
+func (rm *resolutionMatcher) matchString(ctx *testContext, lg *compliance.LicenseGraph) string {
+	cs := newTestCondition(lg, rm.conditions...)
+	return ctx.nodes[rm.appliesTo] + " -> " + ctx.nodes[rm.actsOn] +
+		" [label=\"" + strings.Join(cs.Names(), "\\n") + "\"];"
 }
 
 func (rm *resolutionMatcher) typeString() string {
@@ -1125,7 +981,7 @@
 	}
 }
 
-func matchResolution(appliesTo, actsOn, origin string, conditions ...string) getMatcher {
+func matchResolution(appliesTo, actsOn string, conditions ...string) getMatcher {
 	return func(ctx *testContext) matcher {
 		if _, ok := ctx.nodes[appliesTo]; !ok {
 			ctx.nodes[appliesTo] = fmt.Sprintf("unknown%d", ctx.nextNode)
@@ -1135,11 +991,7 @@
 			ctx.nodes[actsOn] = fmt.Sprintf("unknown%d", ctx.nextNode)
 			ctx.nextNode++
 		}
-		if _, ok := ctx.nodes[origin]; !ok {
-			ctx.nodes[origin] = fmt.Sprintf("unknown%d", ctx.nextNode)
-			ctx.nextNode++
-		}
-		return &resolutionMatcher{appliesTo, actsOn, origin, append([]string{}, conditions...)}
+		return &resolutionMatcher{appliesTo, actsOn, append([]string{}, conditions...)}
 	}
 }
 
@@ -1162,76 +1014,53 @@
 				matchTarget("testdata/firstparty/bin/bin2.meta_lic"),
 				matchTarget("testdata/firstparty/highest.apex.meta_lic"),
 				matchTarget("testdata/firstparty/lib/libb.so.meta_lic"),
-				matchTarget("testdata/firstparty/lib/libd.so.meta_lic"),
 				matchResolution(
 					"testdata/firstparty/bin/bin1.meta_lic",
 					"testdata/firstparty/bin/bin1.meta_lic",
-					"testdata/firstparty/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/bin/bin1.meta_lic",
 					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/bin/bin1.meta_lic",
 					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/bin/bin2.meta_lic",
 					"testdata/firstparty/bin/bin2.meta_lic",
-					"testdata/firstparty/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/highest.apex.meta_lic",
 					"testdata/firstparty/bin/bin1.meta_lic",
-					"testdata/firstparty/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/highest.apex.meta_lic",
 					"testdata/firstparty/bin/bin2.meta_lic",
-					"testdata/firstparty/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/highest.apex.meta_lic",
 					"testdata/firstparty/highest.apex.meta_lic",
-					"testdata/firstparty/highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/highest.apex.meta_lic",
 					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/highest.apex.meta_lic",
 					"testdata/firstparty/lib/libb.so.meta_lic",
-					"testdata/firstparty/lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/highest.apex.meta_lic",
 					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/lib/liba.so.meta_lic",
 					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/lib/libb.so.meta_lic",
 					"testdata/firstparty/lib/libb.so.meta_lic",
-					"testdata/firstparty/lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/firstparty/lib/libd.so.meta_lic",
-					"testdata/firstparty/lib/libd.so.meta_lic",
-					"testdata/firstparty/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1247,76 +1076,53 @@
 				matchTarget("bin/bin2.meta_lic"),
 				matchTarget("highest.apex.meta_lic"),
 				matchTarget("lib/libb.so.meta_lic"),
-				matchTarget("lib/libd.so.meta_lic"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1325,7 +1131,7 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/firstparty/",
 			},
 			expectedOut: []getMatcher{
@@ -1338,62 +1144,50 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1402,7 +1196,7 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions:  compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/firstparty/",
 			},
 			expectedOut: []getMatcher{},
@@ -1412,7 +1206,7 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions:  compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/firstparty/",
 			},
 			expectedOut: []getMatcher{},
@@ -1422,7 +1216,7 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
 				stripPrefix: "testdata/firstparty/",
 			},
 			expectedOut: []getMatcher{},
@@ -1439,76 +1233,53 @@
 				matchTarget("bin/bin2.meta_lic", "notice"),
 				matchTarget("highest.apex.meta_lic", "notice"),
 				matchTarget("lib/libb.so.meta_lic", "notice"),
-				matchTarget("lib/libd.so.meta_lic", "notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1523,76 +1294,53 @@
 				matchTarget("testdata/firstparty/bin/bin2.meta_lic"),
 				matchTarget("testdata/firstparty/container.zip.meta_lic"),
 				matchTarget("testdata/firstparty/lib/libb.so.meta_lic"),
-				matchTarget("testdata/firstparty/lib/libd.so.meta_lic"),
 				matchResolution(
 					"testdata/firstparty/bin/bin1.meta_lic",
 					"testdata/firstparty/bin/bin1.meta_lic",
-					"testdata/firstparty/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/bin/bin1.meta_lic",
 					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/bin/bin1.meta_lic",
 					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/bin/bin2.meta_lic",
 					"testdata/firstparty/bin/bin2.meta_lic",
-					"testdata/firstparty/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/container.zip.meta_lic",
 					"testdata/firstparty/bin/bin1.meta_lic",
-					"testdata/firstparty/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/container.zip.meta_lic",
 					"testdata/firstparty/bin/bin2.meta_lic",
-					"testdata/firstparty/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/container.zip.meta_lic",
 					"testdata/firstparty/container.zip.meta_lic",
-					"testdata/firstparty/container.zip.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/container.zip.meta_lic",
 					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/container.zip.meta_lic",
 					"testdata/firstparty/lib/libb.so.meta_lic",
-					"testdata/firstparty/lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/container.zip.meta_lic",
 					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/lib/liba.so.meta_lic",
 					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/lib/libb.so.meta_lic",
 					"testdata/firstparty/lib/libb.so.meta_lic",
-					"testdata/firstparty/lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/firstparty/lib/libd.so.meta_lic",
-					"testdata/firstparty/lib/libd.so.meta_lic",
-					"testdata/firstparty/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1603,32 +1351,13 @@
 			expectedOut: []getMatcher{
 				matchTarget("testdata/firstparty/application.meta_lic"),
 				matchTarget("testdata/firstparty/lib/liba.so.meta_lic"),
-				matchTarget("testdata/firstparty/bin/bin3.meta_lic"),
-				matchTarget("testdata/firstparty/lib/libb.so.meta_lic"),
 				matchResolution(
 					"testdata/firstparty/application.meta_lic",
 					"testdata/firstparty/application.meta_lic",
-					"testdata/firstparty/application.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/application.meta_lic",
 					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/firstparty/bin/bin3.meta_lic",
-					"testdata/firstparty/bin/bin3.meta_lic",
-					"testdata/firstparty/bin/bin3.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/firstparty/lib/libb.so.meta_lic",
-					"testdata/firstparty/lib/libb.so.meta_lic",
-					"testdata/firstparty/lib/libb.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1643,27 +1372,14 @@
 				matchResolution(
 					"testdata/firstparty/bin/bin1.meta_lic",
 					"testdata/firstparty/bin/bin1.meta_lic",
-					"testdata/firstparty/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/bin/bin1.meta_lic",
 					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/firstparty/bin/bin1.meta_lic",
 					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
-					"testdata/firstparty/lib/liba.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
-					"testdata/firstparty/lib/libc.a.meta_lic",
 					"notice"),
 			},
 		},
@@ -1676,7 +1392,6 @@
 				matchResolution(
 					"testdata/firstparty/lib/libd.so.meta_lic",
 					"testdata/firstparty/lib/libd.so.meta_lic",
-					"testdata/firstparty/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1691,76 +1406,53 @@
 				matchTarget("testdata/notice/bin/bin2.meta_lic"),
 				matchTarget("testdata/notice/highest.apex.meta_lic"),
 				matchTarget("testdata/notice/lib/libb.so.meta_lic"),
-				matchTarget("testdata/notice/lib/libd.so.meta_lic"),
 				matchResolution(
 					"testdata/notice/bin/bin1.meta_lic",
 					"testdata/notice/bin/bin1.meta_lic",
-					"testdata/notice/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/bin/bin1.meta_lic",
 					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/bin/bin1.meta_lic",
 					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/bin/bin2.meta_lic",
 					"testdata/notice/bin/bin2.meta_lic",
-					"testdata/notice/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/highest.apex.meta_lic",
 					"testdata/notice/bin/bin1.meta_lic",
-					"testdata/notice/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/highest.apex.meta_lic",
 					"testdata/notice/bin/bin2.meta_lic",
-					"testdata/notice/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/highest.apex.meta_lic",
 					"testdata/notice/highest.apex.meta_lic",
-					"testdata/notice/highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/highest.apex.meta_lic",
 					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/highest.apex.meta_lic",
 					"testdata/notice/lib/libb.so.meta_lic",
-					"testdata/notice/lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/highest.apex.meta_lic",
 					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/lib/liba.so.meta_lic",
 					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/lib/libb.so.meta_lic",
 					"testdata/notice/lib/libb.so.meta_lic",
-					"testdata/notice/lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/notice/lib/libd.so.meta_lic",
-					"testdata/notice/lib/libd.so.meta_lic",
-					"testdata/notice/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1776,76 +1468,53 @@
 				matchTarget("bin/bin2.meta_lic"),
 				matchTarget("highest.apex.meta_lic"),
 				matchTarget("lib/libb.so.meta_lic"),
-				matchTarget("lib/libd.so.meta_lic"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1854,7 +1523,7 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/notice/",
 			},
 			expectedOut: []getMatcher{
@@ -1867,62 +1536,50 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -1931,7 +1588,7 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions:  compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/notice/",
 			},
 			expectedOut: []getMatcher{},
@@ -1941,7 +1598,7 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions:  compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/notice/",
 			},
 			expectedOut: []getMatcher{},
@@ -1951,7 +1608,7 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
 				stripPrefix: "testdata/notice/",
 			},
 			expectedOut: []getMatcher{},
@@ -1968,76 +1625,53 @@
 				matchTarget("bin/bin2.meta_lic", "notice"),
 				matchTarget("highest.apex.meta_lic", "notice"),
 				matchTarget("lib/libb.so.meta_lic", "notice"),
-				matchTarget("lib/libd.so.meta_lic", "notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2052,76 +1686,53 @@
 				matchTarget("testdata/notice/bin/bin2.meta_lic"),
 				matchTarget("testdata/notice/container.zip.meta_lic"),
 				matchTarget("testdata/notice/lib/libb.so.meta_lic"),
-				matchTarget("testdata/notice/lib/libd.so.meta_lic"),
 				matchResolution(
 					"testdata/notice/bin/bin1.meta_lic",
 					"testdata/notice/bin/bin1.meta_lic",
-					"testdata/notice/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/bin/bin1.meta_lic",
 					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/bin/bin1.meta_lic",
 					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/bin/bin2.meta_lic",
 					"testdata/notice/bin/bin2.meta_lic",
-					"testdata/notice/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/container.zip.meta_lic",
 					"testdata/notice/bin/bin1.meta_lic",
-					"testdata/notice/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/container.zip.meta_lic",
 					"testdata/notice/bin/bin2.meta_lic",
-					"testdata/notice/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/container.zip.meta_lic",
 					"testdata/notice/container.zip.meta_lic",
-					"testdata/notice/container.zip.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/container.zip.meta_lic",
 					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/container.zip.meta_lic",
 					"testdata/notice/lib/libb.so.meta_lic",
-					"testdata/notice/lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/container.zip.meta_lic",
 					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/lib/liba.so.meta_lic",
 					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/lib/libb.so.meta_lic",
 					"testdata/notice/lib/libb.so.meta_lic",
-					"testdata/notice/lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/notice/lib/libd.so.meta_lic",
-					"testdata/notice/lib/libd.so.meta_lic",
-					"testdata/notice/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2132,32 +1743,13 @@
 			expectedOut: []getMatcher{
 				matchTarget("testdata/notice/application.meta_lic"),
 				matchTarget("testdata/notice/lib/liba.so.meta_lic"),
-				matchTarget("testdata/notice/bin/bin3.meta_lic"),
-				matchTarget("testdata/notice/lib/libb.so.meta_lic"),
 				matchResolution(
 					"testdata/notice/application.meta_lic",
 					"testdata/notice/application.meta_lic",
-					"testdata/notice/application.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/application.meta_lic",
 					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/notice/bin/bin3.meta_lic",
-					"testdata/notice/bin/bin3.meta_lic",
-					"testdata/notice/bin/bin3.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/notice/lib/libb.so.meta_lic",
-					"testdata/notice/lib/libb.so.meta_lic",
-					"testdata/notice/lib/libb.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2172,27 +1764,14 @@
 				matchResolution(
 					"testdata/notice/bin/bin1.meta_lic",
 					"testdata/notice/bin/bin1.meta_lic",
-					"testdata/notice/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/bin/bin1.meta_lic",
 					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/notice/bin/bin1.meta_lic",
 					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
-					"testdata/notice/lib/liba.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
-					"testdata/notice/lib/libc.a.meta_lic",
 					"notice"),
 			},
 		},
@@ -2205,7 +1784,6 @@
 				matchResolution(
 					"testdata/notice/lib/libd.so.meta_lic",
 					"testdata/notice/lib/libd.so.meta_lic",
-					"testdata/notice/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2220,76 +1798,53 @@
 				matchTarget("testdata/reciprocal/bin/bin2.meta_lic"),
 				matchTarget("testdata/reciprocal/highest.apex.meta_lic"),
 				matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"),
-				matchTarget("testdata/reciprocal/lib/libd.so.meta_lic"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin1.meta_lic",
 					"testdata/reciprocal/bin/bin1.meta_lic",
-					"testdata/reciprocal/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin1.meta_lic",
 					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin1.meta_lic",
 					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin2.meta_lic",
 					"testdata/reciprocal/bin/bin2.meta_lic",
-					"testdata/reciprocal/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/highest.apex.meta_lic",
 					"testdata/reciprocal/bin/bin1.meta_lic",
-					"testdata/reciprocal/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/highest.apex.meta_lic",
 					"testdata/reciprocal/bin/bin2.meta_lic",
-					"testdata/reciprocal/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/highest.apex.meta_lic",
 					"testdata/reciprocal/highest.apex.meta_lic",
-					"testdata/reciprocal/highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/highest.apex.meta_lic",
 					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/highest.apex.meta_lic",
 					"testdata/reciprocal/lib/libb.so.meta_lic",
-					"testdata/reciprocal/lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/highest.apex.meta_lic",
 					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/lib/libb.so.meta_lic",
 					"testdata/reciprocal/lib/libb.so.meta_lic",
-					"testdata/reciprocal/lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/reciprocal/lib/libd.so.meta_lic",
-					"testdata/reciprocal/lib/libd.so.meta_lic",
-					"testdata/reciprocal/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2305,76 +1860,53 @@
 				matchTarget("bin/bin2.meta_lic"),
 				matchTarget("highest.apex.meta_lic"),
 				matchTarget("lib/libb.so.meta_lic"),
-				matchTarget("lib/libd.so.meta_lic"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2383,7 +1915,7 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/reciprocal/",
 			},
 			expectedOut: []getMatcher{
@@ -2394,37 +1926,30 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2433,7 +1958,7 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions:  compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/reciprocal/",
 			},
 			expectedOut: []getMatcher{
@@ -2444,27 +1969,22 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 			},
 		},
@@ -2473,7 +1993,7 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions:  compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/reciprocal/",
 			},
 			expectedOut: []getMatcher{},
@@ -2483,7 +2003,7 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
 				stripPrefix: "testdata/reciprocal/",
 			},
 			expectedOut: []getMatcher{
@@ -2494,27 +2014,22 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 			},
 		},
@@ -2530,76 +2045,53 @@
 				matchTarget("bin/bin2.meta_lic", "notice"),
 				matchTarget("highest.apex.meta_lic", "notice"),
 				matchTarget("lib/libb.so.meta_lic", "notice"),
-				matchTarget("lib/libd.so.meta_lic", "notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2614,76 +2106,53 @@
 				matchTarget("testdata/reciprocal/bin/bin2.meta_lic"),
 				matchTarget("testdata/reciprocal/container.zip.meta_lic"),
 				matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"),
-				matchTarget("testdata/reciprocal/lib/libd.so.meta_lic"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin1.meta_lic",
 					"testdata/reciprocal/bin/bin1.meta_lic",
-					"testdata/reciprocal/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin1.meta_lic",
 					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin1.meta_lic",
 					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin2.meta_lic",
 					"testdata/reciprocal/bin/bin2.meta_lic",
-					"testdata/reciprocal/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/container.zip.meta_lic",
 					"testdata/reciprocal/bin/bin1.meta_lic",
-					"testdata/reciprocal/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/container.zip.meta_lic",
 					"testdata/reciprocal/bin/bin2.meta_lic",
-					"testdata/reciprocal/bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/container.zip.meta_lic",
 					"testdata/reciprocal/container.zip.meta_lic",
-					"testdata/reciprocal/container.zip.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/container.zip.meta_lic",
 					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/container.zip.meta_lic",
 					"testdata/reciprocal/lib/libb.so.meta_lic",
-					"testdata/reciprocal/lib/libb.so.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/container.zip.meta_lic",
 					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/lib/libb.so.meta_lic",
 					"testdata/reciprocal/lib/libb.so.meta_lic",
-					"testdata/reciprocal/lib/libb.so.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/reciprocal/lib/libd.so.meta_lic",
-					"testdata/reciprocal/lib/libd.so.meta_lic",
-					"testdata/reciprocal/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2694,33 +2163,14 @@
 			expectedOut: []getMatcher{
 				matchTarget("testdata/reciprocal/application.meta_lic"),
 				matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"),
-				matchTarget("testdata/reciprocal/bin/bin3.meta_lic"),
-				matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"),
 				matchResolution(
 					"testdata/reciprocal/application.meta_lic",
 					"testdata/reciprocal/application.meta_lic",
-					"testdata/reciprocal/application.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/application.meta_lic",
 					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"reciprocal"),
-				matchResolution(
-					"testdata/reciprocal/bin/bin3.meta_lic",
-					"testdata/reciprocal/bin/bin3.meta_lic",
-					"testdata/reciprocal/bin/bin3.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/reciprocal/lib/libb.so.meta_lic",
-					"testdata/reciprocal/lib/libb.so.meta_lic",
-					"testdata/reciprocal/lib/libb.so.meta_lic",
-					"notice"),
 			},
 		},
 		{
@@ -2734,27 +2184,14 @@
 				matchResolution(
 					"testdata/reciprocal/bin/bin1.meta_lic",
 					"testdata/reciprocal/bin/bin1.meta_lic",
-					"testdata/reciprocal/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin1.meta_lic",
 					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
 					"reciprocal"),
 				matchResolution(
 					"testdata/reciprocal/bin/bin1.meta_lic",
 					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"testdata/reciprocal/lib/liba.so.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
-					"testdata/reciprocal/lib/libc.a.meta_lic",
 					"reciprocal"),
 			},
 		},
@@ -2767,7 +2204,6 @@
 				matchResolution(
 					"testdata/reciprocal/lib/libd.so.meta_lic",
 					"testdata/reciprocal/lib/libd.so.meta_lic",
-					"testdata/reciprocal/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -2781,143 +2217,67 @@
 				matchTarget("testdata/restricted/lib/libc.a.meta_lic"),
 				matchTarget("testdata/restricted/bin/bin2.meta_lic"),
 				matchTarget("testdata/restricted/lib/libb.so.meta_lic"),
-				matchTarget("testdata/restricted/lib/libd.so.meta_lic"),
 				matchTarget("testdata/restricted/highest.apex.meta_lic"),
 				matchResolution(
 					"testdata/restricted/bin/bin1.meta_lic",
 					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
 					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"testdata/restricted/bin/bin1.meta_lic",
 					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"reciprocal"),
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"testdata/restricted/bin/bin2.meta_lic",
 					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/bin/bin2.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
 					"testdata/restricted/lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"testdata/restricted/highest.apex.meta_lic",
 					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/bin/bin2.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/highest.apex.meta_lic",
 					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/highest.apex.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/highest.apex.meta_lic",
 					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/restricted/highest.apex.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
 					"notice"),
+				matchResolution(
+					"testdata/restricted/highest.apex.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/highest.apex.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/highest.apex.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
 			},
 		},
 		{
@@ -2931,143 +2291,67 @@
 				matchTarget("lib/libc.a.meta_lic"),
 				matchTarget("bin/bin2.meta_lic"),
 				matchTarget("lib/libb.so.meta_lic"),
-				matchTarget("lib/libd.so.meta_lic"),
 				matchTarget("highest.apex.meta_lic"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin1.meta_lic",
-					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin1.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin2.meta_lic",
-					"lib/libd.so.meta_lic",
 					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
-					"notice"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"bin/bin1.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
 					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
 			},
 		},
 		{
@@ -3075,7 +2359,7 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/restricted/",
 			},
 			expectedOut: []getMatcher{
@@ -3085,27 +2369,22 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 			},
 		},
@@ -3114,7 +2393,7 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions:  compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/restricted/",
 			},
 			expectedOut: []getMatcher{
@@ -3127,82 +2406,57 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin1.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"bin/bin1.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
 					"highest.apex.meta_lic",
-					"lib/liba.so.meta_lic",
+					"bin/bin2.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
+					"restricted",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 			},
 		},
@@ -3211,7 +2465,7 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions:  compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/restricted/",
 			},
 			expectedOut: []getMatcher{},
@@ -3221,7 +2475,7 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
 				stripPrefix: "testdata/restricted/",
 			},
 			expectedOut: []getMatcher{
@@ -3234,82 +2488,57 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin1.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"bin/bin1.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
 					"highest.apex.meta_lic",
-					"lib/liba.so.meta_lic",
+					"bin/bin2.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
+					"restricted",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 			},
 		},
@@ -3320,147 +2549,71 @@
 			ctx:       context{stripPrefix: "testdata/restricted/", labelConditions: true},
 			expectedOut: []getMatcher{
 				matchTarget("bin/bin1.meta_lic", "notice"),
-				matchTarget("lib/liba.so.meta_lic", "restricted"),
+				matchTarget("lib/liba.so.meta_lic", "restricted_allows_dynamic_linking"),
 				matchTarget("lib/libc.a.meta_lic", "reciprocal"),
 				matchTarget("bin/bin2.meta_lic", "notice"),
 				matchTarget("lib/libb.so.meta_lic", "restricted"),
-				matchTarget("lib/libd.so.meta_lic", "notice"),
 				matchTarget("highest.apex.meta_lic", "notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin1.meta_lic",
-					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin1.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin2.meta_lic",
-					"lib/libd.so.meta_lic",
 					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
-					"notice"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"bin/bin1.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
 					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
 			},
 		},
 		{
@@ -3473,143 +2626,67 @@
 				matchTarget("testdata/restricted/lib/libc.a.meta_lic"),
 				matchTarget("testdata/restricted/bin/bin2.meta_lic"),
 				matchTarget("testdata/restricted/lib/libb.so.meta_lic"),
-				matchTarget("testdata/restricted/lib/libd.so.meta_lic"),
 				matchTarget("testdata/restricted/container.zip.meta_lic"),
 				matchResolution(
 					"testdata/restricted/bin/bin1.meta_lic",
 					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
 					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"testdata/restricted/bin/bin1.meta_lic",
 					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"reciprocal"),
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"testdata/restricted/bin/bin2.meta_lic",
 					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/bin/bin2.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
 					"testdata/restricted/lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"testdata/restricted/container.zip.meta_lic",
 					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/bin/bin2.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/container.zip.meta_lic",
 					"testdata/restricted/bin/bin2.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/container.zip.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/container.zip.meta_lic",
 					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/restricted/container.zip.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
 					"notice"),
+				matchResolution(
+					"testdata/restricted/container.zip.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/container.zip.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/container.zip.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
 			},
 		},
 		{
@@ -3619,57 +2696,16 @@
 			expectedOut: []getMatcher{
 				matchTarget("testdata/restricted/application.meta_lic"),
 				matchTarget("testdata/restricted/lib/liba.so.meta_lic"),
-				matchTarget("testdata/restricted/lib/libb.so.meta_lic"),
-				matchTarget("testdata/restricted/bin/bin3.meta_lic"),
 				matchResolution(
 					"testdata/restricted/application.meta_lic",
 					"testdata/restricted/application.meta_lic",
-					"testdata/restricted/application.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/application.meta_lic",
-					"testdata/restricted/application.meta_lic",
 					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/application.meta_lic",
-					"testdata/restricted/application.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/application.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/application.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/application.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin3.meta_lic",
-					"testdata/restricted/bin/bin3.meta_lic",
-					"testdata/restricted/bin/bin3.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
-					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"restricted"),
 			},
 		},
@@ -3684,42 +2720,16 @@
 				matchResolution(
 					"testdata/restricted/bin/bin1.meta_lic",
 					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"notice"),
 				matchResolution(
 					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/bin/bin1.meta_lic",
 					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
+					"restricted_allows_dynamic_linking"),
 				matchResolution(
 					"testdata/restricted/bin/bin1.meta_lic",
 					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/bin/bin1.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"reciprocal"),
-				matchResolution(
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/liba.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
-					"testdata/restricted/lib/libc.a.meta_lic",
+					"restricted_allows_dynamic_linking",
 					"reciprocal"),
 			},
 		},
@@ -3732,7 +2742,6 @@
 				matchResolution(
 					"testdata/restricted/lib/libd.so.meta_lic",
 					"testdata/restricted/lib/libd.so.meta_lic",
-					"testdata/restricted/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -3746,96 +2755,61 @@
 				matchTarget("testdata/proprietary/lib/libc.a.meta_lic"),
 				matchTarget("testdata/proprietary/bin/bin2.meta_lic"),
 				matchTarget("testdata/proprietary/lib/libb.so.meta_lic"),
-				matchTarget("testdata/proprietary/lib/libd.so.meta_lic"),
 				matchTarget("testdata/proprietary/highest.apex.meta_lic"),
 				matchResolution(
 					"testdata/proprietary/bin/bin1.meta_lic",
 					"testdata/proprietary/bin/bin1.meta_lic",
-					"testdata/proprietary/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/proprietary/bin/bin1.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/bin/bin1.meta_lic",
 					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/bin/bin2.meta_lic",
 					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/bin/bin2.meta_lic",
+					"restricted",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
 					"testdata/proprietary/lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"testdata/proprietary/highest.apex.meta_lic",
 					"testdata/proprietary/bin/bin1.meta_lic",
-					"testdata/proprietary/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/proprietary/highest.apex.meta_lic",
 					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/bin/bin2.meta_lic",
+					"restricted",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/highest.apex.meta_lic",
-					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
 					"testdata/proprietary/highest.apex.meta_lic",
-					"testdata/proprietary/highest.apex.meta_lic",
-					"testdata/proprietary/highest.apex.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"testdata/proprietary/highest.apex.meta_lic",
-					"testdata/proprietary/highest.apex.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/highest.apex.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/highest.apex.meta_lic",
 					"testdata/proprietary/lib/libb.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"testdata/proprietary/highest.apex.meta_lic",
 					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
-					"testdata/proprietary/highest.apex.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/lib/liba.so.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
 					"by_exception_only",
@@ -3843,24 +2817,7 @@
 				matchResolution(
 					"testdata/proprietary/lib/libb.so.meta_lic",
 					"testdata/proprietary/lib/libb.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
 					"restricted"),
-				matchResolution(
-					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
-					"by_exception_only",
-					"proprietary"),
-				matchResolution(
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"notice"),
 			},
 		},
 		{
@@ -3874,96 +2831,61 @@
 				matchTarget("lib/libc.a.meta_lic"),
 				matchTarget("bin/bin2.meta_lic"),
 				matchTarget("lib/libb.so.meta_lic"),
-				matchTarget("lib/libd.so.meta_lic"),
 				matchTarget("highest.apex.meta_lic"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"by_exception_only",
+					"restricted",
 					"proprietary"),
 				matchResolution(
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin2.meta_lic",
-					"lib/libd.so.meta_lic",
 					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
+					"restricted",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"highest.apex.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
 					"by_exception_only",
@@ -3971,24 +2893,7 @@
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"by_exception_only",
-					"proprietary"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"notice"),
 			},
 		},
 		{
@@ -3996,7 +2901,7 @@
 			name:      "apex_trimmed_notice",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"notice"},
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
 				stripPrefix: "testdata/proprietary/",
 			},
 			expectedOut: []getMatcher{
@@ -4005,17 +2910,14 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
 					"notice"),
 			},
 		},
@@ -4024,7 +2926,7 @@
 			name:      "apex_trimmed_share",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted"},
+				conditions:  compliance.ImpliesShared.AsList(),
 				stripPrefix: "testdata/proprietary/",
 			},
 			expectedOut: []getMatcher{
@@ -4034,32 +2936,26 @@
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 			},
 		},
@@ -4068,7 +2964,7 @@
 			name:      "apex_trimmed_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"proprietary"},
+				conditions:  compliance.ImpliesPrivate.AsList(),
 				stripPrefix: "testdata/proprietary/",
 			},
 			expectedOut: []getMatcher{
@@ -4080,37 +2976,30 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"proprietary"),
 			},
 		},
@@ -4119,7 +3008,7 @@
 			name:      "apex_trimmed_share_private",
 			roots:     []string{"highest.apex.meta_lic"},
 			ctx: context{
-				conditions:  []string{"reciprocal", "restricted", "proprietary"},
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
 				stripPrefix: "testdata/proprietary/",
 			},
 			expectedOut: []getMatcher{
@@ -4132,67 +3021,48 @@
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
+					"restricted",
 					"proprietary"),
 				matchResolution(
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
+					"restricted",
 					"proprietary"),
 				matchResolution(
 					"highest.apex.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"proprietary"),
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 			},
 		},
@@ -4207,96 +3077,61 @@
 				matchTarget("lib/libc.a.meta_lic", "by_exception_only", "proprietary"),
 				matchTarget("bin/bin2.meta_lic", "by_exception_only", "proprietary"),
 				matchTarget("lib/libb.so.meta_lic", "restricted"),
-				matchTarget("lib/libd.so.meta_lic", "notice"),
 				matchTarget("highest.apex.meta_lic", "notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/liba.so.meta_lic",
-					"lib/liba.so.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"bin/bin1.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"bin/bin2.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
+					"restricted",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"bin/bin2.meta_lic",
-					"lib/libd.so.meta_lic",
 					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin1.meta_lic",
-					"bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"bin/bin2.meta_lic",
-					"bin/bin2.meta_lic",
+					"restricted",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"highest.apex.meta_lic",
-					"bin/bin2.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"highest.apex.meta_lic",
-					"highest.apex.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"highest.apex.meta_lic",
 					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
-					"highest.apex.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
 					"lib/liba.so.meta_lic",
 					"by_exception_only",
@@ -4304,24 +3139,7 @@
 				matchResolution(
 					"lib/libb.so.meta_lic",
 					"lib/libb.so.meta_lic",
-					"lib/libb.so.meta_lic",
 					"restricted"),
-				matchResolution(
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"lib/libc.a.meta_lic",
-					"by_exception_only",
-					"proprietary"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"lib/libd.so.meta_lic",
-					"notice"),
 			},
 		},
 		{
@@ -4334,96 +3152,61 @@
 				matchTarget("testdata/proprietary/lib/libc.a.meta_lic"),
 				matchTarget("testdata/proprietary/bin/bin2.meta_lic"),
 				matchTarget("testdata/proprietary/lib/libb.so.meta_lic"),
-				matchTarget("testdata/proprietary/lib/libd.so.meta_lic"),
 				matchTarget("testdata/proprietary/container.zip.meta_lic"),
 				matchResolution(
 					"testdata/proprietary/bin/bin1.meta_lic",
 					"testdata/proprietary/bin/bin1.meta_lic",
-					"testdata/proprietary/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/proprietary/bin/bin1.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/bin/bin1.meta_lic",
 					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/bin/bin2.meta_lic",
 					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/bin/bin2.meta_lic",
+					"restricted",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
 					"testdata/proprietary/lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"testdata/proprietary/container.zip.meta_lic",
 					"testdata/proprietary/bin/bin1.meta_lic",
-					"testdata/proprietary/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/proprietary/container.zip.meta_lic",
 					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/bin/bin2.meta_lic",
+					"restricted",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/container.zip.meta_lic",
-					"testdata/proprietary/bin/bin2.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
 					"testdata/proprietary/container.zip.meta_lic",
-					"testdata/proprietary/container.zip.meta_lic",
-					"testdata/proprietary/container.zip.meta_lic",
+					"restricted",
 					"notice"),
 				matchResolution(
 					"testdata/proprietary/container.zip.meta_lic",
-					"testdata/proprietary/container.zip.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/container.zip.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/container.zip.meta_lic",
 					"testdata/proprietary/lib/libb.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
 					"restricted"),
 				matchResolution(
 					"testdata/proprietary/container.zip.meta_lic",
 					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
-					"testdata/proprietary/container.zip.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/lib/liba.so.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
 					"by_exception_only",
@@ -4431,24 +3214,7 @@
 				matchResolution(
 					"testdata/proprietary/lib/libb.so.meta_lic",
 					"testdata/proprietary/lib/libb.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
 					"restricted"),
-				matchResolution(
-					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
-					"by_exception_only",
-					"proprietary"),
-				matchResolution(
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
-					"notice"),
 			},
 		},
 		{
@@ -4458,55 +3224,17 @@
 			expectedOut: []getMatcher{
 				matchTarget("testdata/proprietary/application.meta_lic"),
 				matchTarget("testdata/proprietary/lib/liba.so.meta_lic"),
-				matchTarget("testdata/proprietary/lib/libb.so.meta_lic"),
-				matchTarget("testdata/proprietary/bin/bin3.meta_lic"),
 				matchResolution(
 					"testdata/proprietary/application.meta_lic",
 					"testdata/proprietary/application.meta_lic",
-					"testdata/proprietary/application.meta_lic",
-					"notice"),
-				matchResolution(
-					"testdata/proprietary/application.meta_lic",
-					"testdata/proprietary/application.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
+					"notice",
 					"restricted"),
 				matchResolution(
 					"testdata/proprietary/application.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
+					"restricted",
 					"by_exception_only",
 					"proprietary"),
-				matchResolution(
-					"testdata/proprietary/application.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/application.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/bin/bin3.meta_lic",
-					"testdata/proprietary/bin/bin3.meta_lic",
-					"testdata/proprietary/bin/bin3.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
-					"by_exception_only",
-					"proprietary"),
-				matchResolution(
-					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
-				matchResolution(
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"testdata/proprietary/lib/libb.so.meta_lic",
-					"restricted"),
 			},
 		},
 		{
@@ -4520,30 +3248,15 @@
 				matchResolution(
 					"testdata/proprietary/bin/bin1.meta_lic",
 					"testdata/proprietary/bin/bin1.meta_lic",
-					"testdata/proprietary/bin/bin1.meta_lic",
 					"notice"),
 				matchResolution(
 					"testdata/proprietary/bin/bin1.meta_lic",
 					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 				matchResolution(
 					"testdata/proprietary/bin/bin1.meta_lic",
 					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
-					"by_exception_only",
-					"proprietary"),
-				matchResolution(
-					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
-					"testdata/proprietary/lib/liba.so.meta_lic",
-					"by_exception_only",
-					"proprietary"),
-				matchResolution(
-					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
-					"testdata/proprietary/lib/libc.a.meta_lic",
 					"by_exception_only",
 					"proprietary"),
 			},
@@ -4557,7 +3270,6 @@
 				matchResolution(
 					"testdata/proprietary/lib/libd.so.meta_lic",
 					"testdata/proprietary/lib/libd.so.meta_lic",
-					"testdata/proprietary/lib/libd.so.meta_lic",
 					"notice"),
 			},
 		},
@@ -4566,13 +3278,6 @@
 		t.Run(tt.condition+" "+tt.name, func(t *testing.T) {
 			ctx := &testContext{0, make(map[string]string)}
 
-			expectedOut := &bytes.Buffer{}
-			for _, eo := range tt.expectedOut {
-				m := eo(ctx)
-				expectedOut.WriteString(m.matchString(ctx))
-				expectedOut.WriteString("\n")
-			}
-
 			stdout := &bytes.Buffer{}
 			stderr := &bytes.Buffer{}
 
@@ -4581,8 +3286,7 @@
 				rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
 			}
 			tt.ctx.graphViz = true
-			err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...)
-
+			lg, err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...)
 			if err != nil {
 				t.Fatalf("dumpresolutions: error = %v, stderr = %v", err, stderr)
 				return
@@ -4590,6 +3294,14 @@
 			if stderr.Len() > 0 {
 				t.Errorf("dumpresolutions: gotStderr = %v, want none", stderr)
 			}
+
+			expectedOut := &bytes.Buffer{}
+			for _, eo := range tt.expectedOut {
+				m := eo(ctx)
+				expectedOut.WriteString(m.matchString(ctx, lg))
+				expectedOut.WriteString("\n")
+			}
+
 			outList := strings.Split(stdout.String(), "\n")
 			outLine := 0
 			if outList[outLine] != "strict digraph {" {
diff --git a/tools/compliance/cmd/listshare.go b/tools/compliance/cmd/listshare.go
index bba2308..5c58dc4 100644
--- a/tools/compliance/cmd/listshare.go
+++ b/tools/compliance/cmd/listshare.go
@@ -22,6 +22,7 @@
 	"os"
 	"path/filepath"
 	"sort"
+	"strings"
 )
 
 func init() {
@@ -83,17 +84,17 @@
 	shareSource := compliance.ResolveSourceSharing(licenseGraph)
 
 	// Group the resolutions by project.
-	presolution := make(map[string]*compliance.LicenseConditionSet)
+	presolution := make(map[string]compliance.LicenseConditionSet)
 	for _, target := range shareSource.AttachesTo() {
 		rl := shareSource.Resolutions(target)
 		sort.Sort(rl)
 		for _, r := range rl {
 			for _, p := range r.ActsOn().Projects() {
 				if _, ok := presolution[p]; !ok {
-					presolution[p] = r.Resolves().Copy()
+					presolution[p] = r.Resolves()
 					continue
 				}
-				presolution[p].AddSet(r.Resolves())
+				presolution[p] = presolution[p].Union(r.Resolves())
 			}
 		}
 	}
@@ -107,17 +108,11 @@
 
 	// Output the sorted projects and the source-sharing license conditions that each project resolves.
 	for _, p := range projects {
-		fmt.Fprintf(stdout, "%s", p)
-
-		// Sort the conditions for repeatability/stability.
-		conditions := presolution[p].AsList()
-		sort.Sort(conditions)
-
-		// Output the sorted origin:condition pairs.
-		for _, lc := range conditions {
-			fmt.Fprintf(stdout, ",%s:%s", lc.Origin().Name(), lc.Name())
+		if presolution[p].IsEmpty() {
+			fmt.Fprintf(stdout, "%s\n", p)
+		} else {
+			fmt.Fprintf(stdout, "%s,%s\n", p, strings.Join(presolution[p].Names(), ","))
 		}
-		fmt.Fprintf(stdout, "\n")
 	}
 
 	return nil
diff --git a/tools/compliance/cmd/listshare_test.go b/tools/compliance/cmd/listshare_test.go
index b4847e3..2ee249d 100644
--- a/tools/compliance/cmd/listshare_test.go
+++ b/tools/compliance/cmd/listshare_test.go
@@ -98,12 +98,12 @@
 			expectedOut: []projectShare{
 				{
 					project:    "device/library",
-					conditions: []string{"lib/liba.so.meta_lic:reciprocal"},
+					conditions: []string{"reciprocal"},
 				},
 				{
 					project: "static/library",
 					conditions: []string{
-						"lib/libc.a.meta_lic:reciprocal",
+						"reciprocal",
 					},
 				},
 			},
@@ -115,12 +115,12 @@
 			expectedOut: []projectShare{
 				{
 					project:    "device/library",
-					conditions: []string{"lib/liba.so.meta_lic:reciprocal"},
+					conditions: []string{"reciprocal"},
 				},
 				{
 					project: "static/library",
 					conditions: []string{
-						"lib/libc.a.meta_lic:reciprocal",
+						"reciprocal",
 					},
 				},
 			},
@@ -132,7 +132,7 @@
 			expectedOut: []projectShare{
 				{
 					project:    "device/library",
-					conditions: []string{"lib/liba.so.meta_lic:reciprocal"},
+					conditions: []string{"reciprocal"},
 				},
 			},
 		},
@@ -144,13 +144,13 @@
 				{
 					project: "device/library",
 					conditions: []string{
-						"lib/liba.so.meta_lic:reciprocal",
+						"reciprocal",
 					},
 				},
 				{
 					project: "static/library",
 					conditions: []string{
-						"lib/libc.a.meta_lic:reciprocal",
+						"reciprocal",
 					},
 				},
 			},
@@ -168,34 +168,34 @@
 			expectedOut: []projectShare{
 				{
 					project:    "base/library",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 				{
 					project:    "device/library",
-					conditions: []string{"lib/liba.so.meta_lic:restricted"},
+					conditions: []string{"restricted_allows_dynamic_linking"},
 				},
 				{
 					project:    "dynamic/binary",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 				{
 					project: "highest/apex",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
-						"lib/libb.so.meta_lic:restricted",
+						"restricted",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 				{
 					project: "static/binary",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 				{
 					project: "static/library",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
-						"lib/libc.a.meta_lic:reciprocal",
+						"reciprocal",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 			},
@@ -207,34 +207,34 @@
 			expectedOut: []projectShare{
 				{
 					project:    "base/library",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 				{
 					project: "container/zip",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
-						"lib/libb.so.meta_lic:restricted",
+						"restricted",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 				{
 					project:    "device/library",
-					conditions: []string{"lib/liba.so.meta_lic:restricted"},
+					conditions: []string{"restricted_allows_dynamic_linking"},
 				},
 				{
 					project:    "dynamic/binary",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 				{
 					project: "static/binary",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 				{
 					project: "static/library",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
-						"lib/libc.a.meta_lic:reciprocal",
+						"reciprocal",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 			},
@@ -247,15 +247,15 @@
 				{
 					project: "device/library",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
-						"lib/libb.so.meta_lic:restricted",
+						"restricted",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 				{
 					project: "distributable/application",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
-						"lib/libb.so.meta_lic:restricted",
+						"restricted",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 			},
@@ -268,20 +268,20 @@
 				{
 					project: "device/library",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 				{
 					project: "static/binary",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 				{
 					project: "static/library",
 					conditions: []string{
-						"lib/liba.so.meta_lic:restricted",
-						"lib/libc.a.meta_lic:reciprocal",
+						"reciprocal",
+						"restricted_allows_dynamic_linking",
 					},
 				},
 			},
@@ -299,15 +299,15 @@
 			expectedOut: []projectShare{
 				{
 					project:    "base/library",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 				{
 					project:    "dynamic/binary",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 				{
 					project:    "highest/apex",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 			},
 		},
@@ -318,15 +318,15 @@
 			expectedOut: []projectShare{
 				{
 					project:    "base/library",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 				{
 					project:    "container/zip",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 				{
 					project:    "dynamic/binary",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 			},
 		},
@@ -337,11 +337,11 @@
 			expectedOut: []projectShare{
 				{
 					project:    "device/library",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 				{
 					project:    "distributable/application",
-					conditions: []string{"lib/libb.so.meta_lic:restricted"},
+					conditions: []string{"restricted"},
 				},
 			},
 		},
@@ -365,9 +365,6 @@
 				expectedOut.WriteString(p.project)
 				for _, lc := range p.conditions {
 					expectedOut.WriteString(",")
-					expectedOut.WriteString("testdata/")
-					expectedOut.WriteString(tt.condition)
-					expectedOut.WriteString("/")
 					expectedOut.WriteString(lc)
 				}
 				expectedOut.WriteString("\n")
diff --git a/tools/compliance/condition.go b/tools/compliance/condition.go
index b5c8cec..26b91ca 100644
--- a/tools/compliance/condition.go
+++ b/tools/compliance/condition.go
@@ -16,150 +16,87 @@
 
 import (
 	"fmt"
-	"strings"
 )
 
-// LicenseCondition describes an individual license condition or requirement
-// originating at a specific target node. (immutable)
-//
-// e.g. A module licensed under GPL terms would originate a `restricted` condition.
-type LicenseCondition struct {
-	name   string
-	origin *TargetNode
-}
+// LicenseCondition identifies a recognized license condition by setting the
+// corresponding bit.
+type LicenseCondition uint16
 
-// Name returns the name of the condition. e.g. "restricted" or "notice"
+// LicenseConditionMask is a bitmask for the recognized license conditions.
+const LicenseConditionMask = LicenseCondition(0x3ff)
+
+const (
+	// UnencumberedCondition identifies public domain or public domain-
+	// like license that disclaims copyright.
+	UnencumberedCondition = LicenseCondition(0x0001)
+	// PermissiveCondition identifies a license without notice or other
+	// significant requirements.
+	PermissiveCondition = LicenseCondition(0x0002)
+	// NoticeCondition identifies a typical open-source license with only
+	// notice or attribution requirements.
+	NoticeCondition = LicenseCondition(0x0004)
+	// ReciprocalCondition identifies a license with requirement to share
+	// the module's source only.
+	ReciprocalCondition = LicenseCondition(0x0008)
+	// RestrictedCondition identifies a license with requirement to share
+	// all source code linked to the module's source.
+	RestrictedCondition = LicenseCondition(0x0010)
+	// RestrictedClasspathExceptionCondition identifies RestrictedCondition
+	// waived for dynamic linking from independent modules.
+	RestrictedClasspathExceptionCondition = LicenseCondition(0x0020)
+	// WeaklyRestrictedCondition identifies a RestrictedCondition waived
+	// for dynamic linking.
+	WeaklyRestrictedCondition = LicenseCondition(0x0040)
+	// ProprietaryCondition identifies a license with source privacy
+	// requirements.
+	ProprietaryCondition = LicenseCondition(0x0080)
+	// ByExceptionOnly identifies a license where policy requires product
+	// counsel review prior to use.
+	ByExceptionOnlyCondition = LicenseCondition(0x0100)
+	// NotAllowedCondition identifies a license with onerous conditions
+	// where policy prohibits use.
+	NotAllowedCondition = LicenseCondition(0x0200)
+)
+
+var (
+	// RecognizedConditionNames maps condition strings to LicenseCondition.
+	RecognizedConditionNames = map[string]LicenseCondition{
+		"unencumbered": UnencumberedCondition,
+		"permissive": PermissiveCondition,
+		"notice": NoticeCondition,
+		"reciprocal": ReciprocalCondition,
+		"restricted": RestrictedCondition,
+		"restricted_with_classpath_exception": RestrictedClasspathExceptionCondition,
+		"restricted_allows_dynamic_linking": WeaklyRestrictedCondition,
+		"proprietary": ProprietaryCondition,
+		"by_exception_only": ByExceptionOnlyCondition,
+		"not_allowed": NotAllowedCondition,
+	}
+)
+
+// Name returns the condition string corresponding to the LicenseCondition.
 func (lc LicenseCondition) Name() string {
-	return lc.name
-}
-
-// Origin identifies the TargetNode where the condition originates.
-func (lc LicenseCondition) Origin() *TargetNode {
-	return lc.origin
-}
-
-// asString returns a string representation of a license condition:
-// origin+separator+condition.
-func (lc LicenseCondition) asString(separator string) string {
-	return lc.origin.name + separator + lc.name
-}
-
-// ConditionList implements introspection methods to arrays of LicenseCondition.
-type ConditionList []LicenseCondition
-
-
-// ConditionList orders arrays of LicenseCondition by Origin and Name.
-
-// Len returns the length of the list.
-func (l ConditionList) Len() int      { return len(l) }
-
-// Swap rearranges 2 elements in the list so each occupies the other's former position.
-func (l ConditionList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
-
-// Less returns true when the `i`th element is lexicographically less than tht `j`th element.
-func (l ConditionList) Less(i, j int) bool {
-	if l[i].origin.name == l[j].origin.name {
-		return l[i].name < l[j].name
+	switch lc {
+	case UnencumberedCondition:
+		return "unencumbered"
+	case PermissiveCondition:
+		return "permissive"
+	case NoticeCondition:
+		return "notice"
+	case ReciprocalCondition:
+		return "reciprocal"
+	case RestrictedCondition:
+		return "restricted"
+	case RestrictedClasspathExceptionCondition:
+		return "restricted_with_classpath_exception"
+	case WeaklyRestrictedCondition:
+		return "restricted_allows_dynamic_linking"
+	case ProprietaryCondition:
+		return "proprietary"
+	case ByExceptionOnlyCondition:
+		return "by_exception_only"
+	case NotAllowedCondition:
+		return "not_allowed"
 	}
-	return l[i].origin.name < l[j].origin.name
-}
-
-// String returns a string representation of the set.
-func (cl ConditionList) String() string {
-	var sb strings.Builder
-	fmt.Fprintf(&sb, "[")
-	sep := ""
-	for _, lc := range cl {
-		fmt.Fprintf(&sb, "%s%s:%s", sep, lc.origin.name, lc.name)
-		sep = ", "
-	}
-	fmt.Fprintf(&sb, "]")
-	return sb.String()
-}
-
-// Names returns the list of the conditions' names.
-func (cl ConditionList) Names() []string {
-	result := make([]string, 0, len(cl))
-	for _, lc := range cl {
-		result = append(result, lc.name)
-	}
-	return result
-}
-
-// HasByName returns true if the list contains any condition matching `name`.
-func (cl ConditionList) HasByName(name ConditionNames) bool {
-	for _, lc := range cl {
-		if name.Contains(lc.name) {
-			return true
-		}
-	}
-	return false
-}
-
-// ByName returns the sublist of conditions that match `name`.
-func (cl ConditionList) ByName(name ConditionNames) ConditionList {
-	result := make(ConditionList, 0, cl.CountByName(name))
-	for _, lc := range cl {
-		if name.Contains(lc.name) {
-			result = append(result, lc)
-		}
-	}
-	return result
-}
-
-// CountByName returns the size of the sublist of conditions that match `name`.
-func (cl ConditionList) CountByName(name ConditionNames) int {
-	size := 0
-	for _, lc := range cl {
-		if name.Contains(lc.name) {
-			size++
-		}
-	}
-	return size
-}
-
-// HasByOrigin returns true if the list contains any condition originating at `origin`.
-func (cl ConditionList) HasByOrigin(origin *TargetNode) bool {
-	for _, lc := range cl {
-		if lc.origin.name == origin.name {
-			return true
-		}
-	}
-	return false
-}
-
-// ByOrigin returns the sublist of conditions that originate at `origin`.
-func (cl ConditionList) ByOrigin(origin *TargetNode) ConditionList {
-	result := make(ConditionList, 0, cl.CountByOrigin(origin))
-	for _, lc := range cl {
-		if lc.origin.name == origin.name {
-			result = append(result, lc)
-		}
-	}
-	return result
-}
-
-// CountByOrigin returns the size of the sublist of conditions that originate at `origin`.
-func (cl ConditionList) CountByOrigin(origin *TargetNode) int {
-	size := 0
-	for _, lc := range cl {
-		if lc.origin.name == origin.name {
-			size++
-		}
-	}
-	return size
-}
-
-// ConditionNames implements the Contains predicate for slices of condition
-// name strings.
-type ConditionNames []string
-
-// Contains returns true if the name matches one of the ConditionNames.
-func (cn ConditionNames) Contains(name string) bool {
-	for _, cname := range cn {
-		if cname == name {
-			return true
-		}
-	}
-	return false
+	panic(fmt.Errorf("unrecognized license condition: %04x", lc))
 }
diff --git a/tools/compliance/condition_test.go b/tools/compliance/condition_test.go
index 0507469..778ce4a 100644
--- a/tools/compliance/condition_test.go
+++ b/tools/compliance/condition_test.go
@@ -15,204 +15,53 @@
 package compliance
 
 import (
-	"sort"
-	"strings"
 	"testing"
 )
 
-func TestConditionNames(t *testing.T) {
-	impliesShare := ConditionNames([]string{"restricted", "reciprocal"})
+func TestConditionSetHas(t *testing.T) {
+	impliesShare := ImpliesShared
 
-	if impliesShare.Contains("notice") {
-		t.Errorf("impliesShare.Contains(\"notice\") got true, want false")
+	t.Logf("testing with imliesShare=%04x", impliesShare)
+
+	if impliesShare.HasAny(NoticeCondition) {
+		t.Errorf("impliesShare.HasAny(\"notice\"=%04x) got true, want false", NoticeCondition)
 	}
 
-	if !impliesShare.Contains("restricted") {
-		t.Errorf("impliesShare.Contains(\"restricted\") got false, want true")
+	if !impliesShare.HasAny(RestrictedCondition) {
+		t.Errorf("impliesShare.HasAny(\"restricted\"=%04x) got false, want true", RestrictedCondition)
 	}
 
-	if !impliesShare.Contains("reciprocal") {
-		t.Errorf("impliesShare.Contains(\"reciprocal\") got false, want true")
+	if !impliesShare.HasAny(ReciprocalCondition) {
+		t.Errorf("impliesShare.HasAny(\"reciprocal\"=%04x) got false, want true", ReciprocalCondition)
 	}
 
-	if impliesShare.Contains("") {
-		t.Errorf("impliesShare.Contains(\"\") got true, want false")
+	if impliesShare.HasAny(LicenseCondition(0x0000)) {
+		t.Errorf("impliesShare.HasAny(nil=%04x) got true, want false", LicenseCondition(0x0000))
 	}
 }
 
-func TestConditionList(t *testing.T) {
-	tests := []struct {
-		name       string
-		conditions map[string][]string
-		byName     map[string][]string
-		byOrigin   map[string][]string
-	}{
-		{
-			name: "noticeonly",
-			conditions: map[string][]string{
-				"notice": []string{"bin1", "lib1"},
-			},
-			byName: map[string][]string{
-				"notice":     []string{"bin1", "lib1"},
-				"restricted": []string{},
-			},
-			byOrigin: map[string][]string{
-				"bin1": []string{"notice"},
-				"lib1": []string{"notice"},
-				"bin2": []string{},
-				"lib2": []string{},
-			},
-		},
-		{
-			name:       "empty",
-			conditions: map[string][]string{},
-			byName: map[string][]string{
-				"notice":     []string{},
-				"restricted": []string{},
-			},
-			byOrigin: map[string][]string{
-				"bin1": []string{},
-				"lib1": []string{},
-				"bin2": []string{},
-				"lib2": []string{},
-			},
-		},
-		{
-			name: "everything",
-			conditions: map[string][]string{
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"bin2":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"lib1":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"lib2":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"other": []string{},
-			},
-		},
-		{
-			name: "allbutoneeach",
-			conditions: map[string][]string{
-				"notice":            []string{"bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1"},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"reciprocal", "restricted", "by_exception_only"},
-				"bin2":  []string{"notice", "restricted", "by_exception_only"},
-				"lib1":  []string{"notice", "reciprocal", "by_exception_only"},
-				"lib2":  []string{"notice", "reciprocal", "restricted"},
-				"other": []string{},
-			},
-		},
-		{
-			name: "oneeach",
-			conditions: map[string][]string{
-				"notice":            []string{"bin1"},
-				"reciprocal":        []string{"bin2"},
-				"restricted":        []string{"lib1"},
-				"by_exception_only": []string{"lib2"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin1"},
-				"reciprocal":        []string{"bin2"},
-				"restricted":        []string{"lib1"},
-				"by_exception_only": []string{"lib2"},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"notice"},
-				"bin2":  []string{"reciprocal"},
-				"lib1":  []string{"restricted"},
-				"lib2":  []string{"by_exception_only"},
-				"other": []string{},
-			},
-		},
+func TestConditionName(t *testing.T) {
+	for expected, condition := range RecognizedConditionNames {
+		actual := condition.Name()
+		if expected != actual {
+			t.Errorf("unexpected name for condition %04x: got %s, want %s", condition, actual, expected)
+		}
 	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			lg := newLicenseGraph()
-			cl := toConditionList(lg, tt.conditions)
-			for names, expected := range tt.byName {
-				name := ConditionNames(strings.Split(names, ":"))
-				if cl.HasByName(name) {
-					if len(expected) == 0 {
-						t.Errorf("unexpected ConditionList.HasByName(%q): got true, want false", name)
-					}
-				} else {
-					if len(expected) != 0 {
-						t.Errorf("unexpected ConditionList.HasByName(%q): got false, want true", name)
-					}
-				}
-				if len(expected) != cl.CountByName(name) {
-					t.Errorf("unexpected ConditionList.CountByName(%q): got %d, want %d", name, cl.CountByName(name), len(expected))
-				}
-				byName := cl.ByName(name)
-				if len(expected) != len(byName) {
-					t.Errorf("unexpected ConditionList.ByName(%q): got %v, want %v", name, byName, expected)
-				} else {
-					sort.Strings(expected)
-					actual := make([]string, 0, len(byName))
-					for _, lc := range byName {
-						actual = append(actual, lc.Origin().Name())
-					}
-					sort.Strings(actual)
-					for i := 0; i < len(expected); i++ {
-						if expected[i] != actual[i] {
-							t.Errorf("unexpected ConditionList.ByName(%q) index %d in %v: got %s, want %s", name, i, actual, actual[i], expected[i])
-						}
-					}
-				}
+}
+
+func TestConditionName_InvalidCondition(t *testing.T) {
+	panicked := false
+	var lc LicenseCondition
+	func() {
+		defer func() {
+			if err := recover(); err != nil {
+				panicked = true
 			}
-			for origin, expected := range tt.byOrigin {
-				onode := newTestNode(lg, origin)
-				if cl.HasByOrigin(onode) {
-					if len(expected) == 0 {
-						t.Errorf("unexpected ConditionList.HasByOrigin(%q): got true, want false", origin)
-					}
-				} else {
-					if len(expected) != 0 {
-						t.Errorf("unexpected ConditionList.HasByOrigin(%q): got false, want true", origin)
-					}
-				}
-				if len(expected) != cl.CountByOrigin(onode) {
-					t.Errorf("unexpected ConditionList.CountByOrigin(%q): got %d, want %d", origin, cl.CountByOrigin(onode), len(expected))
-				}
-				byOrigin := cl.ByOrigin(onode)
-				if len(expected) != len(byOrigin) {
-					t.Errorf("unexpected ConditionList.ByOrigin(%q): got %v, want %v", origin, byOrigin, expected)
-				} else {
-					sort.Strings(expected)
-					actual := make([]string, 0, len(byOrigin))
-					for _, lc := range byOrigin {
-						actual = append(actual, lc.Name())
-					}
-					sort.Strings(actual)
-					for i := 0; i < len(expected); i++ {
-						if expected[i] != actual[i] {
-							t.Errorf("unexpected ConditionList.ByOrigin(%q) index %d in %v: got %s, want %s", origin, i, actual, actual[i], expected[i])
-						}
-					}
-				}
-			}
-		})
+		}()
+		name := lc.Name()
+		t.Errorf("invalid condition unexpected name: got %s, wanted panic", name)
+	}()
+	if !panicked {
+		t.Errorf("no expected panic for %04x.Name(): got no panic, wanted panic", lc)
 	}
 }
diff --git a/tools/compliance/conditionset.go b/tools/compliance/conditionset.go
index 1ad15ca..7a12ddc 100644
--- a/tools/compliance/conditionset.go
+++ b/tools/compliance/conditionset.go
@@ -16,263 +16,174 @@
 
 import (
 	"fmt"
+	"strings"
 )
 
-// NewLicenseConditionSet creates a new instance or variable of *LicenseConditionSet.
-func NewLicenseConditionSet(conditions ...LicenseCondition) *LicenseConditionSet {
-	cs := newLicenseConditionSet()
-	cs.Add(conditions...)
+// LicenseConditionSet identifies sets of license conditions.
+type LicenseConditionSet LicenseCondition
+
+// AllLicenseConditions is the set of all recognized license conditions.
+const AllLicenseConditions = LicenseConditionSet(LicenseConditionMask)
+
+// NewLicenseConditionSet returns a set containing exactly the elements of
+// `conditions`.
+func NewLicenseConditionSet(conditions ...LicenseCondition) LicenseConditionSet {
+	cs := LicenseConditionSet(0x00)
+	for _, lc := range conditions {
+		cs |= LicenseConditionSet(lc)
+	}
 	return cs
 }
 
-// LicenseConditionSet describes a mutable set of immutable license conditions.
-type LicenseConditionSet struct {
-	// conditions describes the set of license conditions i.e. (condition name, origin target) pairs
-	// by mapping condition name -> origin target -> true.
-	conditions map[string]map[*TargetNode]bool
-}
-
-// Add makes all `conditions` members of the set if they were not previously.
-func (cs *LicenseConditionSet) Add(conditions ...LicenseCondition) {
-	if len(conditions) == 0 {
-		return
-	}
+// Plus returns a new set containing all of the elements of `cs` and all of the
+// `conditions`.
+func (cs LicenseConditionSet) Plus(conditions ...LicenseCondition) LicenseConditionSet {
+	result := cs
 	for _, lc := range conditions {
-		if _, ok := cs.conditions[lc.name]; !ok {
-			cs.conditions[lc.name] = make(map[*TargetNode]bool)
-		}
-		cs.conditions[lc.name][lc.origin] = true
+		result |= LicenseConditionSet(lc)
 	}
+	return result
 }
 
-// AddSet makes all elements of `conditions` members of the set if they were not previously.
-func (cs *LicenseConditionSet) AddSet(other *LicenseConditionSet) {
-	if len(other.conditions) == 0 {
-		return
+// Union returns a new set containing all of the elements of `cs` and all of the
+// elements of the `other` sets.
+func (cs LicenseConditionSet) Union(other ...LicenseConditionSet) LicenseConditionSet {
+	result := cs
+	for _, ls := range other {
+		result |= ls
 	}
-	for name, origins := range other.conditions {
-		if len(origins) == 0 {
-			continue
-		}
-		if _, ok := cs.conditions[name]; !ok {
-			cs.conditions[name] = make(map[*TargetNode]bool)
-		}
-		for origin := range origins {
-			cs.conditions[name][origin] = other.conditions[name][origin]
-		}
-	}
+	return result
 }
 
-// ByName returns a list of the conditions in the set matching `names`.
-func (cs *LicenseConditionSet) ByName(names ...ConditionNames) *LicenseConditionSet {
-	other := newLicenseConditionSet()
-	for _, cn := range names {
-		for _, name := range cn {
-			if origins, ok := cs.conditions[name]; ok {
-				other.conditions[name] = make(map[*TargetNode]bool)
-				for origin := range origins {
-					other.conditions[name][origin] = true
-				}
-			}
-		}
+// MatchingAny returns the subset of `cs` equal to any of the `conditions`.
+func (cs LicenseConditionSet) MatchingAny(conditions ...LicenseCondition) LicenseConditionSet {
+	result := LicenseConditionSet(0x00)
+	for _, lc := range conditions {
+		result |= cs & LicenseConditionSet(lc)
 	}
-	return other
+	return result
 }
 
-// HasAnyByName returns true if the set contains any conditions matching `names` originating at any target.
-func (cs *LicenseConditionSet) HasAnyByName(names ...ConditionNames) bool {
-	for _, cn := range names {
-		for _, name := range cn {
-			if origins, ok := cs.conditions[name]; ok {
-				if len(origins) > 0 {
-					return true
-				}
-			}
-		}
+// MatchingAnySet returns the subset of `cs` that are members of any of the
+// `other` sets.
+func (cs LicenseConditionSet) MatchingAnySet(other ...LicenseConditionSet) LicenseConditionSet {
+	result := LicenseConditionSet(0x00)
+	for _, ls := range other {
+		result |= cs & ls
 	}
-	return false
+	return result
 }
 
-// CountByName returns the number of conditions matching `names` originating at any target.
-func (cs *LicenseConditionSet) CountByName(names ...ConditionNames) int {
-	size := 0
-	for _, cn := range names {
-		for _, name := range cn {
-			if origins, ok := cs.conditions[name]; ok {
-				size += len(origins)
-			}
-		}
-	}
-	return size
-}
-
-// ByOrigin returns all of the conditions that originate at `origin` regardless of name.
-func (cs *LicenseConditionSet) ByOrigin(origin *TargetNode) *LicenseConditionSet {
-	other := newLicenseConditionSet()
-	for name, origins := range cs.conditions {
-		if _, ok := origins[origin]; ok {
-			other.conditions[name] = make(map[*TargetNode]bool)
-			other.conditions[name][origin] = true
-		}
-	}
-	return other
-}
-
-// HasAnyByOrigin returns true if the set contains any conditions originating at `origin` regardless of condition name.
-func (cs *LicenseConditionSet) HasAnyByOrigin(origin *TargetNode) bool {
-	for _, origins := range cs.conditions {
-		if _, ok := origins[origin]; ok {
+// HasAny returns true when `cs` contains at least one of the `conditions`.
+func (cs LicenseConditionSet) HasAny(conditions ...LicenseCondition) bool {
+	for _, lc := range conditions {
+		if 0x0000 != (cs & LicenseConditionSet(lc)) {
 			return true
 		}
 	}
 	return false
 }
 
-// CountByOrigin returns the number of conditions originating at `origin` regardless of condition name.
-func (cs *LicenseConditionSet) CountByOrigin(origin *TargetNode) int {
-	size := 0
-	for _, origins := range cs.conditions {
-		if _, ok := origins[origin]; ok {
-			size++
-		}
-	}
-	return size
-}
-
-// AsList returns a list of all the conditions in the set.
-func (cs *LicenseConditionSet) AsList() ConditionList {
-	result := make(ConditionList, 0, cs.Count())
-	for name, origins := range cs.conditions {
-		for origin := range origins {
-			result = append(result, LicenseCondition{name, origin})
-		}
-	}
-	return result
-}
-
-// Names returns a list of the names of the conditions in the set.
-func (cs *LicenseConditionSet) Names() []string {
-	result := make([]string, 0, len(cs.conditions))
-	for name := range cs.conditions {
-		result = append(result, name)
-	}
-	return result
-}
-
-// Count returns the number of conditions in the set.
-func (cs *LicenseConditionSet) Count() int {
-	size := 0
-	for _, origins := range cs.conditions {
-		size += len(origins)
-	}
-	return size
-}
-
-// Copy creates a new LicenseCondition variable with the same value.
-func (cs *LicenseConditionSet) Copy() *LicenseConditionSet {
-	other := newLicenseConditionSet()
-	for name := range cs.conditions {
-		other.conditions[name] = make(map[*TargetNode]bool)
-		for origin := range cs.conditions[name] {
-			other.conditions[name][origin] = cs.conditions[name][origin]
-		}
-	}
-	return other
-}
-
-// HasCondition returns true if the set contains any condition matching both `names` and `origin`.
-func (cs *LicenseConditionSet) HasCondition(names ConditionNames, origin *TargetNode) bool {
-	for _, name := range names {
-		if origins, ok := cs.conditions[name]; ok {
-			_, isPresent := origins[origin]
-			if isPresent {
-				return true
-			}
+// MatchesAnySet returns true when `cs` has a non-empty intersection with at
+// least one of the `other` condition sets.
+func (cs LicenseConditionSet) MatchesAnySet(other ...LicenseConditionSet) bool {
+	for _, ls := range other {
+		if 0x0000 != (cs & ls) {
+			return true
 		}
 	}
 	return false
 }
 
-// IsEmpty returns true when the set of conditions contains zero elements.
-func (cs *LicenseConditionSet) IsEmpty() bool {
-	for _, origins := range cs.conditions {
-		if 0 < len(origins) {
+// HasAll returns true when `cs` contains every one of the `conditions`.
+func (cs LicenseConditionSet) HasAll(conditions ...LicenseCondition) bool {
+	for _, lc := range conditions {
+		if 0x0000 == (cs & LicenseConditionSet(lc)) {
 			return false
 		}
 	}
 	return true
 }
 
-// RemoveAllByName changes the set to delete all conditions matching `names`.
-func (cs *LicenseConditionSet) RemoveAllByName(names ...ConditionNames) {
-	for _, cn := range names {
-		for _, name := range cn {
-			delete(cs.conditions, name)
+// MatchesEverySet returns true when `cs` has a non-empty intersection with
+// each of the `other` condition sets.
+func (cs LicenseConditionSet) MatchesEverySet(other ...LicenseConditionSet) bool {
+	for _, ls := range other {
+		if 0x0000 == (cs & ls) {
+			return false
 		}
 	}
+	return true
 }
 
-// Remove changes the set to delete `conditions`.
-func (cs *LicenseConditionSet) Remove(conditions ...LicenseCondition) {
+// Intersection returns the subset of `cs` that are members of every `other`
+// set.
+func (cs LicenseConditionSet) Intersection(other ...LicenseConditionSet) LicenseConditionSet {
+	result := cs
+	for _, ls := range other {
+		result &= ls
+	}
+	return result
+}
+
+// Minus returns the subset of `cs` that are not equaal to any `conditions`.
+func (cs LicenseConditionSet) Minus(conditions ...LicenseCondition) LicenseConditionSet {
+	result := cs
 	for _, lc := range conditions {
-		if _, isPresent := cs.conditions[lc.name]; !isPresent {
-			panic(fmt.Errorf("attempt to remove non-existent condition: %q", lc.asString(":")))
-		}
-		if _, isPresent := cs.conditions[lc.name][lc.origin]; !isPresent {
-			panic(fmt.Errorf("attempt to remove non-existent origin: %q", lc.asString(":")))
-		}
-		delete(cs.conditions[lc.name], lc.origin)
+		result &^= LicenseConditionSet(lc)
 	}
+	return result
 }
 
-// removeSet changes the set to delete all conditions also present in `other`.
-func (cs *LicenseConditionSet) RemoveSet(other *LicenseConditionSet) {
-	for name, origins := range other.conditions {
-		if _, isPresent := cs.conditions[name]; !isPresent {
-			continue
-		}
-		for origin := range origins {
-			delete(cs.conditions[name], origin)
+// Difference returns the subset of `cs` that are not members of any `other`
+// set.
+func (cs LicenseConditionSet) Difference(other ...LicenseConditionSet) LicenseConditionSet {
+	result := cs
+	for _, ls := range other {
+		result &^= ls
+	}
+	return result
+}
+
+// Len returns the number of license conditions in the set.
+func (cs LicenseConditionSet) Len() int {
+	size := 0
+	for lc := LicenseConditionSet(0x01); 0x00 != (AllLicenseConditions & lc); lc <<= 1 {
+		if 0x00 != (cs & lc) {
+			size++
 		}
 	}
+	return size
 }
 
-// compliance-only LicenseConditionSet methods
-
-// newLicenseConditionSet constructs a set of `conditions`.
-func newLicenseConditionSet() *LicenseConditionSet {
-	return &LicenseConditionSet{make(map[string]map[*TargetNode]bool)}
-}
-
-// add changes the set to include each element of `conditions` originating at `origin`.
-func (cs *LicenseConditionSet) add(origin *TargetNode, conditions ...string) {
-	for _, name := range conditions {
-		if _, ok := cs.conditions[name]; !ok {
-			cs.conditions[name] = make(map[*TargetNode]bool)
-		}
-		cs.conditions[name][origin] = true
-	}
-}
-
-// asStringList returns the conditions in the set as `separator`-separated (origin, condition-name) pair strings.
-func (cs *LicenseConditionSet) asStringList(separator string) []string {
-	result := make([]string, 0, cs.Count())
-	for name, origins := range cs.conditions {
-		for origin := range origins {
-			result = append(result, origin.name+separator+name)
+// AsList returns an array of the license conditions in the set.
+func (cs LicenseConditionSet) AsList() []LicenseCondition {
+	result := make([]LicenseCondition, 0, cs.Len())
+	for lc := LicenseConditionSet(0x01); 0x00 != (AllLicenseConditions & lc); lc <<= 1 {
+		if 0x00 != (cs & lc) {
+			result = append(result, LicenseCondition(lc))
 		}
 	}
 	return result
 }
 
-// conditionNamesArray implements a `contains` predicate for arrays of ConditionNames
-type conditionNamesArray []ConditionNames
-
-func (cn conditionNamesArray) contains(name string) bool {
-	for _, names := range cn {
-		if names.Contains(name) {
-			return true
+// Names returns an array of the names of the license conditions in the set.
+func (cs LicenseConditionSet) Names() []string {
+	result := make([]string, 0, cs.Len())
+	for lc := LicenseConditionSet(0x01); 0x00 != (AllLicenseConditions & lc); lc <<= 1 {
+		if 0x00 != (cs & lc) {
+			result = append(result, LicenseCondition(lc).Name())
 		}
 	}
-	return false
+	return result
+}
+
+// IsEmpty returns true when the set contains no license conditions.
+func (cs LicenseConditionSet) IsEmpty() bool {
+	return 0x00 == (cs & AllLicenseConditions)
+}
+
+// String returns a human-readable string representation of the set.
+func (cs LicenseConditionSet) String() string {
+	return fmt.Sprintf("{%s}", strings.Join(cs.Names(), "|"))
 }
diff --git a/tools/compliance/conditionset_test.go b/tools/compliance/conditionset_test.go
index eac0680..c7306e7 100644
--- a/tools/compliance/conditionset_test.go
+++ b/tools/compliance/conditionset_test.go
@@ -15,576 +15,643 @@
 package compliance
 
 import (
-	"sort"
 	"strings"
 	"testing"
 )
 
-type byName map[string][]string
-
-func (bn byName) checkPublic(ls *LicenseConditionSet, t *testing.T) {
-	for names, expected := range bn {
-		name := ConditionNames(strings.Split(names, ":"))
-		if ls.HasAnyByName(name) {
-			if len(expected) == 0 {
-				t.Errorf("unexpected LicenseConditionSet.HasAnyByName(%q): got true, want false", name)
-			}
-		} else {
-			if len(expected) != 0 {
-				t.Errorf("unexpected LicenseConditionSet.HasAnyByName(%q): got false, want true", name)
-			}
-		}
-		if len(expected) != ls.CountByName(name) {
-			t.Errorf("unexpected LicenseConditionSet.CountByName(%q): got %d, want %d", name, ls.CountByName(name), len(expected))
-		}
-		byName := ls.ByName(name).AsList()
-		if len(expected) != len(byName) {
-			t.Errorf("unexpected LicenseConditionSet.ByName(%q): got %v, want %v", name, byName, expected)
-		} else {
-			sort.Strings(expected)
-			actual := make([]string, 0, len(byName))
-			for _, lc := range byName {
-				actual = append(actual, lc.Origin().Name())
-			}
-			sort.Strings(actual)
-			for i := 0; i < len(expected); i++ {
-				if expected[i] != actual[i] {
-					t.Errorf("unexpected LicenseConditionSet.ByName(%q) index %d in %v: got %s, want %s", name, i, actual, actual[i], expected[i])
-				}
-			}
-		}
-	}
-}
-
-type byOrigin map[string][]string
-
-func (bo byOrigin) checkPublic(lg *LicenseGraph, ls *LicenseConditionSet, t *testing.T) {
-	expectedCount := 0
-	for origin, expected := range bo {
-		expectedCount += len(expected)
-		onode := newTestNode(lg, origin)
-		if ls.HasAnyByOrigin(onode) {
-			if len(expected) == 0 {
-				t.Errorf("unexpected LicenseConditionSet.HasAnyByOrigin(%q): got true, want false", origin)
-			}
-		} else {
-			if len(expected) != 0 {
-				t.Errorf("unexpected LicenseConditionSet.HasAnyByOrigin(%q): got false, want true", origin)
-			}
-		}
-		if len(expected) != ls.CountByOrigin(onode) {
-			t.Errorf("unexpected LicenseConditionSet.CountByOrigin(%q): got %d, want %d", origin, ls.CountByOrigin(onode), len(expected))
-		}
-		byOrigin := ls.ByOrigin(onode).AsList()
-		if len(expected) != len(byOrigin) {
-			t.Errorf("unexpected LicenseConditionSet.ByOrigin(%q): got %v, want %v", origin, byOrigin, expected)
-		} else {
-			sort.Strings(expected)
-			actual := make([]string, 0, len(byOrigin))
-			for _, lc := range byOrigin {
-				actual = append(actual, lc.Name())
-			}
-			sort.Strings(actual)
-			for i := 0; i < len(expected); i++ {
-				if expected[i] != actual[i] {
-					t.Errorf("unexpected LicenseConditionSet.ByOrigin(%q) index %d in %v: got %s, want %s", origin, i, actual, actual[i], expected[i])
-				}
-			}
-		}
-	}
-	if expectedCount != ls.Count() {
-		t.Errorf("unexpected LicenseConditionSet.Count(): got %d, want %d", ls.Count(), expectedCount)
-	}
-	if ls.IsEmpty() {
-		if expectedCount != 0 {
-			t.Errorf("unexpected LicenseConditionSet.IsEmpty(): got true, want false")
-		}
-	} else {
-		if expectedCount == 0 {
-			t.Errorf("unexpected LicenseConditionSet.IsEmpty(): got false, want true")
-		}
-	}
-}
-
 func TestConditionSet(t *testing.T) {
 	tests := []struct {
-		name       string
-		conditions map[string][]string
-		add        map[string][]string
-		byName     map[string][]string
-		byOrigin   map[string][]string
+		name        string
+		conditions  []string
+		plus        *[]string
+		minus       *[]string
+		matchingAny map[string][]string
+		expected    []string
 	}{
 		{
 			name:       "empty",
-			conditions: map[string][]string{},
-			add:        map[string][]string{},
-			byName: map[string][]string{
+			conditions: []string{},
+			plus:       &[]string{},
+			matchingAny: map[string][]string{
 				"notice":     []string{},
 				"restricted": []string{},
+				"restricted|reciprocal": []string{},
 			},
-			byOrigin: map[string][]string{
-				"bin1": []string{},
-				"lib1": []string{},
-				"bin2": []string{},
-				"lib2": []string{},
+			expected:   []string{},
+		},
+		{
+			name:       "emptyminusnothing",
+			conditions: []string{},
+			minus:      &[]string{},
+			matchingAny: map[string][]string{
+				"notice":     []string{},
+				"restricted": []string{},
+				"restricted|reciprocal": []string{},
 			},
+			expected:   []string{},
+		},
+		{
+			name:       "emptyminusnotice",
+			conditions: []string{},
+			minus:      &[]string{"notice"},
+			matchingAny: map[string][]string{
+				"notice":     []string{},
+				"restricted": []string{},
+				"restricted|reciprocal": []string{},
+			},
+			expected:   []string{},
 		},
 		{
 			name: "noticeonly",
-			conditions: map[string][]string{
-				"notice": []string{"bin1", "lib1"},
-			},
-			byName: map[string][]string{
-				"notice":     []string{"bin1", "lib1"},
+			conditions: []string{"notice"},
+			matchingAny: map[string][]string{
+				"notice":     []string{"notice"},
+				"notice|proprietary":     []string{"notice"},
 				"restricted": []string{},
 			},
-			byOrigin: map[string][]string{
-				"bin1": []string{"notice"},
-				"lib1": []string{"notice"},
-				"bin2": []string{},
-				"lib2": []string{},
-			},
+			expected: []string{"notice"},
 		},
 		{
-			name: "noticeonlyadded",
-			conditions: map[string][]string{
-				"notice": []string{"bin1", "lib1"},
-			},
-			add: map[string][]string{
-				"notice": []string{"bin1", "bin2"},
-			},
-			byName: map[string][]string{
-				"notice":     []string{"bin1", "bin2", "lib1"},
+			name: "allnoticeonly",
+			conditions: []string{"notice"},
+			plus: &[]string{"notice"},
+			matchingAny: map[string][]string{
+				"notice":     []string{"notice"},
+				"notice|proprietary":     []string{"notice"},
 				"restricted": []string{},
 			},
-			byOrigin: map[string][]string{
-				"bin1": []string{"notice"},
-				"lib1": []string{"notice"},
-				"bin2": []string{"notice"},
-				"lib2": []string{},
+			expected: []string{"notice"},
+		},
+		{
+			name: "emptyplusnotice",
+			conditions: []string{},
+			plus: &[]string{"notice"},
+			matchingAny: map[string][]string{
+				"notice":     []string{"notice"},
+				"notice|proprietary":     []string{"notice"},
+				"restricted": []string{},
 			},
+			expected: []string{"notice"},
 		},
 		{
 			name: "everything",
-			conditions: map[string][]string{
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
+			conditions: []string{"unencumbered", "permissive", "notice", "reciprocal", "restricted", "proprietary"},
+			plus: &[]string{"restricted_with_classpath_exception", "restricted_allows_dynamic_linking", "by_exception_only", "not_allowed"},
+			matchingAny: map[string][]string{
+				"unencumbered": []string{"unencumbered"},
+				"permissive":       []string{"permissive"},
+				"notice":     []string{"notice"},
+				"reciprocal":     []string{"reciprocal"},
+				"restricted":     []string{"restricted"},
+				"restricted_with_classpath_exception":     []string{"restricted_with_classpath_exception"},
+				"restricted_allows_dynamic_linking":     []string{"restricted_allows_dynamic_linking"},
+				"proprietary":     []string{"proprietary"},
+				"by_exception_only":     []string{"by_exception_only"},
+				"not_allowed":     []string{"not_allowed"},
+				"notice|proprietary":     []string{"notice", "proprietary"},
 			},
-			add: map[string][]string{
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"bin2":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"lib1":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"lib2":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"other": []string{},
+			expected: []string{
+				"unencumbered",
+				"permissive",
+				"notice",
+				"reciprocal",
+				"restricted",
+				"restricted_with_classpath_exception",
+				"restricted_allows_dynamic_linking",
+				"proprietary",
+				"by_exception_only",
+				"not_allowed",
 			},
 		},
 		{
-			name: "allbutoneeach",
-			conditions: map[string][]string{
-				"notice":            []string{"bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1"},
+			name: "everythingplusminusnothing",
+			conditions: []string{
+				"unencumbered",
+				"permissive",
+				"notice",
+				"reciprocal",
+				"restricted",
+				"restricted_with_classpath_exception",
+				"restricted_allows_dynamic_linking",
+				"proprietary",
+				"by_exception_only",
+				"not_allowed",
 			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1"},
+			plus: &[]string{},
+			minus: &[]string{},
+			matchingAny: map[string][]string{
+				"unencumbered|permissive|notice": []string{"unencumbered", "permissive", "notice"},
+				"restricted|reciprocal":     []string{"reciprocal", "restricted"},
+				"proprietary|by_exception_only":     []string{"proprietary", "by_exception_only"},
+				"not_allowed":     []string{"not_allowed"},
 			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"reciprocal", "restricted", "by_exception_only"},
-				"bin2":  []string{"notice", "restricted", "by_exception_only"},
-				"lib1":  []string{"notice", "reciprocal", "by_exception_only"},
-				"lib2":  []string{"notice", "reciprocal", "restricted"},
-				"other": []string{},
+			expected: []string{
+				"unencumbered",
+				"permissive",
+				"notice",
+				"reciprocal",
+				"restricted",
+				"restricted_with_classpath_exception",
+				"restricted_allows_dynamic_linking",
+				"proprietary",
+				"by_exception_only",
+				"not_allowed",
 			},
 		},
 		{
-			name: "allbutoneeachadded",
-			conditions: map[string][]string{
-				"notice":            []string{"bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1"},
+			name: "allbutone",
+			conditions: []string{"unencumbered", "permissive", "notice", "reciprocal", "restricted", "proprietary"},
+			plus: &[]string{"restricted_allows_dynamic_linking", "by_exception_only", "not_allowed"},
+			matchingAny: map[string][]string{
+				"unencumbered": []string{"unencumbered"},
+				"permissive":       []string{"permissive"},
+				"notice":     []string{"notice"},
+				"reciprocal":     []string{"reciprocal"},
+				"restricted":     []string{"restricted"},
+				"restricted_with_classpath_exception":     []string{},
+				"restricted_allows_dynamic_linking":     []string{"restricted_allows_dynamic_linking"},
+				"proprietary":     []string{"proprietary"},
+				"by_exception_only":     []string{"by_exception_only"},
+				"not_allowed":     []string{"not_allowed"},
+				"notice|proprietary":     []string{"notice", "proprietary"},
 			},
-			add: map[string][]string{
-				"notice":            []string{"bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1"},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"reciprocal", "restricted", "by_exception_only"},
-				"bin2":  []string{"notice", "restricted", "by_exception_only"},
-				"lib1":  []string{"notice", "reciprocal", "by_exception_only"},
-				"lib2":  []string{"notice", "reciprocal", "restricted"},
-				"other": []string{},
+			expected: []string{
+				"unencumbered",
+				"permissive",
+				"notice",
+				"reciprocal",
+				"restricted",
+				"restricted_allows_dynamic_linking",
+				"proprietary",
+				"by_exception_only",
+				"not_allowed",
 			},
 		},
 		{
-			name: "allbutoneeachfilled",
-			conditions: map[string][]string{
-				"notice":            []string{"bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1"},
+			name: "everythingminusone",
+			conditions: []string{
+				"unencumbered",
+				"permissive",
+				"notice",
+				"reciprocal",
+				"restricted",
+				"restricted_with_classpath_exception",
+				"restricted_allows_dynamic_linking",
+				"proprietary",
+				"by_exception_only",
+				"not_allowed",
 			},
-			add: map[string][]string{
-				"notice":            []string{"bin1", "bin2", "lib1"},
-				"reciprocal":        []string{"bin1", "bin2", "lib2"},
-				"restricted":        []string{"bin1", "lib1", "lib2"},
-				"by_exception_only": []string{"bin2", "lib1", "lib2"},
+			minus: &[]string{"restricted_allows_dynamic_linking"},
+			matchingAny: map[string][]string{
+				"unencumbered": []string{"unencumbered"},
+				"permissive":       []string{"permissive"},
+				"notice":     []string{"notice"},
+				"reciprocal":     []string{"reciprocal"},
+				"restricted":     []string{"restricted"},
+				"restricted_with_classpath_exception":     []string{"restricted_with_classpath_exception"},
+				"restricted_allows_dynamic_linking":     []string{},
+				"proprietary":     []string{"proprietary"},
+				"by_exception_only":     []string{"by_exception_only"},
+				"not_allowed":     []string{"not_allowed"},
+				"restricted|proprietary":     []string{"restricted", "proprietary"},
 			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"bin2":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"lib1":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"lib2":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"other": []string{},
+			expected: []string{
+				"unencumbered",
+				"permissive",
+				"notice",
+				"reciprocal",
+				"restricted",
+				"restricted_with_classpath_exception",
+				"proprietary",
+				"by_exception_only",
+				"not_allowed",
 			},
 		},
 		{
-			name: "oneeach",
-			conditions: map[string][]string{
-				"notice":            []string{"bin1"},
-				"reciprocal":        []string{"bin2"},
-				"restricted":        []string{"lib1"},
-				"by_exception_only": []string{"lib2"},
+			name: "everythingminuseverything",
+			conditions: []string{
+				"unencumbered",
+				"permissive",
+				"notice",
+				"reciprocal",
+				"restricted",
+				"restricted_with_classpath_exception",
+				"restricted_allows_dynamic_linking",
+				"proprietary",
+				"by_exception_only",
+				"not_allowed",
 			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin1"},
-				"reciprocal":        []string{"bin2"},
-				"restricted":        []string{"lib1"},
-				"by_exception_only": []string{"lib2"},
+			minus: &[]string{
+				"unencumbered",
+				"permissive",
+				"notice",
+				"reciprocal",
+				"restricted",
+				"restricted_with_classpath_exception",
+				"restricted_allows_dynamic_linking",
+				"proprietary",
+				"by_exception_only",
+				"not_allowed",
 			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"notice"},
-				"bin2":  []string{"reciprocal"},
-				"lib1":  []string{"restricted"},
-				"lib2":  []string{"by_exception_only"},
-				"other": []string{},
+			matchingAny: map[string][]string{
+				"unencumbered": []string{},
+				"permissive":       []string{},
+				"notice":     []string{},
+				"reciprocal":     []string{},
+				"restricted":     []string{},
+				"restricted_with_classpath_exception":     []string{},
+				"restricted_allows_dynamic_linking":     []string{},
+				"proprietary":     []string{},
+				"by_exception_only":     []string{},
+				"not_allowed":     []string{},
+				"restricted|proprietary":     []string{},
 			},
+			expected: []string{},
 		},
 		{
-			name: "oneeachoverlap",
-			conditions: map[string][]string{
-				"notice":            []string{"bin1"},
-				"reciprocal":        []string{"bin2"},
-				"restricted":        []string{"lib1"},
-				"by_exception_only": []string{"lib2"},
+			name: "restrictedplus",
+			conditions: []string{"restricted", "restricted_with_classpath_exception", "restricted_allows_dynamic_linking"},
+			plus: &[]string{"permissive", "notice", "restricted", "proprietary"},
+			matchingAny: map[string][]string{
+				"unencumbered":     []string{},
+				"permissive":     []string{"permissive"},
+				"notice":     []string{"notice"},
+				"restricted":     []string{"restricted"},
+				"restricted_with_classpath_exception":     []string{"restricted_with_classpath_exception"},
+				"restricted_allows_dynamic_linking":     []string{"restricted_allows_dynamic_linking"},
+				"proprietary":     []string{"proprietary"},
+				"restricted|proprietary":     []string{"restricted", "proprietary"},
+				"by_exception_only": []string{},
+				"proprietary|by_exception_only":     []string{"proprietary"},
 			},
-			add: map[string][]string{
-				"notice":            []string{"lib2"},
-				"reciprocal":        []string{"lib1"},
-				"restricted":        []string{"bin2"},
-				"by_exception_only": []string{"bin1"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin1", "lib2"},
-				"reciprocal":        []string{"bin2", "lib1"},
-				"restricted":        []string{"bin2", "lib1"},
-				"by_exception_only": []string{"bin1", "lib2"},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"by_exception_only", "notice"},
-				"bin2":  []string{"reciprocal", "restricted"},
-				"lib1":  []string{"reciprocal", "restricted"},
-				"lib2":  []string{"by_exception_only", "notice"},
-				"other": []string{},
-			},
-		},
-		{
-			name: "oneeachadded",
-			conditions: map[string][]string{
-				"notice":            []string{"bin1"},
-				"reciprocal":        []string{"bin2"},
-				"restricted":        []string{"lib1"},
-				"by_exception_only": []string{"lib2"},
-			},
-			add: map[string][]string{
-				"notice":            []string{"bin1"},
-				"reciprocal":        []string{"bin2"},
-				"restricted":        []string{"lib1"},
-				"by_exception_only": []string{"lib2"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin1"},
-				"reciprocal":        []string{"bin2"},
-				"restricted":        []string{"lib1"},
-				"by_exception_only": []string{"lib2"},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"notice"},
-				"bin2":  []string{"reciprocal"},
-				"lib1":  []string{"restricted"},
-				"lib2":  []string{"by_exception_only"},
-				"other": []string{},
-			},
+			expected: []string{"permissive", "notice", "restricted", "restricted_with_classpath_exception", "restricted_allows_dynamic_linking", "proprietary"},
 		},
 	}
 	for _, tt := range tests {
-		testPublicInterface := func(lg *LicenseGraph, cs *LicenseConditionSet, t *testing.T) {
-			byName(tt.byName).checkPublic(cs, t)
-			byOrigin(tt.byOrigin).checkPublic(lg, cs, t)
+		toConditions := func(names []string) []LicenseCondition {
+			result := make([]LicenseCondition, 0, len(names))
+			for _, name := range names {
+				result = append(result, RecognizedConditionNames[name])
+			}
+			return result
 		}
-		t.Run(tt.name+"_public_interface", func(t *testing.T) {
-			lg := newLicenseGraph()
-			cs := NewLicenseConditionSet(toConditionList(lg, tt.conditions)...)
-			if tt.add != nil {
-				cs.Add(toConditionList(lg, tt.add)...)
+		populate := func() LicenseConditionSet {
+			testSet := NewLicenseConditionSet(toConditions(tt.conditions)...)
+			if tt.plus != nil {
+				testSet = testSet.Plus(toConditions(*tt.plus)...)
 			}
-			testPublicInterface(lg, cs, t)
-		})
-
-		t.Run("Copy() of "+tt.name+"_public_interface", func(t *testing.T) {
-			lg := newLicenseGraph()
-			cs := NewLicenseConditionSet(toConditionList(lg, tt.conditions)...)
-			if tt.add != nil {
-				cs.Add(toConditionList(lg, tt.add)...)
+			if tt.minus != nil {
+				testSet = testSet.Minus(toConditions(*tt.minus)...)
 			}
-			testPublicInterface(lg, cs.Copy(), t)
-		})
+			return testSet
+		}
+		populateSet := func() LicenseConditionSet {
+			testSet := NewLicenseConditionSet(toConditions(tt.conditions)...)
+			if tt.plus != nil {
+				testSet = testSet.Union(NewLicenseConditionSet(toConditions(*tt.plus)...))
+			}
+			if tt.minus != nil {
+				testSet = testSet.Difference(NewLicenseConditionSet(toConditions(*tt.minus)...))
+			}
+			return testSet
+		}
+		populatePlusSet := func() LicenseConditionSet {
+			testSet := NewLicenseConditionSet(toConditions(tt.conditions)...)
+			if tt.plus != nil {
+				testSet = testSet.Union(NewLicenseConditionSet(toConditions(*tt.plus)...))
+			}
+			if tt.minus != nil {
+				testSet = testSet.Minus(toConditions(*tt.minus)...)
+			}
+			return testSet
+		}
+		populateMinusSet := func() LicenseConditionSet {
+			testSet := NewLicenseConditionSet(toConditions(tt.conditions)...)
+			if tt.plus != nil {
+				testSet = testSet.Plus(toConditions(*tt.plus)...)
+			}
+			if tt.minus != nil {
+				testSet = testSet.Difference(NewLicenseConditionSet(toConditions(*tt.minus)...))
+			}
+			return testSet
+		}
+		checkMatching := func(cs LicenseConditionSet, t *testing.T) {
+			for data, expectedNames := range tt.matchingAny {
+				expectedConditions := toConditions(expectedNames)
+				expected := NewLicenseConditionSet(expectedConditions...)
+				actual := cs.MatchingAny(toConditions(strings.Split(data, "|"))...)
+				actualNames := actual.Names()
 
-		testPrivateInterface := func(lg *LicenseGraph, cs *LicenseConditionSet, t *testing.T) {
-			slist := make([]string, 0, cs.Count())
-			for origin, expected := range tt.byOrigin {
-				for _, name := range expected {
-					slist = append(slist, origin+";"+name)
+				t.Logf("MatchingAny(%s): actual set %04x %s", data, actual, actual.String())
+				t.Logf("MatchingAny(%s): expected set %04x %s", data, expected, expected.String())
+
+				if actual != expected {
+					t.Errorf("MatchingAny(%s): got %04x, want %04x", data, actual, expected)
+					continue
+				}
+				if len(actualNames) != len(expectedNames) {
+					t.Errorf("len(MatchinAny(%s).Names()): got %d, want %d",
+						data, len(actualNames), len(expectedNames))
+				} else {
+					for i := 0; i < len(actualNames); i++ {
+						if actualNames[i] != expectedNames[i] {
+							t.Errorf("MatchingAny(%s).Names()[%d]: got %s, want %s",
+								data, i, actualNames[i], expectedNames[i])
+							break
+						}
+					}
+				}
+				actualConditions := actual.AsList()
+				if len(actualConditions) != len(expectedConditions) {
+					t.Errorf("len(MatchingAny(%d).AsList()):  got %d, want %d",
+						data, len(actualNames), len(expectedNames))
+				} else {
+					for i := 0; i < len(actualNames); i++ {
+						if actualNames[i] != expectedNames[i] {
+							t.Errorf("MatchingAny(%s).AsList()[%d]: got %s, want %s",
+								data, i, actualNames[i], expectedNames[i])
+							break
+						}
+					}
 				}
 			}
-			actualSlist := cs.asStringList(";")
-			if len(slist) != len(actualSlist) {
-				t.Errorf("unexpected LicenseConditionSet.asStringList(\";\"): got %v, want %v", actualSlist, slist)
+		}
+		checkMatchingSet := func(cs LicenseConditionSet, t *testing.T) {
+			for data, expectedNames := range tt.matchingAny {
+				expected := NewLicenseConditionSet(toConditions(expectedNames)...)
+				actual := cs.MatchingAnySet(NewLicenseConditionSet(toConditions(strings.Split(data, "|"))...))
+				actualNames := actual.Names()
+
+				t.Logf("MatchingAnySet(%s): actual set %04x %s", data, actual, actual.String())
+				t.Logf("MatchingAnySet(%s): expected set %04x %s", data, expected, expected.String())
+
+				if actual != expected {
+					t.Errorf("MatchingAnySet(%s): got %04x, want %04x", data, actual, expected)
+					continue
+				}
+				if len(actualNames) != len(expectedNames) {
+					t.Errorf("len(MatchingAnySet(%s).Names()): got %d, want %d",
+						data, len(actualNames), len(expectedNames))
+				} else {
+					for i := 0; i < len(actualNames); i++ {
+						if actualNames[i] != expectedNames[i] {
+							t.Errorf("MatchingAnySet(%s).Names()[%d]: got %s, want %s",
+								data, i, actualNames[i], expectedNames[i])
+							break
+						}
+					}
+				}
+				expectedConditions := toConditions(expectedNames)
+				actualConditions := actual.AsList()
+				if len(actualConditions) != len(expectedConditions) {
+					t.Errorf("len(MatchingAnySet(%s).AsList()): got %d, want %d",
+						data, len(actualNames), len(expectedNames))
+				} else {
+					for i := 0; i < len(actualNames); i++ {
+						if actualNames[i] != expectedNames[i] {
+							t.Errorf("MatchingAnySet(%s).AsList()[%d]: got %s, want %s",
+								data, i, actualNames[i], expectedNames[i])
+							break
+						}
+					}
+				}
+			}
+		}
+
+		checkExpected := func(actual LicenseConditionSet, t *testing.T) bool {
+			t.Logf("checkExpected{%s}", strings.Join(tt.expected, ", "))
+
+			expectedConditions := toConditions(tt.expected)
+			expected := NewLicenseConditionSet(expectedConditions...)
+
+			actualNames := actual.Names()
+
+			t.Logf("actual license condition set: %04x %s", actual, actual.String())
+			t.Logf("expected license condition set: %04x %s", expected, expected.String())
+
+			if actual != expected {
+				t.Errorf("checkExpected: got %04x, want %04x", actual, expected)
+				return false
+			}
+
+			if len(actualNames) != len(tt.expected) {
+				t.Errorf("len(actual.Names()): got %d, want %d", len(actualNames), len(tt.expected))
 			} else {
-				sort.Strings(slist)
-				sort.Strings(actualSlist)
-				for i := 0; i < len(slist); i++ {
-					if slist[i] != actualSlist[i] {
-						t.Errorf("unexpected LicenseConditionSet.asStringList(\";\") index %d in %v: got %s, want %s", i, actualSlist, actualSlist[i], slist[i])
+				for i := 0; i < len(actualNames); i++ {
+					if actualNames[i] != tt.expected[i] {
+						t.Errorf("actual.Names()[%d]: got %s, want %s", i, actualNames[i], tt.expected[i])
+						break
 					}
 				}
 			}
+
+			actualConditions := actual.AsList()
+			if len(actualConditions) != len(expectedConditions) {
+				t.Errorf("len(actual.AsList()): got %d, want %d", len(actualConditions), len(expectedConditions))
+			} else {
+				for i := 0; i < len(actualConditions); i++ {
+					if actualConditions[i] != expectedConditions[i] {
+						t.Errorf("actual.AsList()[%d]: got %s, want %s",
+							i, actualConditions[i], expectedConditions[i])
+						break
+					}
+				}
+			}
+
+			if len(tt.expected) == 0 {
+				if !actual.IsEmpty() {
+					t.Errorf("actual.IsEmpty(): got false, want true")
+				}
+				if actual.HasAny(expectedConditions...) {
+					t.Errorf("actual.HasAny(): got true, want false")
+				}
+			} else {
+				if actual.IsEmpty() {
+					t.Errorf("actual.IsEmpty(): got true, want false")
+				}
+				if !actual.HasAny(expectedConditions...) {
+					t.Errorf("actual.HasAny(all expected): got false, want true")
+				}
+			}
+			if !actual.HasAll(expectedConditions...) {
+				t.Errorf("actual.Hasll(all expected): want true, got false")
+			}
+			for _, expectedCondition := range expectedConditions {
+				if !actual.HasAny(expectedCondition) {
+					t.Errorf("actual.HasAny(%q): got false, want true", expectedCondition.Name())
+				}
+				if !actual.HasAll(expectedCondition) {
+					t.Errorf("actual.HasAll(%q): got false, want true", expectedCondition.Name())
+				}
+			}
+
+			notExpected := (AllLicenseConditions &^ expected)
+			notExpectedList := notExpected.AsList()
+			t.Logf("not expected license condition set: %04x %s", notExpected, notExpected.String())
+
+			if len(tt.expected) == 0 {
+				if actual.HasAny(append(expectedConditions, notExpectedList...)...) {
+					t.Errorf("actual.HasAny(all conditions): want false, got true")
+				}
+			} else {
+				if !actual.HasAny(append(expectedConditions, notExpectedList...)...) {
+					t.Errorf("actual.HasAny(all conditions): want true, got false")
+				}
+			}
+			if len(notExpectedList) == 0 {
+				if !actual.HasAll(append(expectedConditions, notExpectedList...)...) {
+					t.Errorf("actual.HasAll(all conditions): want true, got false")
+				}
+			} else {
+				if actual.HasAll(append(expectedConditions, notExpectedList...)...) {
+					t.Errorf("actual.HasAll(all conditions): want false, got true")
+				}
+			}
+			for _, unexpectedCondition := range notExpectedList {
+				if actual.HasAny(unexpectedCondition) {
+					t.Errorf("actual.HasAny(%q): got true, want false", unexpectedCondition.Name())
+				}
+				if actual.HasAll(unexpectedCondition) {
+					t.Errorf("actual.HasAll(%q): got true, want false", unexpectedCondition.Name())
+				}
+			}
+			return true
 		}
 
-		t.Run(tt.name+"_private_list_interface", func(t *testing.T) {
-			lg := newLicenseGraph()
-			cs := newLicenseConditionSet()
-			for name, origins := range tt.conditions {
-				for _, origin := range origins {
-					cs.add(newTestNode(lg, origin), name)
-				}
-			}
-			if tt.add != nil {
-				cs.Add(toConditionList(lg, tt.add)...)
-			}
-			testPrivateInterface(lg, cs, t)
-		})
+		checkExpectedSet := func(actual LicenseConditionSet, t *testing.T) bool {
+			t.Logf("checkExpectedSet{%s}", strings.Join(tt.expected, ", "))
 
-		t.Run(tt.name+"_private_set_interface", func(t *testing.T) {
-			lg := newLicenseGraph()
-			cs := newLicenseConditionSet()
-			for name, origins := range tt.conditions {
-				for _, origin := range origins {
-					cs.add(newTestNode(lg, origin), name)
-				}
+			expectedConditions := toConditions(tt.expected)
+			expected := NewLicenseConditionSet(expectedConditions...)
+
+			actualNames := actual.Names()
+
+			t.Logf("actual license condition set: %04x %s", actual, actual.String())
+			t.Logf("expected license condition set: %04x %s", expected, expected.String())
+
+			if actual != expected {
+				t.Errorf("checkExpectedSet: got %04x, want %04x", actual, expected)
+				return false
 			}
-			if tt.add != nil {
-				other := newLicenseConditionSet()
-				for name, origins := range tt.add {
-					for _, origin := range origins {
-						other.add(newTestNode(lg, origin), name)
+
+			if len(actualNames) != len(tt.expected) {
+				t.Errorf("len(actual.Names()): got %d, want %d", len(actualNames), len(tt.expected))
+			} else {
+				for i := 0; i < len(actualNames); i++ {
+					if actualNames[i] != tt.expected[i] {
+						t.Errorf("actual.Names()[%d]: got %s, want %s", i, actualNames[i], tt.expected[i])
+						break
 					}
 				}
-				cs.AddSet(other)
 			}
-			testPrivateInterface(lg, cs, t)
-		})
-	}
-}
 
-func TestConditionSet_Removals(t *testing.T) {
-	tests := []struct {
-		name         string
-		conditions   map[string][]string
-		removeByName []ConditionNames
-		removeSet    map[string][]string
-		byName       map[string][]string
-		byOrigin     map[string][]string
-	}{
-		{
-			name:         "emptybyname",
-			conditions:   map[string][]string{},
-			removeByName: []ConditionNames{{"reciprocal", "restricted"}},
-			byName: map[string][]string{
-				"notice":     []string{},
-				"restricted": []string{},
-			},
-			byOrigin: map[string][]string{
-				"bin1": []string{},
-				"lib1": []string{},
-				"bin2": []string{},
-				"lib2": []string{},
-			},
-		},
-		{
-			name:       "emptybyset",
-			conditions: map[string][]string{},
-			removeSet: map[string][]string{
-				"notice":     []string{"bin1", "bin2"},
-				"restricted": []string{"lib1", "lib2"},
-			},
-			byName: map[string][]string{
-				"notice":     []string{},
-				"restricted": []string{},
-			},
-			byOrigin: map[string][]string{
-				"bin1": []string{},
-				"lib1": []string{},
-				"bin2": []string{},
-				"lib2": []string{},
-			},
-		},
-		{
-			name: "everythingremovenone",
-			conditions: map[string][]string{
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
-			},
-			removeByName: []ConditionNames{{"permissive", "unencumbered"}},
-			removeSet: map[string][]string{
-				"notice": []string{"apk1"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"bin2":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"lib1":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"lib2":  []string{"notice", "reciprocal", "restricted", "by_exception_only"},
-				"other": []string{},
-			},
-		},
-		{
-			name: "everythingremovesome",
-			conditions: map[string][]string{
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
-			},
-			removeByName: []ConditionNames{{"restricted", "by_exception_only"}},
-			removeSet: map[string][]string{
-				"notice": []string{"lib1"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{"bin1", "bin2", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{},
-				"by_exception_only": []string{},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{"notice", "reciprocal"},
-				"bin2":  []string{"notice", "reciprocal"},
-				"lib1":  []string{"reciprocal"},
-				"lib2":  []string{"notice", "reciprocal"},
-				"other": []string{},
-			},
-		},
-		{
-			name: "everythingremoveall",
-			conditions: map[string][]string{
-				"notice":            []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted":        []string{"bin1", "bin2", "lib1", "lib2"},
-				"by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"},
-			},
-			removeByName: []ConditionNames{{"restricted", "by_exception_only"}},
-			removeSet: map[string][]string{
-				"notice":     []string{"bin1", "bin2", "lib1", "lib2"},
-				"reciprocal": []string{"bin1", "bin2", "lib1", "lib2"},
-				"restricted": []string{"bin1"},
-			},
-			byName: map[string][]string{
-				"permissive":        []string{},
-				"notice":            []string{},
-				"reciprocal":        []string{},
-				"restricted":        []string{},
-				"by_exception_only": []string{},
-			},
-			byOrigin: map[string][]string{
-				"bin1":  []string{},
-				"bin2":  []string{},
-				"lib1":  []string{},
-				"lib2":  []string{},
-				"other": []string{},
-			},
-		},
-	}
-	for _, tt := range tests {
+			actualConditions := actual.AsList()
+			if len(actualConditions) != len(expectedConditions) {
+				t.Errorf("len(actual.AsList()): got %d, want %d", len(actualConditions), len(expectedConditions))
+			} else {
+				for i := 0; i < len(actualConditions); i++ {
+					if actualConditions[i] != expectedConditions[i] {
+						t.Errorf("actual.AsList()[%d}: got %s, want %s",
+							i, actualConditions[i], expectedConditions[i])
+						break
+					}
+				}
+			}
+
+			if len(tt.expected) == 0 {
+				if !actual.IsEmpty() {
+					t.Errorf("actual.IsEmpty(): got false, want true")
+				}
+				if actual.MatchesAnySet(expected) {
+					t.Errorf("actual.MatchesAnySet({}): got true, want false")
+				}
+				if actual.MatchesEverySet(expected, expected) {
+					t.Errorf("actual.MatchesEverySet({}, {}): want false, got true")
+				}
+			} else {
+				if actual.IsEmpty() {
+					t.Errorf("actual.IsEmpty(): got true, want false")
+				}
+				if !actual.MatchesAnySet(expected) {
+					t.Errorf("actual.MatchesAnySet({all expected}): want true, got false")
+				}
+				if !actual.MatchesEverySet(expected, expected) {
+					t.Errorf("actual.MatchesEverySet({all expected}, {all expected}): want true, got false")
+				}
+			}
+
+			notExpected := (AllLicenseConditions &^ expected)
+			t.Logf("not expected license condition set: %04x %s", notExpected, notExpected.String())
+
+			if len(tt.expected) == 0 {
+				if actual.MatchesAnySet(expected, notExpected) {
+					t.Errorf("empty actual.MatchesAnySet({expected}, {not expected}): want false, got true")
+				}
+			} else {
+				if !actual.MatchesAnySet(expected, notExpected) {
+					t.Errorf("actual.MatchesAnySet({expected}, {not expected}): want true, got false")
+				}
+			}
+			if actual.MatchesAnySet(notExpected) {
+				t.Errorf("actual.MatchesAnySet({not expected}): want false, got true")
+			}
+			if actual.MatchesEverySet(notExpected) {
+				t.Errorf("actual.MatchesEverySet({not expected}): want false, got true")
+			}
+			if actual.MatchesEverySet(expected, notExpected) {
+				t.Errorf("actual.MatchesEverySet({expected}, {not expected}): want false, got true")
+			}
+
+			if !actual.Difference(expected).IsEmpty() {
+				t.Errorf("actual.Difference({expected}).IsEmpty(): want true, got false")
+			}
+			if expected != actual.Intersection(expected) {
+				t.Errorf("expected == actual.Intersection({expected}): want true, got false (%04x != %04x)", expected, actual.Intersection(expected))
+			}
+			if actual != actual.Intersection(expected) {
+				t.Errorf("actual == actual.Intersection({expected}): want true, got false (%04x != %04x)", actual, actual.Intersection(expected))
+			}
+			return true
+		}
+
 		t.Run(tt.name, func(t *testing.T) {
-			lg := newLicenseGraph()
-			cs := newLicenseConditionSet()
-			for name, origins := range tt.conditions {
-				for _, origin := range origins {
-					cs.add(newTestNode(lg, origin), name)
-				}
+			cs := populate()
+			if checkExpected(cs, t) {
+				checkMatching(cs, t)
 			}
-			if tt.removeByName != nil {
-				cs.RemoveAllByName(tt.removeByName...)
+			if checkExpectedSet(cs, t) {
+				checkMatchingSet(cs, t)
 			}
-			if tt.removeSet != nil {
-				other := newLicenseConditionSet()
-				for name, origins := range tt.removeSet {
-					for _, origin := range origins {
-						other.add(newTestNode(lg, origin), name)
-					}
-				}
-				cs.RemoveSet(other)
+		})
+
+		t.Run(tt.name+"_sets", func(t *testing.T) {
+			cs := populateSet()
+			if checkExpected(cs, t) {
+				checkMatching(cs, t)
 			}
-			byName(tt.byName).checkPublic(cs, t)
-			byOrigin(tt.byOrigin).checkPublic(lg, cs, t)
+			if checkExpectedSet(cs, t){
+				checkMatchingSet(cs, t)
+			}
+		})
+
+		t.Run(tt.name+"_plusset", func(t *testing.T) {
+			cs := populatePlusSet()
+			if checkExpected(cs, t) {
+				checkMatching(cs, t)
+			}
+			if checkExpectedSet(cs, t){
+				checkMatchingSet(cs, t)
+			}
+		})
+
+		t.Run(tt.name+"_minusset", func(t *testing.T) {
+			cs := populateMinusSet()
+			if checkExpected(cs, t) {
+				checkMatching(cs, t)
+			}
+			if checkExpectedSet(cs, t){
+				checkMatchingSet(cs, t)
+			}
 		})
 	}
 }
diff --git a/tools/compliance/graph.go b/tools/compliance/graph.go
index 9dcfa66..97fa657 100644
--- a/tools/compliance/graph.go
+++ b/tools/compliance/graph.go
@@ -52,30 +52,19 @@
 	// edges lists the directed edges in the graph from target to dependency. (guarded by mu)
 	//
 	// Alternatively, the graph is the set of `edges`.
-	edges []*dependencyEdge
+	edges TargetEdgeList
 
-	// targets identifies, indexes by name, and describes the entire set of target node files.
+	// targets identifies, indexes, and describes the entire set of target node files.
 	/// (guarded by mu)
 	targets map[string]*TargetNode
 
-	// index facilitates looking up edges from targets. (creation guarded by my)
-	//
-	// This is a forward index from target to dependencies. i.e. "top-down"
-	index map[string][]*dependencyEdge
+	// wgBU becomes non-nil when the bottom-up resolve begins and reaches 0
+	// (i.e. Wait() proceeds) when the bottom-up resolve completes. (guarded by mu)
+	wgBU *sync.WaitGroup
 
-	// rsBU caches the results of a full bottom-up resolve. (creation guarded by mu)
-	//
-	// A bottom-up resolve is a prerequisite for all of the top-down resolves so caching
-	// the result is a performance win.
-	rsBU *ResolutionSet
-
-	// rsTD caches the results of a full top-down resolve. (creation guarded by mu)
-	//
-	// A top-down resolve is a prerequisite for final resolutions.
-	// e.g. a shipped node inheriting a `restricted` condition from a parent through a
-	// dynamic dependency implies a notice dependency on the parent; even though, the
-	// distribution does not happen as a result of the dynamic dependency itself.
-	rsTD *ResolutionSet
+	// wgTD becomes non-nil when the top-down resolve begins and reaches 0 (i.e. Wait()
+	// proceeds) when the top-down resolve completes. (guarded by mu)
+	wgTD *sync.WaitGroup
 
 	// shippedNodes caches the results of a full walk of nodes identifying targets
 	// distributed either directly or as derivative works. (creation guarded by mu)
@@ -85,35 +74,18 @@
 	mu sync.Mutex
 }
 
-// TargetNode returns the target node identified by `name`.
-func (lg *LicenseGraph) TargetNode(name string) *TargetNode {
-	if _, ok := lg.targets[name]; !ok {
-		panic(fmt.Errorf("target node %q missing from graph", name))
-	}
-	return lg.targets[name]
-}
-
-// HasTargetNode returns true if a target node identified by `name` appears in
-// the graph.
-func (lg *LicenseGraph) HasTargetNode(name string) bool {
-	_, isPresent := lg.targets[name]
-	return isPresent
-}
-
 // Edges returns the list of edges in the graph. (unordered)
 func (lg *LicenseGraph) Edges() TargetEdgeList {
 	edges := make(TargetEdgeList, 0, len(lg.edges))
-	for _, e := range lg.edges {
-		edges = append(edges, TargetEdge{lg, e})
-	}
+	edges = append(edges, lg.edges...)
 	return edges
 }
 
 // Targets returns the list of target nodes in the graph. (unordered)
 func (lg *LicenseGraph) Targets() TargetNodeList {
 	targets := make(TargetNodeList, 0, len(lg.targets))
-	for target := range lg.targets {
-		targets = append(targets, lg.targets[target])
+	for _, target := range lg.targets {
+		targets = append(targets, target)
 	}
 	return targets
 }
@@ -124,33 +96,10 @@
 func newLicenseGraph() *LicenseGraph {
 	return &LicenseGraph{
 		rootFiles: []string{},
-		edges:     make([]*dependencyEdge, 0, 1000),
 		targets:   make(map[string]*TargetNode),
 	}
 }
 
-// indexForward guarantees the `index` map is populated to look up edges by
-// `target`.
-func (lg *LicenseGraph) indexForward() {
-	lg.mu.Lock()
-	defer func() {
-		lg.mu.Unlock()
-	}()
-
-	if lg.index != nil {
-		return
-	}
-
-	lg.index = make(map[string][]*dependencyEdge)
-	for _, e := range lg.edges {
-		if _, ok := lg.index[e.target]; ok {
-			lg.index[e.target] = append(lg.index[e.target], e)
-		} else {
-			lg.index[e.target] = []*dependencyEdge{e}
-		}
-	}
-}
-
 // TargetEdge describes a directed, annotated edge from a target to a
 // dependency. (immutable)
 //
@@ -159,25 +108,25 @@
 // i.e. `Target` depends on `Dependency` in the manner described by
 // `Annotations`.
 type TargetEdge struct {
-	// lg identifies the scope, i.e. license graph, in which the edge appears.
-	lg *LicenseGraph
+	// target and dependency identify the nodes connected by the edge.
+	target, dependency *TargetNode
 
-	// e identifies describes the target, dependency, and annotations of the edge.
-	e *dependencyEdge
+	// annotations identifies the set of compliance-relevant annotations describing the edge.
+	annotations TargetEdgeAnnotations
 }
 
 // Target identifies the target that depends on the dependency.
 //
 // Target needs Dependency to build.
-func (e TargetEdge) Target() *TargetNode {
-	return e.lg.targets[e.e.target]
+func (e *TargetEdge) Target() *TargetNode {
+	return e.target
 }
 
 // Dependency identifies the target depended on by the target.
 //
 // Dependency builds without Target, but Target needs Dependency to build.
-func (e TargetEdge) Dependency() *TargetNode {
-	return e.lg.targets[e.e.dependency]
+func (e *TargetEdge) Dependency() *TargetNode {
+	return e.dependency
 }
 
 // Annotations describes the type of edge by the set of annotations attached to
@@ -186,12 +135,17 @@
 // Only annotations prescribed by policy have any meaning for licensing, and
 // the meaning for licensing is likewise prescribed by policy. Other annotations
 // are preserved and ignored by policy.
-func (e TargetEdge) Annotations() TargetEdgeAnnotations {
-	return e.e.annotations
+func (e *TargetEdge) Annotations() TargetEdgeAnnotations {
+	return e.annotations
+}
+
+// String returns a human-readable string representation of the edge.
+func (e *TargetEdge) String() string {
+	return fmt.Sprintf("%s -[%s]> %s", e.target.name, strings.Join(e.annotations.AsList(), ", "), e.dependency.name)
 }
 
 // TargetEdgeList orders lists of edges by target then dependency then annotations.
-type TargetEdgeList []TargetEdge
+type TargetEdgeList []*TargetEdge
 
 // Len returns the count of the elmements in the list.
 func (l TargetEdgeList) Len() int      { return len(l) }
@@ -201,18 +155,63 @@
 
 // Less returns true when the `i`th element is lexicographically less than the `j`th.
 func (l TargetEdgeList) Less(i, j int) bool {
-	if l[i].e.target == l[j].e.target {
-		if l[i].e.dependency == l[j].e.dependency {
-			return l[i].e.annotations.Compare(l[j].e.annotations) < 0
-		}
-		return l[i].e.dependency < l[j].e.dependency
+	namei := l[i].target.name
+	namej := l[j].target.name
+	if namei == namej {
+		namei = l[i].dependency.name
+		namej = l[j].dependency.name
 	}
-	return l[i].e.target < l[j].e.target
+	if namei == namej {
+		return l[i].annotations.Compare(l[j].annotations) < 0
+	}
+	return namei < namej
+}
+
+// TargetEdgePathSegment describes a single arc in a TargetPath associating the
+// edge with a context `ctx` defined by whatever process is creating the path.
+type TargetEdgePathSegment struct {
+	edge *TargetEdge
+	ctx interface{}
+}
+
+// Target identifies the target that depends on the dependency.
+//
+// Target needs Dependency to build.
+func (s TargetEdgePathSegment) Target() *TargetNode {
+	return s.edge.target
+}
+
+// Dependency identifies the target depended on by the target.
+//
+// Dependency builds without Target, but Target needs Dependency to build.
+func (s TargetEdgePathSegment) Dependency() *TargetNode {
+	return s.edge.dependency
+}
+
+// Annotations describes the type of edge by the set of annotations attached to
+// it.
+//
+// Only annotations prescribed by policy have any meaning for licensing, and
+// the meaning for licensing is likewise prescribed by policy. Other annotations
+// are preserved and ignored by policy.
+func (s TargetEdgePathSegment) Annotations() TargetEdgeAnnotations {
+	return s.edge.annotations
+}
+
+// Context returns the context associated with the path segment. The type and
+// value of the context defined by the process creating the path.
+func (s TargetEdgePathSegment) Context() interface{} {
+	return s.ctx
+}
+
+// String returns a human-readable string representation of the edge.
+func (s TargetEdgePathSegment) String() string {
+	return fmt.Sprintf("%s -[%s]> %s", s.edge.target.name, strings.Join(s.edge.annotations.AsList(), ", "), s.edge.dependency.name)
 }
 
 // TargetEdgePath describes a sequence of edges starting at a root and ending
 // at some final dependency.
-type TargetEdgePath []TargetEdge
+type TargetEdgePath []TargetEdgePathSegment
 
 // NewTargetEdgePath creates a new, empty path with capacity `cap`.
 func NewTargetEdgePath(cap int) *TargetEdgePath {
@@ -222,15 +221,15 @@
 
 // Push appends a new edge to the list verifying that the target of the new
 // edge is the dependency of the prior.
-func (p *TargetEdgePath) Push(edge TargetEdge) {
+func (p *TargetEdgePath) Push(edge *TargetEdge, ctx interface{}) {
 	if len(*p) == 0 {
-		*p = append(*p, edge)
+		*p = append(*p, TargetEdgePathSegment{edge, ctx})
 		return
 	}
-	if (*p)[len(*p)-1].e.dependency != edge.e.target {
-		panic(fmt.Errorf("disjoint path %s does not end at %s", p.String(), edge.e.target))
+	if (*p)[len(*p)-1].edge.dependency != edge.target {
+		panic(fmt.Errorf("disjoint path %s does not end at %s", p.String(), edge.target.name))
 	}
-	*p = append(*p, edge)
+	*p = append(*p, TargetEdgePathSegment{edge, ctx})
 }
 
 // Pop shortens the path by 1 edge.
@@ -256,10 +255,11 @@
 	}
 	var sb strings.Builder
 	fmt.Fprintf(&sb, "[")
-	for _, e := range *p {
-		fmt.Fprintf(&sb, "%s -> ", e.e.target)
+	for _, s := range *p {
+		fmt.Fprintf(&sb, "%s -> ", s.edge.target.name)
 	}
-	fmt.Fprintf(&sb, "%s]", (*p)[len(*p)-1].e.dependency)
+	lastSegment := (*p)[len(*p)-1]
+	fmt.Fprintf(&sb, "%s]", lastSegment.edge.dependency.name)
 	return sb.String()
 }
 
@@ -279,6 +279,13 @@
 	return tn.name
 }
 
+// Dependencies returns the list of edges to dependencies of `tn`.
+func (tn *TargetNode) Dependencies() TargetEdgeList {
+	edges := make(TargetEdgeList, 0, len(tn.edges))
+	edges = append(edges, tn.edges...)
+	return edges
+}
+
 // PackageName returns the string that identifes the package for the target.
 func (tn *TargetNode) PackageName() string {
 	return tn.proto.GetPackageName()
@@ -323,10 +330,8 @@
 // is a matter of policy. (unordered)
 //
 // e.g. notice or proprietary
-func (tn *TargetNode) LicenseConditions() *LicenseConditionSet {
-	result := newLicenseConditionSet()
-	result.add(tn, tn.proto.LicenseConditions...)
-	return result
+func (tn *TargetNode) LicenseConditions() LicenseConditionSet {
+	return tn.licenseConditions
 }
 
 // LicenseTexts returns the paths to the files containing the license texts for
@@ -387,12 +392,12 @@
 // Annotations typically distinguish between static linkage versus dynamic
 // versus tools that are used at build time but are not linked in any way.
 type TargetEdgeAnnotations struct {
-	annotations map[string]bool
+	annotations map[string]struct{}
 }
 
 // newEdgeAnnotations creates a new instance of TargetEdgeAnnotations.
 func newEdgeAnnotations() TargetEdgeAnnotations {
-	return TargetEdgeAnnotations{make(map[string]bool)}
+	return TargetEdgeAnnotations{make(map[string]struct{})}
 }
 
 // HasAnnotation returns true if an annotation `ann` is in the set.
@@ -439,7 +444,7 @@
 
 // TargetNodeSet describes a set of distinct nodes in a license graph.
 type TargetNodeSet struct {
-	nodes map[*TargetNode]bool
+	nodes map[*TargetNode]struct{}
 }
 
 // Contains returns true when `target` is an element of the set.
@@ -466,6 +471,11 @@
 	return result
 }
 
+// String returns a human-readable string representation of the set.
+func (ts *TargetNodeSet) String() string {
+	return fmt.Sprintf("{%s}", strings.Join(ts.Names(), ", "))
+}
+
 // TargetNodeList orders a list of targets by name.
 type TargetNodeList []*TargetNode
 
diff --git a/tools/compliance/policy/policy.go b/tools/compliance/policy/policy.go
index d3e412b..581912a 100644
--- a/tools/compliance/policy/policy.go
+++ b/tools/compliance/policy/policy.go
@@ -30,31 +30,33 @@
 	}
 
 	// ImpliesUnencumbered lists the condition names representing an author attempt to disclaim copyright.
-	ImpliesUnencumbered = ConditionNames{"unencumbered"}
+	ImpliesUnencumbered = LicenseConditionSet(UnencumberedCondition)
 
 	// ImpliesPermissive lists the condition names representing copyrighted but "licensed without policy requirements".
-	ImpliesPermissive = ConditionNames{"permissive"}
+	ImpliesPermissive = LicenseConditionSet(PermissiveCondition)
 
 	// ImpliesNotice lists the condition names implying a notice or attribution policy.
-	ImpliesNotice = ConditionNames{"unencumbered", "permissive", "notice", "reciprocal", "restricted", "proprietary", "by_exception_only"}
+	ImpliesNotice = LicenseConditionSet(UnencumberedCondition | PermissiveCondition | NoticeCondition | ReciprocalCondition |
+			RestrictedCondition | RestrictedClasspathExceptionCondition | WeaklyRestrictedCondition |
+			ProprietaryCondition | ByExceptionOnlyCondition)
 
 	// ImpliesReciprocal lists the condition names implying a local source-sharing policy.
-	ImpliesReciprocal = ConditionNames{"reciprocal"}
+	ImpliesReciprocal = LicenseConditionSet(ReciprocalCondition)
 
 	// Restricted lists the condition names implying an infectious source-sharing policy.
-	ImpliesRestricted = ConditionNames{"restricted"}
+	ImpliesRestricted = LicenseConditionSet(RestrictedCondition | RestrictedClasspathExceptionCondition | WeaklyRestrictedCondition)
 
 	// ImpliesProprietary lists the condition names implying a confidentiality policy.
-	ImpliesProprietary = ConditionNames{"proprietary"}
+	ImpliesProprietary = LicenseConditionSet(ProprietaryCondition)
 
 	// ImpliesByExceptionOnly lists the condition names implying a policy for "license review and approval before use".
-	ImpliesByExceptionOnly = ConditionNames{"proprietary", "by_exception_only"}
+	ImpliesByExceptionOnly = LicenseConditionSet(ProprietaryCondition | ByExceptionOnlyCondition)
 
 	// ImpliesPrivate lists the condition names implying a source-code privacy policy.
-	ImpliesPrivate = ConditionNames{"proprietary"}
+	ImpliesPrivate = LicenseConditionSet(ProprietaryCondition)
 
 	// ImpliesShared lists the condition names implying a source-code sharing policy.
-	ImpliesShared = ConditionNames{"reciprocal", "restricted"}
+	ImpliesShared = LicenseConditionSet(ReciprocalCondition | RestrictedCondition | RestrictedClasspathExceptionCondition | WeaklyRestrictedCondition)
 )
 
 var (
@@ -64,100 +66,117 @@
 	ccBySa       = regexp.MustCompile(`^SPDX-license-identifier-CC-BY.*-SA.*`)
 )
 
-// Resolution happens in two passes:
+
+// LicenseConditionSetFromNames returns a set containing the recognized `names` and
+// silently ignoring or discarding the unrecognized `names`.
+func LicenseConditionSetFromNames(tn *TargetNode, names ...string) LicenseConditionSet {
+	cs := NewLicenseConditionSet()
+	for _, name := range names {
+		if name == "restricted" {
+			if 0 == len(tn.LicenseKinds()) {
+				cs = cs.Plus(RestrictedCondition)
+				continue
+			}
+			hasLgpl := false
+			hasClasspath := false
+			hasGeneric := false
+			for _, kind := range tn.LicenseKinds() {
+				if strings.HasSuffix(kind, "-with-classpath-exception") {
+					cs = cs.Plus(RestrictedClasspathExceptionCondition)
+					hasClasspath = true
+				} else if anyLgpl.MatchString(kind) {
+					cs = cs.Plus(WeaklyRestrictedCondition)
+					hasLgpl = true
+				} else if versionedGpl.MatchString(kind) {
+					cs = cs.Plus(RestrictedCondition)
+				} else if genericGpl.MatchString(kind) {
+					hasGeneric = true
+				} else if kind == "legacy_restricted" || ccBySa.MatchString(kind) {
+					cs = cs.Plus(RestrictedCondition)
+				} else {
+					cs = cs.Plus(RestrictedCondition)
+				}
+			}
+			if hasGeneric && !hasLgpl && !hasClasspath {
+				cs = cs.Plus(RestrictedCondition)
+			}
+			continue
+		}
+		if lc, ok := RecognizedConditionNames[name]; ok {
+			cs |= LicenseConditionSet(lc)
+		}
+	}
+	return cs
+}
+
+
+// Resolution happens in three phases:
 //
-// 1. A bottom-up traversal propagates license conditions up to targets from
-// dendencies as needed.
+// 1. A bottom-up traversal propagates (restricted) license conditions up to
+// targets from dendencies as needed.
 //
-// 2. For each condition of interest, a top-down traversal adjusts the attached
-// conditions pushing restricted down from targets into linked dependencies.
+// 2. For each condition of interest, a top-down traversal propagates
+// (restricted) conditions down from targets into linked dependencies.
 //
-// The behavior of the 2 passes gets controlled by the 2 functions below.
+// 3. Finally, a walk of the shipped target nodes attaches resolutions to the
+// ancestor nodes from the root down to and including the first non-container.
 //
-// The first function controls what happens during the bottom-up traversal. In
-// general conditions flow up through static links but not other dependencies;
-// except, restricted sometimes flows up through dynamic links.
+// e.g. If a disk image contains a binary bin1 that links a library liba, the
+// notice requirement for liba gets attached to the disk image and to bin1.
+// Because liba doesn't actually get shipped as a separate artifact, but only
+// as bits in bin1, it has no actions 'attached' to it. The actions attached
+// to the image and to bin1 'act on' liba by providing notice.
 //
-// In general, too, the originating target gets acted on to resolve the
-// condition (e.g. providing notice), but again restricted is special in that
-// it requires acting on (i.e. sharing source of) both the originating module
-// and the target using the module.
+// The behavior of the 3 phases gets controlled by the 3 functions below.
 //
-// The latter function controls what happens during the top-down traversal. In
-// general, only restricted conditions flow down at all, and only through
-// static links.
+// The first function controls what happens during the bottom-up propagation.
+// Restricted conditions propagate up all non-toolchain dependencies; except,
+// some do not propagate up dynamic links, which may depend on whether the
+// modules are independent.
+//
+// The second function controls what happens during the top-down propagation.
+// Restricted conditions propagate down as above with the added caveat that
+// inherited restricted conditions do not propagate from pure aggregates to
+// their dependencies.
+//
+// The final function controls which conditions apply/get attached to ancestors
+// depending on the types of dependencies involved. All conditions apply across
+// normal derivation dependencies. No conditions apply across toolchain
+// dependencies. Some restricted conditions apply across dynamic link
+// dependencies.
 //
 // Not all restricted licenses are create equal. Some have special rules or
 // exceptions. e.g. LGPL or "with classpath excption".
 
-// depActionsApplicableToTarget returns the actions which propagate up an
+
+// depConditionsPropagatingToTarget returns the conditions which propagate up an
 // edge from dependency to target.
 //
-// This function sets the policy for the bottom-up traversal and how conditions
+// This function sets the policy for the bottom-up propagation and how conditions
 // flow up the graph from dependencies to targets.
 //
 // If a pure aggregation is built into a derivative work that is not a pure
 // aggregation, per policy it ceases to be a pure aggregation in the context of
 // that derivative work. The `treatAsAggregate` parameter will be false for
 // non-aggregates and for aggregates in non-aggregate contexts.
-func depActionsApplicableToTarget(e TargetEdge, depActions actionSet, treatAsAggregate bool) actionSet {
-	result := make(actionSet)
+func depConditionsPropagatingToTarget(lg *LicenseGraph, e *TargetEdge, depConditions LicenseConditionSet, treatAsAggregate bool) LicenseConditionSet {
+	result := LicenseConditionSet(0x0000)
 	if edgeIsDerivation(e) {
-		result.addSet(depActions)
-		for _, cs := range depActions.byName(ImpliesRestricted) {
-			result.add(e.Target(), cs)
-		}
+		result |= depConditions & ImpliesRestricted
 		return result
 	}
 	if !edgeIsDynamicLink(e) {
 		return result
 	}
 
-	restricted := depActions.byName(ImpliesRestricted)
-	for actsOn, cs := range restricted {
-		for _, lc := range cs.AsList() {
-			hasGpl := false
-			hasLgpl := false
-			hasClasspath := false
-			hasGeneric := false
-			hasOther := false
-			for _, kind := range lc.origin.LicenseKinds() {
-				if strings.HasSuffix(kind, "-with-classpath-exception") {
-					hasClasspath = true
-				} else if anyLgpl.MatchString(kind) {
-					hasLgpl = true
-				} else if versionedGpl.MatchString(kind) {
-					hasGpl = true
-				} else if genericGpl.MatchString(kind) {
-					hasGeneric = true
-				} else if kind == "legacy_restricted" || ccBySa.MatchString(kind) {
-					hasOther = true
-				}
-			}
-			if hasOther || hasGpl {
-				result.addCondition(actsOn, lc)
-				result.addCondition(e.Target(), lc)
-				continue
-			}
-			if hasClasspath && !edgeNodesAreIndependentModules(e) {
-				result.addCondition(actsOn, lc)
-				result.addCondition(e.Target(), lc)
-				continue
-			}
-			if hasLgpl || hasClasspath {
-				continue
-			}
-			if !hasGeneric {
-				continue
-			}
-			result.addCondition(actsOn, lc)
-			result.addCondition(e.Target(), lc)
-		}
+	result |= depConditions & LicenseConditionSet(RestrictedCondition)
+	if 0 != (depConditions & LicenseConditionSet(RestrictedClasspathExceptionCondition)) && !edgeNodesAreIndependentModules(e) {
+		result |= LicenseConditionSet(RestrictedClasspathExceptionCondition)
 	}
 	return result
 }
 
-// targetConditionsApplicableToDep returns the conditions which propagate down
+// targetConditionsPropagatingToDep returns the conditions which propagate down
 // an edge from target to dependency.
 //
 // This function sets the policy for the top-down traversal and how conditions
@@ -167,81 +186,73 @@
 // aggregation, per policy it ceases to be a pure aggregation in the context of
 // that derivative work. The `treatAsAggregate` parameter will be false for
 // non-aggregates and for aggregates in non-aggregate contexts.
-func targetConditionsApplicableToDep(e TargetEdge, targetConditions *LicenseConditionSet, treatAsAggregate bool) *LicenseConditionSet {
-	result := targetConditions.Copy()
+func targetConditionsPropagatingToDep(lg *LicenseGraph, e *TargetEdge, targetConditions LicenseConditionSet, treatAsAggregate bool) LicenseConditionSet {
+	result := targetConditions
 
 	// reverse direction -- none of these apply to things depended-on, only to targets depending-on.
-	result.RemoveAllByName(ConditionNames{"unencumbered", "permissive", "notice", "reciprocal", "proprietary", "by_exception_only"})
+	result = result.Minus(UnencumberedCondition, PermissiveCondition, NoticeCondition, ReciprocalCondition, ProprietaryCondition, ByExceptionOnlyCondition)
 
 	if !edgeIsDerivation(e) && !edgeIsDynamicLink(e) {
 		// target is not a derivative work of dependency and is not linked to dependency
-		result.RemoveAllByName(ImpliesRestricted)
+		result = result.Difference(ImpliesRestricted)
 		return result
 	}
 	if treatAsAggregate {
 		// If the author of a pure aggregate licenses it restricted, apply restricted to immediate dependencies.
 		// Otherwise, restricted does not propagate back down to dependencies.
-		restricted := result.ByName(ImpliesRestricted).AsList()
-		for _, lc := range restricted {
-			if lc.origin.name != e.e.target {
-				result.Remove(lc)
-			}
+		if !LicenseConditionSetFromNames(e.target, e.target.proto.LicenseConditions...).MatchesAnySet(ImpliesRestricted) {
+			result = result.Difference(ImpliesRestricted)
 		}
 		return result
 	}
 	if edgeIsDerivation(e) {
 		return result
 	}
-	restricted := result.ByName(ImpliesRestricted).AsList()
-	for _, lc := range restricted {
-		hasGpl := false
-		hasLgpl := false
-		hasClasspath := false
-		hasGeneric := false
-		hasOther := false
-		for _, kind := range lc.origin.LicenseKinds() {
-			if strings.HasSuffix(kind, "-with-classpath-exception") {
-				hasClasspath = true
-			} else if anyLgpl.MatchString(kind) {
-				hasLgpl = true
-			} else if versionedGpl.MatchString(kind) {
-				hasGpl = true
-			} else if genericGpl.MatchString(kind) {
-				hasGeneric = true
-			} else if kind == "legacy_restricted" || ccBySa.MatchString(kind) {
-				hasOther = true
-			}
-		}
-		if hasOther || hasGpl {
-			continue
-		}
-		if hasClasspath && !edgeNodesAreIndependentModules(e) {
-			continue
-		}
-		if hasGeneric && !hasLgpl && !hasClasspath {
-			continue
-		}
-		result.Remove(lc)
+	result = result.Minus(WeaklyRestrictedCondition)
+	if edgeNodesAreIndependentModules(e) {
+		result = result.Minus(RestrictedClasspathExceptionCondition)
 	}
 	return result
 }
 
+// conditionsAttachingAcrossEdge returns the subset of conditions in `universe`
+// that apply across edge `e`.
+//
+// This function sets the policy for attaching actions to ancestor nodes in the
+// final resolution walk.
+func conditionsAttachingAcrossEdge(lg *LicenseGraph, e *TargetEdge, universe LicenseConditionSet) LicenseConditionSet {
+	result := universe
+	if edgeIsDerivation(e) {
+		return result
+	}
+	if !edgeIsDynamicLink(e) {
+		return NewLicenseConditionSet()
+	}
+
+	result &= LicenseConditionSet(RestrictedCondition | RestrictedClasspathExceptionCondition)
+	if 0 != (result & LicenseConditionSet(RestrictedClasspathExceptionCondition)) && edgeNodesAreIndependentModules(e) {
+		result &= LicenseConditionSet(RestrictedCondition)
+	}
+	return result
+}
+
+
 // edgeIsDynamicLink returns true for edges representing shared libraries
 // linked dynamically at runtime.
-func edgeIsDynamicLink(e TargetEdge) bool {
-	return e.e.annotations.HasAnnotation("dynamic")
+func edgeIsDynamicLink(e *TargetEdge) bool {
+	return e.annotations.HasAnnotation("dynamic")
 }
 
 // edgeIsDerivation returns true for edges where the target is a derivative
 // work of dependency.
-func edgeIsDerivation(e TargetEdge) bool {
-	isDynamic := e.e.annotations.HasAnnotation("dynamic")
-	isToolchain := e.e.annotations.HasAnnotation("toolchain")
+func edgeIsDerivation(e *TargetEdge) bool {
+	isDynamic := e.annotations.HasAnnotation("dynamic")
+	isToolchain := e.annotations.HasAnnotation("toolchain")
 	return !isDynamic && !isToolchain
 }
 
 // edgeNodesAreIndependentModules returns true for edges where the target and
 // dependency are independent modules.
-func edgeNodesAreIndependentModules(e TargetEdge) bool {
-	return e.Target().PackageName() != e.Dependency().PackageName()
+func edgeNodesAreIndependentModules(e *TargetEdge) bool {
+	return e.target.PackageName() != e.dependency.PackageName()
 }
diff --git a/tools/compliance/policy/policy_test.go b/tools/compliance/policy/policy_test.go
index aea307f..09e831c 100644
--- a/tools/compliance/policy/policy_test.go
+++ b/tools/compliance/policy/policy_test.go
@@ -34,21 +34,21 @@
 		{
 			name:                     "firstparty",
 			edge:                     annotated{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"apacheLib.meta_lic:apacheLib.meta_lic:notice"},
+			expectedDepActions:       []string{},
 			expectedTargetConditions: []string{},
 		},
 		{
 			name:                     "notice",
 			edge:                     annotated{"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"mitLib.meta_lic:mitLib.meta_lic:notice"},
+			expectedDepActions:       []string{},
 			expectedTargetConditions: []string{},
 		},
 		{
 			name: "fponlgpl",
 			edge: annotated{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
 			expectedDepActions: []string{
-				"apacheBin.meta_lic:lgplLib.meta_lic:restricted",
-				"lgplLib.meta_lic:lgplLib.meta_lic:restricted",
+				"apacheBin.meta_lic:lgplLib.meta_lic:restricted_allows_dynamic_linking",
+				"lgplLib.meta_lic:lgplLib.meta_lic:restricted_allows_dynamic_linking",
 			},
 			expectedTargetConditions: []string{},
 		},
@@ -86,8 +86,8 @@
 			name: "independentmodulestatic",
 			edge: annotated{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
 			expectedDepActions: []string{
-				"apacheBin.meta_lic:gplWithClasspathException.meta_lic:restricted",
-				"gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted",
+				"apacheBin.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception",
+				"gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception",
 			},
 			expectedTargetConditions: []string{},
 		},
@@ -95,8 +95,8 @@
 			name: "dependentmodule",
 			edge: annotated{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
 			expectedDepActions: []string{
-				"dependentModule.meta_lic:gplWithClasspathException.meta_lic:restricted",
-				"gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted",
+				"dependentModule.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception",
+				"gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception",
 			},
 			expectedTargetConditions: []string{},
 		},
@@ -104,8 +104,8 @@
 		{
 			name:                     "lgplonfp",
 			edge:                     annotated{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"apacheLib.meta_lic:apacheLib.meta_lic:notice"},
-			expectedTargetConditions: []string{"lgplBin.meta_lic:restricted"},
+			expectedDepActions:       []string{},
+			expectedTargetConditions: []string{"lgplBin.meta_lic:restricted_allows_dynamic_linking"},
 		},
 		{
 			name:                     "lgplonfpdynamic",
@@ -116,14 +116,14 @@
 		{
 			name:                     "gplonfp",
 			edge:                     annotated{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"apacheLib.meta_lic:apacheLib.meta_lic:notice"},
+			expectedDepActions:       []string{},
 			expectedTargetConditions: []string{"gplBin.meta_lic:restricted"},
 		},
 		{
 			name:                     "gplcontainer",
 			edge:                     annotated{"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
 			treatAsAggregate:         true,
-			expectedDepActions:       []string{"apacheLib.meta_lic:apacheLib.meta_lic:notice"},
+			expectedDepActions:       []string{},
 			expectedTargetConditions: []string{"gplContainer.meta_lic:restricted"},
 		},
 		{
@@ -133,7 +133,6 @@
 			otherCondition:   "gplLib.meta_lic:restricted",
 			expectedDepActions: []string{
 				"apacheContainer.meta_lic:gplLib.meta_lic:restricted",
-				"apacheLib.meta_lic:apacheLib.meta_lic:notice",
 				"apacheLib.meta_lic:gplLib.meta_lic:restricted",
 				"gplLib.meta_lic:gplLib.meta_lic:restricted",
 			},
@@ -146,7 +145,6 @@
 			otherCondition:   "gplLib.meta_lic:restricted",
 			expectedDepActions: []string{
 				"apacheBin.meta_lic:gplLib.meta_lic:restricted",
-				"apacheLib.meta_lic:apacheLib.meta_lic:notice",
 				"apacheLib.meta_lic:gplLib.meta_lic:restricted",
 				"gplLib.meta_lic:gplLib.meta_lic:restricted",
 			},
@@ -167,14 +165,14 @@
 		{
 			name:                     "independentmodulereversestatic",
 			edge:                     annotated{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"apacheBin.meta_lic:apacheBin.meta_lic:notice"},
-			expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted"},
+			expectedDepActions:       []string{},
+			expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted_with_classpath_exception"},
 		},
 		{
 			name:                     "dependentmodulereverse",
 			edge:                     annotated{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
 			expectedDepActions:       []string{},
-			expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted"},
+			expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted_with_classpath_exception"},
 		},
 		{
 			name: "ponr",
@@ -188,31 +186,31 @@
 		{
 			name:                     "ronp",
 			edge:                     annotated{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"proprietary.meta_lic:proprietary.meta_lic:proprietary"},
+			expectedDepActions:       []string{},
 			expectedTargetConditions: []string{"gplBin.meta_lic:restricted"},
 		},
 		{
 			name:                     "noticeonb_e_o",
 			edge:                     annotated{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"by_exception.meta_lic:by_exception.meta_lic:by_exception_only"},
+			expectedDepActions:       []string{},
 			expectedTargetConditions: []string{},
 		},
 		{
 			name:                     "b_e_oonnotice",
 			edge:                     annotated{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"mitLib.meta_lic:mitLib.meta_lic:notice"},
+			expectedDepActions:       []string{},
 			expectedTargetConditions: []string{},
 		},
 		{
 			name:                     "noticeonrecip",
 			edge:                     annotated{"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"mplLib.meta_lic:mplLib.meta_lic:reciprocal"},
+			expectedDepActions:       []string{},
 			expectedTargetConditions: []string{},
 		},
 		{
 			name:                     "reciponnotice",
 			edge:                     annotated{"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
-			expectedDepActions:       []string{"mitLib.meta_lic:mitLib.meta_lic:notice"},
+			expectedDepActions:       []string{},
 			expectedTargetConditions: []string{},
 		},
 	}
@@ -231,69 +229,80 @@
 				t.Errorf("unexpected error reading graph: %w", err)
 				return
 			}
+			edge := lg.Edges()[0]
 			// simulate a condition inherited from another edge/dependency.
 			otherTarget := ""
 			otherCondition := ""
+			var otn *TargetNode
 			if len(tt.otherCondition) > 0 {
 				fields := strings.Split(tt.otherCondition, ":")
 				otherTarget = fields[0]
 				otherCondition = fields[1]
+				otn = &TargetNode{name: otherTarget}
 				// other target must exist in graph
-				lg.targets[otherTarget] = &TargetNode{name: otherTarget}
-				lg.targets[otherTarget].proto.LicenseConditions = append(lg.targets[otherTarget].proto.LicenseConditions, otherCondition)
+				lg.targets[otherTarget] = otn
+				otn.licenseConditions = LicenseConditionSet(RecognizedConditionNames[otherCondition])
+			}
+			targets := make(map[string]*TargetNode)
+			targets[edge.target.name] = edge.target
+			targets[edge.dependency.name] = edge.dependency
+			if otn != nil {
+				targets[otn.name] = otn
 			}
 			if tt.expectedDepActions != nil {
-				depActions := make(actionSet)
-				depActions[lg.targets[tt.edge.dep]] = lg.targets[tt.edge.dep].LicenseConditions()
-				if otherTarget != "" {
-					// simulate a sub-dependency's condition having already propagated up to dep and about to go to target
-					otherCs := lg.targets[otherTarget].LicenseConditions()
-					depActions[lg.targets[tt.edge.dep]].AddSet(otherCs)
-					depActions[lg.targets[otherTarget]] = otherCs
-				}
-				asActual := depActionsApplicableToTarget(lg.Edges()[0], depActions, tt.treatAsAggregate)
-				asExpected := make(actionSet)
-				for _, triple := range tt.expectedDepActions {
-					fields := strings.Split(triple, ":")
-					actsOn := lg.targets[fields[0]]
-					origin := lg.targets[fields[1]]
-					expectedConditions := newLicenseConditionSet()
-					expectedConditions.add(origin, fields[2:]...)
-					if _, ok := asExpected[actsOn]; ok {
-						asExpected[actsOn].AddSet(expectedConditions)
-					} else {
-						asExpected[actsOn] = expectedConditions
+				t.Run("depConditionsPropagatingToTarget", func(t *testing.T) {
+					depConditions := edge.dependency.LicenseConditions()
+					if otherTarget != "" {
+						// simulate a sub-dependency's condition having already propagated up to dep and about to go to target
+						otherCs := otn.LicenseConditions()
+						depConditions |= otherCs
 					}
-				}
-
-				checkSameActions(lg, asActual, asExpected, t)
+					t.Logf("calculate target actions for edge=%s, dep conditions=%04x, treatAsAggregate=%v", edge.String(), depConditions, tt.treatAsAggregate)
+					csActual := depConditionsPropagatingToTarget(lg, edge, depConditions, tt.treatAsAggregate)
+					t.Logf("calculated target conditions as %04x{%s}", csActual, strings.Join(csActual.Names(), ", "))
+					csExpected := NewLicenseConditionSet()
+					for _, triple := range tt.expectedDepActions {
+						fields := strings.Split(triple, ":")
+						expectedConditions := NewLicenseConditionSet()
+						for _, cname := range fields[2:] {
+							expectedConditions = expectedConditions.Plus(RecognizedConditionNames[cname])
+						}
+						csExpected |= expectedConditions
+					}
+					t.Logf("expected target conditions as %04x{%s}", csExpected, strings.Join(csExpected.Names(), ", "))
+					if csActual != csExpected {
+						t.Errorf("unexpected license conditions: got %04x, want %04x", csActual, csExpected)
+					}
+				})
 			}
 			if tt.expectedTargetConditions != nil {
-				targetConditions := lg.TargetNode(tt.edge.target).LicenseConditions()
-				if otherTarget != "" {
-					targetConditions.add(lg.targets[otherTarget], otherCondition)
-				}
-				cs := targetConditionsApplicableToDep(
-					lg.Edges()[0],
-					targetConditions,
-					tt.treatAsAggregate)
-				actual := make([]string, 0, cs.Count())
-				for _, lc := range cs.AsList() {
-					actual = append(actual, lc.asString(":"))
-				}
-				sort.Strings(actual)
-				sort.Strings(tt.expectedTargetConditions)
-				if len(actual) != len(tt.expectedTargetConditions) {
-					t.Errorf("unexpected number of target conditions: got %v with %d conditions, want %v with %d conditions",
-						actual, len(actual), tt.expectedTargetConditions, len(tt.expectedTargetConditions))
-				} else {
-					for i := 0; i < len(actual); i++ {
-						if actual[i] != tt.expectedTargetConditions[i] {
-							t.Errorf("unexpected target condition at element %d: got %q, want %q",
-								i, actual[i], tt.expectedTargetConditions[i])
+				t.Run("targetConditionsPropagatingToDep", func(t *testing.T) {
+					targetConditions := edge.target.LicenseConditions()
+					if otherTarget != "" {
+						targetConditions = targetConditions.Union(otn.licenseConditions)
+					}
+					t.Logf("calculate dep conditions for edge=%s, target conditions=%v, treatAsAggregate=%v", edge.String(), targetConditions.Names(), tt.treatAsAggregate)
+					cs := targetConditionsPropagatingToDep(lg, edge, targetConditions, tt.treatAsAggregate)
+					t.Logf("calculated dep conditions as %v", cs.Names())
+					actual := cs.Names()
+					sort.Strings(actual)
+					expected := make([]string, 0)
+					for _, expectedDepCondition := range tt.expectedTargetConditions {
+						expected = append(expected, strings.Split(expectedDepCondition, ":")[1])
+					}
+					sort.Strings(expected)
+					if len(actual) != len(expected) {
+						t.Errorf("unexpected number of target conditions: got %v with %d conditions, want %v with %d conditions",
+							actual, len(actual), expected, len(expected))
+					} else {
+						for i := 0; i < len(actual); i++ {
+							if actual[i] != expected[i] {
+								t.Errorf("unexpected target condition at element %d: got %q, want %q",
+									i, actual[i], expected[i])
+							}
 						}
 					}
-				}
+				})
 			}
 		})
 	}
diff --git a/tools/compliance/policy/resolve.go b/tools/compliance/policy/resolve.go
index 58547f8..336894a 100644
--- a/tools/compliance/policy/resolve.go
+++ b/tools/compliance/policy/resolve.go
@@ -14,228 +14,196 @@
 
 package compliance
 
+import (
+	"sync"
+)
+
 // ResolveBottomUpConditions performs a bottom-up walk of the LicenseGraph
 // propagating conditions up the graph as necessary according to the properties
 // of each edge and according to each license condition in question.
 //
-// Subsequent top-down walks of the graph will filter some resolutions and may
-// introduce new resolutions.
-//
 // e.g. if a "restricted" condition applies to a binary, it also applies to all
 // of the statically-linked libraries and the transitive closure of their static
 // dependencies; even if neither they nor the transitive closure of their
 // dependencies originate any "restricted" conditions. The bottom-up walk will
 // not resolve the library and its transitive closure, but the later top-down
 // walk will.
-func ResolveBottomUpConditions(lg *LicenseGraph) *ResolutionSet {
+func ResolveBottomUpConditions(lg *LicenseGraph) {
 
 	// short-cut if already walked and cached
 	lg.mu.Lock()
-	rs := lg.rsBU
+	wg := lg.wgBU
+
+	if wg != nil {
+		lg.mu.Unlock()
+		wg.Wait()
+		return
+	}
+	wg = &sync.WaitGroup{}
+	wg.Add(1)
+	lg.wgBU = wg
 	lg.mu.Unlock()
 
-	if rs != nil {
-		return rs
+	// amap identifes targets previously walked. (guarded by mu)
+	amap := make(map[*TargetNode]struct{})
+
+	// cmap identifies targets previously walked as pure aggregates. i.e. as containers
+	// (guarded by mu)
+	cmap := make(map[*TargetNode]struct{})
+	var mu sync.Mutex
+
+	var walk func(target *TargetNode, treatAsAggregate bool) LicenseConditionSet
+
+	walk = func(target *TargetNode, treatAsAggregate bool) LicenseConditionSet {
+		priorWalkResults := func() (LicenseConditionSet, bool) {
+			mu.Lock()
+			defer mu.Unlock()
+
+			if _, alreadyWalked := amap[target]; alreadyWalked {
+				if treatAsAggregate {
+					return target.resolution, true
+				}
+				if _, asAggregate := cmap[target]; !asAggregate {
+					return target.resolution, true
+				}
+				// previously walked in a pure aggregate context,
+				// needs to walk again in non-aggregate context
+				delete(cmap, target)
+			} else {
+				target.resolution |= target.licenseConditions
+				amap[target] = struct{}{}
+			}
+			if treatAsAggregate {
+				cmap[target] = struct{}{}
+			}
+			return target.resolution, false
+		}
+		cs, alreadyWalked := priorWalkResults()
+		if alreadyWalked {
+			return cs
+		}
+
+		c := make(chan LicenseConditionSet, len(target.edges))
+		// add all the conditions from all the dependencies
+		for _, edge := range target.edges {
+			go func(edge *TargetEdge) {
+				// walk dependency to get its conditions
+				cs := walk(edge.dependency, treatAsAggregate && edge.dependency.IsContainer())
+
+				// turn those into the conditions that apply to the target
+				cs = depConditionsPropagatingToTarget(lg, edge, cs, treatAsAggregate)
+
+				c <- cs
+			}(edge)
+		}
+		for i := 0; i < len(target.edges); i++ {
+			cs |= <-c
+		}
+		mu.Lock()
+		target.resolution |= cs
+		mu.Unlock()
+
+		// return conditions up the tree
+		return cs
 	}
 
-	// must be indexed for fast lookup
-	lg.indexForward()
-
-	rs = resolveBottomUp(lg, make(map[*TargetNode]actionSet) /* empty map; no prior resolves */)
-
-	// if not yet cached, save the result
-	lg.mu.Lock()
-	if lg.rsBU == nil {
-		lg.rsBU = rs
-	} else {
-		// if we end up with 2, release the later for garbage collection
-		rs = lg.rsBU
+	// walk each of the roots
+	for _, rname := range lg.rootFiles {
+		rnode := lg.targets[rname]
+		_ = walk(rnode, rnode.IsContainer())
 	}
-	lg.mu.Unlock()
 
-	return rs
+	wg.Done()
 }
 
 // ResolveTopDownCondtions performs a top-down walk of the LicenseGraph
-// resolving all reachable nodes for `condition`. Policy establishes the rules
-// for transforming and propagating resolutions down the graph.
+// propagating conditions from target to dependency.
 //
 // e.g. For current policy, none of the conditions propagate from target to
 // dependency except restricted. For restricted, the policy is to share the
 // source of any libraries linked to restricted code and to provide notice.
-func ResolveTopDownConditions(lg *LicenseGraph) *ResolutionSet {
+func ResolveTopDownConditions(lg *LicenseGraph) {
 
 	// short-cut if already walked and cached
 	lg.mu.Lock()
-	rs := lg.rsTD
-	lg.mu.Unlock()
+	wg := lg.wgTD
 
-	if rs != nil {
-		return rs
+	if wg != nil {
+		lg.mu.Unlock()
+		wg.Wait()
+		return
 	}
+	wg = &sync.WaitGroup{}
+	wg.Add(1)
+	lg.wgTD = wg
+	lg.mu.Unlock()
 
 	// start with the conditions propagated up the graph
-	rs = ResolveBottomUpConditions(lg)
+	ResolveBottomUpConditions(lg)
 
-	// rmap maps 'appliesTo' targets to their applicable conditions
-	//
-	// rmap is the resulting ResolutionSet
-	rmap := make(map[*TargetNode]actionSet)
+	// amap contains the set of targets already walked. (guarded by mu)
+	amap := make(map[*TargetNode]struct{})
 
 	// cmap contains the set of targets walked as pure aggregates. i.e. containers
-	cmap := make(map[*TargetNode]bool)
+	// (guarded by mu)
+	cmap := make(map[*TargetNode]struct{})
 
-	var walk func(fnode *TargetNode, cs *LicenseConditionSet, treatAsAggregate bool)
+	// mu guards concurrent access to cmap
+	var mu sync.Mutex
 
-	walk = func(fnode *TargetNode, cs *LicenseConditionSet, treatAsAggregate bool) {
-		if _, ok := rmap[fnode]; !ok {
-			rmap[fnode] = make(actionSet)
-		}
-		rmap[fnode].add(fnode, cs)
+	var walk func(fnode *TargetNode, cs LicenseConditionSet, treatAsAggregate bool)
+
+	walk = func(fnode *TargetNode, cs LicenseConditionSet, treatAsAggregate bool) {
+		defer wg.Done()
+		mu.Lock()
+		fnode.resolution |= fnode.licenseConditions
+		fnode.resolution |= cs
+		amap[fnode] = struct{}{}
 		if treatAsAggregate {
-			cmap[fnode] = true
+			cmap[fnode] = struct{}{}
 		}
-		// add conditions attached to `fnode`
-		cs = cs.Copy()
-		for _, fcs := range rs.resolutions[fnode] {
-			cs.AddSet(fcs)
-		}
+		cs = fnode.resolution
+		mu.Unlock()
 		// for each dependency
-		for _, edge := range lg.index[fnode.name] {
-			e := TargetEdge{lg, edge}
-			// dcs holds the dpendency conditions inherited from the target
-			dcs := targetConditionsApplicableToDep(e, cs, treatAsAggregate)
-			if dcs.IsEmpty() && !treatAsAggregate {
-				continue
-			}
-			dnode := lg.targets[edge.dependency]
-			if as, alreadyWalked := rmap[dnode]; alreadyWalked {
-				diff := dcs.Copy()
-				diff.RemoveSet(as.conditions())
-				if diff.IsEmpty() {
-					// no new conditions
+		for _, edge := range fnode.edges {
+			func(edge *TargetEdge) {
+				// dcs holds the dpendency conditions inherited from the target
+				dcs := targetConditionsPropagatingToDep(lg, edge, cs, treatAsAggregate)
+				dnode := edge.dependency
+				mu.Lock()
+				defer mu.Unlock()
+				depcs := dnode.resolution
+				_, alreadyWalked := amap[dnode]
+				if !dcs.IsEmpty() && alreadyWalked {
+					if dcs.Difference(depcs).IsEmpty() {
+						// no new conditions
 
-					// pure aggregates never need walking a 2nd time with same conditions
-					if treatAsAggregate {
-						continue
+						// pure aggregates never need walking a 2nd time with same conditions
+						if treatAsAggregate {
+							return
+						}
+						// non-aggregates don't need walking as non-aggregate a 2nd time
+						if _, asAggregate := cmap[dnode]; !asAggregate {
+							return
+						}
+						// previously walked as pure aggregate; need to re-walk as non-aggregate
+						delete(cmap, dnode)
 					}
-					// non-aggregates don't need walking as non-aggregate a 2nd time
-					if _, asAggregate := cmap[dnode]; !asAggregate {
-						continue
-					}
-					// previously walked as pure aggregate; need to re-walk as non-aggregate
-					delete(cmap, dnode)
 				}
-			}
-			// add the conditions to the dependency
-			walk(dnode, dcs, treatAsAggregate && lg.targets[edge.dependency].IsContainer())
+				// add the conditions to the dependency
+				wg.Add(1)
+				go walk(dnode, dcs, treatAsAggregate && dnode.IsContainer())
+			}(edge)
 		}
 	}
 
 	// walk each of the roots
-	for _, r := range lg.rootFiles {
-		rnode := lg.targets[r]
-		as, ok := rs.resolutions[rnode]
-		if !ok {
-			// no conditions in root or transitive closure of dependencies
-			continue
-		}
-		if as.isEmpty() {
-			continue
-		}
-
+	for _, rname := range lg.rootFiles {
+		rnode := lg.targets[rname]
+		wg.Add(1)
 		// add the conditions to the root and its transitive closure
-		walk(rnode, newLicenseConditionSet(), lg.targets[r].IsContainer())
+		go walk(rnode, NewLicenseConditionSet(), rnode.IsContainer())
 	}
-
-	// back-fill any bottom-up conditions on targets missed by top-down walk
-	for attachesTo, as := range rs.resolutions {
-		if _, ok := rmap[attachesTo]; !ok {
-			rmap[attachesTo] = as.copy()
-		} else {
-			rmap[attachesTo].addSet(as)
-		}
-	}
-
-	// propagate any new conditions back up the graph
-	rs = resolveBottomUp(lg, rmap)
-
-	// if not yet cached, save the result
-	lg.mu.Lock()
-	if lg.rsTD == nil {
-		lg.rsTD = rs
-	} else {
-		// if we end up with 2, release the later for garbage collection
-		rs = lg.rsTD
-	}
-	lg.mu.Unlock()
-
-	return rs
-}
-
-// resolveBottomUp implements a bottom-up resolve propagating conditions both
-// from the graph, and from a `priors` map of resolutions.
-func resolveBottomUp(lg *LicenseGraph, priors map[*TargetNode]actionSet) *ResolutionSet {
-	rs := newResolutionSet()
-
-	// cmap contains an entry for every target that was previously walked as a pure aggregate only.
-	cmap := make(map[string]bool)
-
-	var walk func(f string, treatAsAggregate bool) actionSet
-
-	walk = func(f string, treatAsAggregate bool) actionSet {
-		target := lg.targets[f]
-		result := make(actionSet)
-		result[target] = newLicenseConditionSet()
-		result[target].add(target, target.proto.LicenseConditions...)
-		if pas, ok := priors[target]; ok {
-			result.addSet(pas)
-		}
-		if preresolved, ok := rs.resolutions[target]; ok {
-			if treatAsAggregate {
-				result.addSet(preresolved)
-				return result
-			}
-			if _, asAggregate := cmap[f]; !asAggregate {
-				result.addSet(preresolved)
-				return result
-			}
-			// previously walked in a pure aggregate context,
-			// needs to walk again in non-aggregate context
-			delete(cmap, f)
-		}
-		if treatAsAggregate {
-			cmap[f] = true
-		}
-
-		// add all the conditions from all the dependencies
-		for _, edge := range lg.index[f] {
-			// walk dependency to get its conditions
-			as := walk(edge.dependency, treatAsAggregate && lg.targets[edge.dependency].IsContainer())
-
-			// turn those into the conditions that apply to the target
-			as = depActionsApplicableToTarget(TargetEdge{lg, edge}, as, treatAsAggregate)
-
-			// add them to the result
-			result.addSet(as)
-		}
-
-		// record these conditions as applicable to the target
-		rs.addConditions(target, result)
-		if len(priors) == 0 {
-			// on the first bottom-up resolve, parents have their own sharing and notice needs
-			// on the later resolve, if priors is empty, there will be nothing new to add
-			rs.addSelf(target, result.byName(ImpliesRestricted))
-		}
-
-		// return this up the tree
-		return result
-	}
-
-	// walk each of the roots
-	for _, r := range lg.rootFiles {
-		_ = walk(r, lg.targets[r].IsContainer())
-	}
-
-	return rs
+	wg.Done()
+	wg.Wait()
 }
diff --git a/tools/compliance/policy/resolve_test.go b/tools/compliance/policy/resolve_test.go
index 4c99d35..09dd7dd 100644
--- a/tools/compliance/policy/resolve_test.go
+++ b/tools/compliance/policy/resolve_test.go
@@ -16,15 +16,16 @@
 
 import (
 	"bytes"
+	"sort"
 	"testing"
 )
 
 func TestResolveBottomUpConditions(t *testing.T) {
 	tests := []struct {
-		name                string
-		roots               []string
-		edges               []annotated
-		expectedResolutions []res
+		name            string
+		roots           []string
+		edges           []annotated
+		expectedActions []tcond
 	}{
 		{
 			name:  "firstparty",
@@ -32,10 +33,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
-				{"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -44,9 +44,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"toolchain"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -56,13 +56,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
-				{"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -72,12 +69,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -86,9 +81,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -98,11 +93,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -112,11 +106,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -125,11 +118,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice|restricted"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -138,9 +129,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"toolchain"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -150,16 +141,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted"},
+				{"apacheBin.meta_lic", "notice|restricted"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -169,13 +154,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted"},
+				{"apacheBin.meta_lic", "notice"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -184,11 +166,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice|restricted"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -198,16 +178,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted"},
+				{"apacheBin.meta_lic", "notice|restricted"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -217,13 +191,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted"},
+				{"apacheBin.meta_lic", "notice"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -232,11 +203,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice|restricted_allows_dynamic_linking"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -245,9 +214,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"toolchain"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -257,16 +226,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted_allows_dynamic_linking"},
+				{"apacheBin.meta_lic", "notice|restricted_allows_dynamic_linking"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -276,13 +239,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "lgplLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted_allows_dynamic_linking"},
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -291,9 +251,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -303,11 +263,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -317,11 +276,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -330,11 +288,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice|restricted_with_classpath_exception"},
+				{"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"},
 			},
 		},
 		{
@@ -343,11 +299,9 @@
 			edges: []annotated{
 				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"dependentModule.meta_lic", "dependentModule.meta_lic", "dependentModule.meta_lic", "notice"},
-				{"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"dependentModule.meta_lic", "notice|restricted_with_classpath_exception"},
+				{"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"},
 			},
 		},
 		{
@@ -356,9 +310,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"},
 			},
 		},
 		{
@@ -367,11 +321,9 @@
 			edges: []annotated{
 				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"dependentModule.meta_lic", "dependentModule.meta_lic", "dependentModule.meta_lic", "notice"},
-				{"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"dependentModule.meta_lic", "notice|restricted_with_classpath_exception"},
+				{"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"},
 			},
 		},
 	}
@@ -383,19 +335,37 @@
 				t.Errorf("unexpected test data error: got %w, want no error", err)
 				return
 			}
-			expectedRs := toResolutionSet(lg, tt.expectedResolutions)
-			actualRs := ResolveBottomUpConditions(lg)
-			checkSame(actualRs, expectedRs, t)
+
+			logGraph(lg, t)
+
+			ResolveBottomUpConditions(lg)
+			actual := asActionList(lg)
+			sort.Sort(actual)
+			t.Logf("actual: %s", actual.String())
+
+			expected := toActionList(lg, tt.expectedActions)
+			sort.Sort(expected)
+			t.Logf("expected: %s", expected.String())
+
+			if len(actual) != len(expected) {
+				t.Errorf("unexpected number of actions: got %d, want %d", len(actual), len(expected))
+				return
+			}
+			for i := 0; i < len(actual); i++ {
+				if actual[i] != expected[i] {
+					t.Errorf("unexpected action at index %d: got %s, want %s", i, actual[i].String(), expected[i].String())
+				}
+			}
 		})
 	}
 }
 
 func TestResolveTopDownConditions(t *testing.T) {
 	tests := []struct {
-		name                string
-		roots               []string
-		edges               []annotated
-		expectedResolutions []res
+		name            string
+		roots           []string
+		edges           []annotated
+		expectedActions []tcond
 	}{
 		{
 			name:  "firstparty",
@@ -403,10 +373,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
-				{"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -415,9 +384,9 @@
 			edges: []annotated{
 				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -427,15 +396,10 @@
 				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice|restricted"},
+				{"mitLib.meta_lic", "notice|restricted"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -445,11 +409,10 @@
 				{"apacheBin.meta_lic", "gplBin.meta_lic", []string{"toolchain"}},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"gplBin.meta_lic", "gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"mitLib.meta_lic", "notice"},
+				{"gplBin.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -462,27 +425,13 @@
 				{"apacheBin.meta_lic", "mplLib.meta_lic", []string{"static"}},
 				{"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"mitBin.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"},
-				{"mitBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"mplLib.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"mplLib.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted"},
+				{"apacheBin.meta_lic", "notice|restricted"},
+				{"mitBin.meta_lic", "notice"},
+				{"gplLib.meta_lic", "restricted"},
+				{"mplLib.meta_lic", "reciprocal|restricted"},
+				{"mitLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -492,13 +441,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted"},
+				{"apacheBin.meta_lic", "notice"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -508,14 +454,10 @@
 				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"dynamic"}},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice|restricted"},
+				{"gplLib.meta_lic", "restricted"},
+				{"mitLib.meta_lic", "notice|restricted"},
 			},
 		},
 		{
@@ -528,23 +470,13 @@
 				{"apacheBin.meta_lic", "mplLib.meta_lic", []string{"dynamic"}},
 				{"mitBin.meta_lic", "mitLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"mitBin.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"mplLib.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"mplLib.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted"},
+				{"apacheBin.meta_lic", "notice|restricted"},
+				{"mitBin.meta_lic", "notice"},
+				{"gplLib.meta_lic", "restricted"},
+				{"mplLib.meta_lic", "reciprocal|restricted"},
+				{"mitLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -554,13 +486,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted"},
+				{"apacheBin.meta_lic", "notice"},
+				{"gplLib.meta_lic", "restricted"},
 			},
 		},
 		{
@@ -570,15 +499,10 @@
 				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice|restricted_allows_dynamic_linking"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
+				{"mitLib.meta_lic", "notice|restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -588,11 +512,10 @@
 				{"apacheBin.meta_lic", "lgplBin.meta_lic", []string{"toolchain"}},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"lgplBin.meta_lic", "lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplBin.meta_lic", "restricted_allows_dynamic_linking"},
+				{"mitLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -603,22 +526,11 @@
 				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted_allows_dynamic_linking"},
+				{"apacheBin.meta_lic", "notice|restricted_allows_dynamic_linking"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
+				{"mitLib.meta_lic", "notice|restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -628,13 +540,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "lgplLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice|restricted_allows_dynamic_linking"},
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -644,11 +553,10 @@
 				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
+				{"mitLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -658,11 +566,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -672,11 +579,10 @@
 				{"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}},
 				{"apacheContainer.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
 			},
-			expectedResolutions: []res{
-				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
-				{"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			expectedActions: []tcond{
+				{"apacheContainer.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "notice"},
+				{"lgplLib.meta_lic", "restricted_allows_dynamic_linking"},
 			},
 		},
 		{
@@ -686,15 +592,10 @@
 				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice|restricted_with_classpath_exception"},
+				{"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"},
+				{"mitLib.meta_lic", "notice|restricted_with_classpath_exception"},
 			},
 		},
 		{
@@ -704,15 +605,10 @@
 				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
 				{"dependentModule.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"dependentModule.meta_lic", "dependentModule.meta_lic", "dependentModule.meta_lic", "notice"},
-				{"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"dependentModule.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"dependentModule.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"dependentModule.meta_lic", "notice|restricted_with_classpath_exception"},
+				{"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"},
+				{"mitLib.meta_lic", "notice|restricted_with_classpath_exception"},
 			},
 		},
 		{
@@ -722,11 +618,10 @@
 				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
 				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
-				{"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"apacheBin.meta_lic", "notice"},
+				{"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"},
+				{"mitLib.meta_lic", "notice"},
 			},
 		},
 		{
@@ -736,15 +631,10 @@
 				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
 				{"dependentModule.meta_lic", "mitLib.meta_lic", []string{"static"}},
 			},
-			expectedResolutions: []res{
-				{"dependentModule.meta_lic", "dependentModule.meta_lic", "dependentModule.meta_lic", "notice"},
-				{"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"dependentModule.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
-				{"dependentModule.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
-				{"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			expectedActions: []tcond{
+				{"dependentModule.meta_lic", "notice|restricted_with_classpath_exception"},
+				{"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"},
+				{"mitLib.meta_lic", "notice|restricted_with_classpath_exception"},
 			},
 		},
 	}
@@ -756,9 +646,27 @@
 				t.Errorf("unexpected test data error: got %w, want no error", err)
 				return
 			}
-			expectedRs := toResolutionSet(lg, tt.expectedResolutions)
-			actualRs := ResolveTopDownConditions(lg)
-			checkSame(actualRs, expectedRs, t)
+
+			logGraph(lg, t)
+
+			ResolveTopDownConditions(lg)
+			actual := asActionList(lg)
+			sort.Sort(actual)
+			t.Logf("actual: %s", actual.String())
+
+			expected := toActionList(lg, tt.expectedActions)
+			sort.Sort(expected)
+			t.Logf("expected: %s", expected.String())
+
+			if len(actual) != len(expected) {
+				t.Errorf("unexpected number of actions: got %d, want %d", len(actual), len(expected))
+				return
+			}
+			for i := 0; i < len(actual); i++ {
+				if actual[i] != expected[i] {
+					t.Errorf("unexpected action at index %d: got %s, want %s", i, actual[i].String(), expected[i].String())
+				}
+			}
 		})
 	}
 }
diff --git a/tools/compliance/policy/resolvenotices.go b/tools/compliance/policy/resolvenotices.go
index 80b5e02..99f6d42 100644
--- a/tools/compliance/policy/resolvenotices.go
+++ b/tools/compliance/policy/resolvenotices.go
@@ -15,7 +15,7 @@
 package compliance
 
 // ResolveNotices implements the policy for notices.
-func ResolveNotices(lg *LicenseGraph) *ResolutionSet {
-	rs := ResolveTopDownConditions(lg)
-	return WalkResolutionsForCondition(lg, rs, ImpliesNotice)
+func ResolveNotices(lg *LicenseGraph) ResolutionSet {
+	ResolveTopDownConditions(lg)
+	return WalkResolutionsForCondition(lg, ImpliesNotice)
 }
diff --git a/tools/compliance/policy/resolveprivacy.go b/tools/compliance/policy/resolveprivacy.go
index dabbc62..2a7992e 100644
--- a/tools/compliance/policy/resolveprivacy.go
+++ b/tools/compliance/policy/resolveprivacy.go
@@ -15,7 +15,7 @@
 package compliance
 
 // ResolveSourcePrivacy implements the policy for source privacy.
-func ResolveSourcePrivacy(lg *LicenseGraph) *ResolutionSet {
-	rs := ResolveTopDownConditions(lg)
-	return WalkResolutionsForCondition(lg, rs, ImpliesPrivate)
+func ResolveSourcePrivacy(lg *LicenseGraph) ResolutionSet {
+	ResolveTopDownConditions(lg)
+	return WalkResolutionsForCondition(lg, ImpliesPrivate)
 }
diff --git a/tools/compliance/policy/resolveprivacy_test.go b/tools/compliance/policy/resolveprivacy_test.go
index 25772bb..2072d22 100644
--- a/tools/compliance/policy/resolveprivacy_test.go
+++ b/tools/compliance/policy/resolveprivacy_test.go
@@ -81,7 +81,7 @@
 			}
 			expectedRs := toResolutionSet(lg, tt.expectedResolutions)
 			actualRs := ResolveSourcePrivacy(lg)
-			checkSame(actualRs, expectedRs, t)
+			checkResolves(actualRs, expectedRs, t)
 		})
 	}
 }
diff --git a/tools/compliance/policy/resolveshare.go b/tools/compliance/policy/resolveshare.go
index 24efd28..9b6a8bb 100644
--- a/tools/compliance/policy/resolveshare.go
+++ b/tools/compliance/policy/resolveshare.go
@@ -15,7 +15,7 @@
 package compliance
 
 // ResolveSourceSharing implements the policy for source-sharing.
-func ResolveSourceSharing(lg *LicenseGraph) *ResolutionSet {
-	rs := ResolveTopDownConditions(lg)
-	return WalkResolutionsForCondition(lg, rs, ImpliesShared)
+func ResolveSourceSharing(lg *LicenseGraph) ResolutionSet {
+	ResolveTopDownConditions(lg)
+	return WalkResolutionsForCondition(lg, ImpliesShared)
 }
diff --git a/tools/compliance/policy/resolveshare_test.go b/tools/compliance/policy/resolveshare_test.go
index ad3630d..f73888d 100644
--- a/tools/compliance/policy/resolveshare_test.go
+++ b/tools/compliance/policy/resolveshare_test.go
@@ -291,7 +291,7 @@
 			}
 			expectedRs := toResolutionSet(lg, tt.expectedResolutions)
 			actualRs := ResolveSourceSharing(lg)
-			checkSame(actualRs, expectedRs, t)
+			checkResolves(actualRs, expectedRs, t)
 		})
 	}
 }
diff --git a/tools/compliance/policy/shareprivacyconflicts.go b/tools/compliance/policy/shareprivacyconflicts.go
index dabdff5..279e179 100644
--- a/tools/compliance/policy/shareprivacyconflicts.go
+++ b/tools/compliance/policy/shareprivacyconflicts.go
@@ -28,57 +28,37 @@
 
 // Error returns a string describing the conflict.
 func (conflict SourceSharePrivacyConflict) Error() string {
-	return fmt.Sprintf("%s %s from %s and must share from %s %s\n",
-		conflict.SourceNode.name,
-		conflict.PrivacyCondition.name, conflict.PrivacyCondition.origin.name,
-		conflict.ShareCondition.name, conflict.ShareCondition.origin.name)
+	return fmt.Sprintf("%s %s and must share from %s condition\n", conflict.SourceNode.name,
+		conflict.PrivacyCondition.Name(), conflict.ShareCondition.Name())
 }
 
 // IsEqualTo returns true when `conflict` and `other` describe the same conflict.
 func (conflict SourceSharePrivacyConflict) IsEqualTo(other SourceSharePrivacyConflict) bool {
 	return conflict.SourceNode.name == other.SourceNode.name &&
-		conflict.ShareCondition.name == other.ShareCondition.name &&
-		conflict.ShareCondition.origin.name == other.ShareCondition.origin.name &&
-		conflict.PrivacyCondition.name == other.PrivacyCondition.name &&
-		conflict.PrivacyCondition.origin.name == other.PrivacyCondition.origin.name
+		conflict.ShareCondition == other.ShareCondition &&
+		conflict.PrivacyCondition == other.PrivacyCondition
 }
 
 // ConflictingSharedPrivateSource lists all of the targets where conflicting conditions to
 // share the source and to keep the source private apply to the target.
 func ConflictingSharedPrivateSource(lg *LicenseGraph) []SourceSharePrivacyConflict {
-	// shareSource is the set of all source-sharing resolutions.
-	shareSource := ResolveSourceSharing(lg)
-	if shareSource.IsEmpty() {
-		return []SourceSharePrivacyConflict{}
-	}
 
-	// privateSource is the set of all source privacy resolutions.
-	privateSource := ResolveSourcePrivacy(lg)
-	if privateSource.IsEmpty() {
-		return []SourceSharePrivacyConflict{}
-	}
-
+	ResolveTopDownConditions(lg)
 	// combined is the combination of source-sharing and source privacy.
-	combined := JoinResolutionSets(shareSource, privateSource)
+	combined := WalkActionsForCondition(lg, ImpliesShared.Union(ImpliesPrivate))
 
 	// size is the size of the result
 	size := 0
-	for _, actsOn := range combined.ActsOn() {
-		rl := combined.ResolutionsByActsOn(actsOn)
-		size += rl.CountConditionsByName(ImpliesShared) * rl.CountConditionsByName(ImpliesPrivate)
+	for _, cs := range combined {
+		size += cs.Intersection(ImpliesShared).Len() * cs.Intersection(ImpliesPrivate).Len()
 	}
 	if size == 0 {
-		return []SourceSharePrivacyConflict{}
+		return nil
 	}
 	result := make([]SourceSharePrivacyConflict, 0, size)
-	for _, actsOn := range combined.ActsOn() {
-		rl := combined.ResolutionsByActsOn(actsOn)
-		if len(rl) == 0 {
-			continue
-		}
-
-		pconditions := rl.ByName(ImpliesPrivate).AllConditions().AsList()
-		ssconditions := rl.ByName(ImpliesShared).AllConditions().AsList()
+	for actsOn, cs := range combined {
+		pconditions := cs.Intersection(ImpliesPrivate).AsList()
+		ssconditions := cs.Intersection(ImpliesShared).AsList()
 
 		// report all conflicting condition combinations
 		for _, p := range pconditions {
diff --git a/tools/compliance/policy/shareprivacyconflicts_test.go b/tools/compliance/policy/shareprivacyconflicts_test.go
index 162c1fe..ad3f3f4 100644
--- a/tools/compliance/policy/shareprivacyconflicts_test.go
+++ b/tools/compliance/policy/shareprivacyconflicts_test.go
@@ -33,19 +33,13 @@
 // Less returns true when the `i`th element is lexicographically less than
 // the `j`th element.
 func (l byConflict) Less(i, j int) bool {
-	if l[i].SourceNode.name == l[j].SourceNode.name {
-		if l[i].ShareCondition.origin.name == l[j].ShareCondition.origin.name {
-			if l[i].ShareCondition.name == l[j].ShareCondition.name {
-				if l[i].PrivacyCondition.origin.name == l[j].PrivacyCondition.origin.name {
-					return l[i].PrivacyCondition.name < l[j].PrivacyCondition.name
-				}
-				return l[i].PrivacyCondition.origin.name < l[j].PrivacyCondition.origin.name
-			}
-			return l[i].ShareCondition.name < l[j].ShareCondition.name
+	if l[i].SourceNode.Name() == l[j].SourceNode.Name() {
+		if l[i].ShareCondition.Name() == l[j].ShareCondition.Name() {
+			return l[i].PrivacyCondition.Name() < l[j].PrivacyCondition.Name()
 		}
-		return l[i].ShareCondition.origin.name < l[j].ShareCondition.origin.name
+		return l[i].ShareCondition.Name() < l[j].ShareCondition.Name()
 	}
-	return l[i].SourceNode.name < l[j].SourceNode.name
+	return l[i].SourceNode.Name() < l[j].SourceNode.Name()
 }
 
 func TestConflictingSharedPrivateSource(t *testing.T) {
diff --git a/tools/compliance/policy/shipped.go b/tools/compliance/policy/shipped.go
index 74eb343..75c8399 100644
--- a/tools/compliance/policy/shipped.go
+++ b/tools/compliance/policy/shipped.go
@@ -24,18 +24,18 @@
 		return shipped
 	}
 
-	tset := make(map[*TargetNode]bool)
+	tset := make(map[*TargetNode]struct{})
 
-	WalkTopDown(lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool {
+	WalkTopDown(NoEdgeContext{}, lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool {
 		if _, alreadyWalked := tset[tn]; alreadyWalked {
 			return false
 		}
 		if len(path) > 0 {
-			if !edgeIsDerivation(path[len(path)-1]) {
+			if !edgeIsDerivation(path[len(path)-1].edge) {
 				return false
 			}
 		}
-		tset[tn] = true
+		tset[tn] = struct{}{}
 		return true
 	})
 
diff --git a/tools/compliance/policy/shipped_test.go b/tools/compliance/policy/shipped_test.go
index 53a8469..718e56f 100644
--- a/tools/compliance/policy/shipped_test.go
+++ b/tools/compliance/policy/shipped_test.go
@@ -17,6 +17,7 @@
 import (
 	"bytes"
 	"sort"
+	"strings"
 	"testing"
 )
 
@@ -110,19 +111,31 @@
 				t.Errorf("unexpected test data error: got %w, want no error", err)
 				return
 			}
+			t.Logf("graph:")
+			for _, edge := range lg.Edges() {
+				t.Logf("  %s", edge.String())
+			}
 			expectedNodes := append([]string{}, tt.expectedNodes...)
-			actualNodes := ShippedNodes(lg).Names()
+			nodeset := ShippedNodes(lg)
+			t.Logf("shipped node set: %s", nodeset.String())
+
+			actualNodes := nodeset.Names()
+			t.Logf("shipped nodes: [%s]", strings.Join(actualNodes, ", "))
+
 			sort.Strings(expectedNodes)
 			sort.Strings(actualNodes)
+
+			t.Logf("sorted nodes: [%s]", strings.Join(actualNodes, ", "))
+			t.Logf("expected nodes: [%s]", strings.Join(expectedNodes, ", "))
                         if len(expectedNodes) != len(actualNodes) {
-				t.Errorf("unexpected number of shipped nodes: got %v with %d nodes, want %v with %d nodes",
-					actualNodes, len(actualNodes), expectedNodes, len(expectedNodes))
+				t.Errorf("unexpected number of shipped nodes: %d nodes, want %d nodes",
+					len(actualNodes), len(expectedNodes))
 				return
 			}
 			for i := 0; i < len(actualNodes); i++ {
 				if expectedNodes[i] != actualNodes[i] {
-					t.Errorf("unexpected node at index %d: got %q in %v, want %q in %v",
-						i, actualNodes[i], actualNodes, expectedNodes[i], expectedNodes)
+					t.Errorf("unexpected node at index %d: got %q, want %q",
+						i, actualNodes[i], expectedNodes[i])
 				}
 			}
 		})
diff --git a/tools/compliance/policy/walk.go b/tools/compliance/policy/walk.go
index 8b6737d..3e73088 100644
--- a/tools/compliance/policy/walk.go
+++ b/tools/compliance/policy/walk.go
@@ -14,27 +14,60 @@
 
 package compliance
 
+// EdgeContextProvider is an interface for injecting edge-specific context
+// into walk paths.
+type EdgeContextProvider interface {
+	// Context returns the context for `edge` when added to `path`.
+	Context(lg *LicenseGraph, path TargetEdgePath, edge *TargetEdge) interface{}
+}
+
+// NoEdgeContext implements EdgeContextProvider for walks that use no context.
+type NoEdgeContext struct{}
+
+// Context returns nil.
+func (ctx NoEdgeContext) Context(lg *LicenseGraph, path TargetEdgePath, edge *TargetEdge) interface{} {
+	return nil
+}
+
+// ApplicableConditionsContext provides the subset of conditions in `universe`
+// that apply to each edge in a path.
+type ApplicableConditionsContext struct {
+	universe LicenseConditionSet
+}
+
+// Context returns the LicenseConditionSet applicable to the edge.
+func (ctx ApplicableConditionsContext) Context(lg *LicenseGraph, path TargetEdgePath, edge *TargetEdge) interface{} {
+	universe := ctx.universe
+	if len(path) > 0 {
+		universe = path[len(path)-1].ctx.(LicenseConditionSet)
+	}
+	return conditionsAttachingAcrossEdge(lg, edge, universe)
+}
+
 // VisitNode is called for each root and for each walked dependency node by
 // WalkTopDown. When VisitNode returns true, WalkTopDown will proceed to walk
 // down the dependences of the node
-type VisitNode func(*LicenseGraph, *TargetNode, TargetEdgePath) bool
+type VisitNode func(lg *LicenseGraph, target *TargetNode, path TargetEdgePath) bool
 
 // WalkTopDown does a top-down walk of `lg` calling `visit` and descending
 // into depenencies when `visit` returns true.
-func WalkTopDown(lg *LicenseGraph, visit VisitNode) {
+func WalkTopDown(ctx EdgeContextProvider, lg *LicenseGraph, visit VisitNode) {
 	path := NewTargetEdgePath(32)
 
-	// must be indexed for fast lookup
-	lg.indexForward()
-
-	var walk func(f string)
-	walk = func(f string) {
-		visitChildren := visit(lg, lg.targets[f], *path)
+	var walk func(fnode *TargetNode)
+	walk = func(fnode *TargetNode) {
+		visitChildren := visit(lg, fnode, *path)
 		if !visitChildren {
 			return
 		}
-		for _, edge := range lg.index[f] {
-			path.Push(TargetEdge{lg, edge})
+		for _, edge := range fnode.edges {
+			var edgeContext interface{}
+			if ctx == nil {
+				edgeContext = nil
+			} else {
+				edgeContext = ctx.Context(lg, *path, edge)
+			}
+			path.Push(edge, edgeContext)
 			walk(edge.dependency)
 			path.Pop()
 		}
@@ -42,35 +75,164 @@
 
 	for _, r := range lg.rootFiles {
 		path.Clear()
-		walk(r)
+		walk(lg.targets[r])
 	}
 }
 
+// resolutionKey identifies results from walking a specific target for a
+// specific set of conditions.
+type resolutionKey struct {
+	target *TargetNode
+	cs LicenseConditionSet
+}
+
 // WalkResolutionsForCondition performs a top-down walk of the LicenseGraph
-// resolving all distributed works for condition `names`.
-func WalkResolutionsForCondition(lg *LicenseGraph, rs *ResolutionSet, names ConditionNames) *ResolutionSet {
+// resolving all distributed works for `conditions`.
+func WalkResolutionsForCondition(lg *LicenseGraph, conditions LicenseConditionSet) ResolutionSet {
 	shipped := ShippedNodes(lg)
 
 	// rmap maps 'attachesTo' targets to the `actsOn` targets and applicable conditions
-	//
-	// rmap is the resulting ResolutionSet
-	rmap := make(map[*TargetNode]actionSet)
+	rmap := make(map[resolutionKey]ActionSet)
 
-	WalkTopDown(lg, func(lg *LicenseGraph, tn *TargetNode, _ TargetEdgePath) bool {
-		if _, ok := rmap[tn]; ok {
+	// cmap identifies previously walked target/condition pairs.
+	cmap := make(map[resolutionKey]struct{})
+
+	// result accumulates the resolutions to return.
+	result := make(ResolutionSet)
+	WalkTopDown(ApplicableConditionsContext{conditions}, lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool {
+		universe := conditions
+		if len(path) > 0 {
+			universe = path[len(path)-1].ctx.(LicenseConditionSet)
+		}
+
+		if universe.IsEmpty() {
+			return false
+		}
+		key := resolutionKey{tn, universe}
+
+		if _, alreadyWalked := cmap[key]; alreadyWalked {
+			pure := true
+			for _, p := range path {
+				target := p.Target()
+				tkey := resolutionKey{target, universe}
+				if _, ok := rmap[tkey]; !ok {
+					rmap[tkey] = make(ActionSet)
+				}
+				// attach prior walk outcome to ancestor
+				for actsOn, cs := range rmap[key] {
+					rmap[tkey][actsOn] = cs
+				}
+				// if prior walk produced results, copy results
+				// to ancestor.
+				if _, ok := result[tn]; ok && pure {
+					if _, ok := result[target]; !ok {
+						result[target] = make(ActionSet)
+					}
+					for actsOn, cs := range result[tn] {
+						result[target][actsOn] = cs
+					}
+					pure = target.IsContainer()
+				}
+			}
+			// if all ancestors are pure aggregates, attach
+			// matching prior walk conditions to self. Prior walk
+			// will not have done so if any ancestor was not an
+			// aggregate.
+			if pure {
+				match := rmap[key][tn].Intersection(universe)
+				if !match.IsEmpty() {
+					if _, ok := result[tn]; !ok {
+						result[tn] = make(ActionSet)
+					}
+					result[tn][tn] = match
+				}
+			}
+			return false
+		}
+		// no need to walk node or dependencies if not shipped
+		if !shipped.Contains(tn) {
+			return false
+		}
+		if _, ok := rmap[key]; !ok {
+			rmap[key] = make(ActionSet)
+		}
+		// add self to walk outcome
+		rmap[key][tn] = tn.resolution
+		cmap[key] = struct{}{}
+		cs := tn.resolution
+		if !cs.IsEmpty() {
+			cs = cs.Intersection(universe)
+			pure := true
+			for _, p := range path {
+				target := p.Target()
+				tkey := resolutionKey{target, universe}
+				if _, ok := rmap[tkey]; !ok {
+					rmap[tkey] = make(ActionSet)
+				}
+				// copy current node's action into ancestor
+				rmap[tkey][tn] = tn.resolution
+				// conditionally put matching conditions into
+				// result
+				if pure && !cs.IsEmpty() {
+					if _, ok := result[target]; !ok {
+						result[target] = make(ActionSet)
+					}
+					result[target][tn] = cs
+					pure = target.IsContainer()
+				}
+			}
+			// if all ancestors are pure aggregates, attach
+			// matching conditions to self.
+			if pure && !cs.IsEmpty() {
+				if _, ok := result[tn]; !ok {
+					result[tn] = make(ActionSet)
+				}
+				result[tn][tn] = cs
+			}
+		}
+		return true
+	})
+
+	return result
+}
+
+// WalkActionsForCondition performs a top-down walk of the LicenseGraph
+// resolving all distributed works for `conditions`.
+func WalkActionsForCondition(lg *LicenseGraph, conditions LicenseConditionSet) ActionSet {
+	shipped := ShippedNodes(lg)
+
+	// cmap identifies previously walked target/condition pairs.
+	cmap := make(map[resolutionKey]struct{})
+
+	// amap maps 'actsOn' targets to the applicable conditions
+	//
+	// amap is the resulting ActionSet
+	amap := make(ActionSet)
+	WalkTopDown(ApplicableConditionsContext{conditions}, lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool {
+		universe := conditions
+		if len(path) > 0 {
+			universe = path[len(path)-1].ctx.(LicenseConditionSet)
+		}
+		if universe.IsEmpty() {
+			return false
+		}
+		key := resolutionKey{tn, universe}
+		if _, ok := cmap[key]; ok {
 			return false
 		}
 		if !shipped.Contains(tn) {
 			return false
 		}
-		if as, ok := rs.resolutions[tn]; ok {
-			fas := as.byActsOn(shipped).byName(names)
-			if !fas.isEmpty() {
-				rmap[tn] = fas
+		cs := universe.Intersection(tn.resolution)
+		if !cs.IsEmpty() {
+			if _, ok := amap[tn]; ok {
+				amap[tn] = cs
+			} else {
+				amap[tn] = amap[tn].Union(cs)
 			}
 		}
-		return tn.IsContainer() // descend into containers
+		return true
 	})
 
-	return &ResolutionSet{rmap}
+	return amap
 }
diff --git a/tools/compliance/policy/walk_test.go b/tools/compliance/policy/walk_test.go
index 07710aa..a2ec6e7 100644
--- a/tools/compliance/policy/walk_test.go
+++ b/tools/compliance/policy/walk_test.go
@@ -22,7 +22,7 @@
 func TestWalkResolutionsForCondition(t *testing.T) {
 	tests := []struct {
 		name                string
-		condition           ConditionNames
+		condition           LicenseConditionSet
 		roots               []string
 		edges               []annotated
 		expectedResolutions []res
@@ -624,8 +624,617 @@
 				return
 			}
 			expectedRs := toResolutionSet(lg, tt.expectedResolutions)
-			actualRs := WalkResolutionsForCondition(lg, ResolveTopDownConditions(lg), tt.condition)
-			checkSame(actualRs, expectedRs, t)
+			ResolveTopDownConditions(lg)
+			actualRs := WalkResolutionsForCondition(lg, tt.condition)
+			checkResolves(actualRs, expectedRs, t)
+		})
+	}
+}
+
+func TestWalkActionsForCondition(t *testing.T) {
+	tests := []struct {
+		name            string
+		condition       LicenseConditionSet
+		roots           []string
+		edges           []annotated
+		expectedActions []act
+	}{
+		{
+			name:      "firstparty",
+			condition: ImpliesNotice,
+			roots:     []string{"apacheBin.meta_lic"},
+			edges: []annotated{
+				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+			},
+		},
+		{
+			name:      "notice",
+			condition: ImpliesNotice,
+			roots:     []string{"mitBin.meta_lic"},
+			edges: []annotated{
+				{"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"mitBin.meta_lic", "mitBin.meta_lic", "notice"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			},
+		},
+		{
+			name:      "fponlgplnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"apacheBin.meta_lic"},
+			edges: []annotated{
+				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"},
+				{"lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "fponlgpldynamicnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"apacheBin.meta_lic"},
+			edges: []annotated{
+				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
+			},
+		},
+		{
+			name:      "independentmodulenotice",
+			condition: ImpliesNotice,
+			roots:     []string{"apacheBin.meta_lic"},
+			edges: []annotated{
+				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
+			},
+		},
+		{
+			name:      "independentmodulerestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"apacheBin.meta_lic"},
+			edges: []annotated{
+				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{},
+		},
+		{
+			name:      "independentmodulestaticnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"apacheBin.meta_lic"},
+			edges: []annotated{
+				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "independentmodulestaticrestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"apacheBin.meta_lic"},
+			edges: []annotated{
+				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "dependentmodulenotice",
+			condition: ImpliesNotice,
+			roots:     []string{"dependentModule.meta_lic"},
+			edges: []annotated{
+				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"dependentModule.meta_lic", "dependentModule.meta_lic", "notice"},
+				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "dependentmodulerestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"dependentModule.meta_lic"},
+			edges: []annotated{
+				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "lgplonfpnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"lgplBin.meta_lic"},
+			edges: []annotated{
+				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "lgplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "lgplonfprestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"lgplBin.meta_lic"},
+			edges: []annotated{
+				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "lgplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "lgplonfpdynamicnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"lgplBin.meta_lic"},
+			edges: []annotated{
+				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "lgplonfpdynamicrestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"lgplBin.meta_lic"},
+			edges: []annotated{
+				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gplonfpnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"gplBin.meta_lic"},
+			edges: []annotated{
+				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "gplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gplonfprestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplBin.meta_lic"},
+			edges: []annotated{
+				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "gplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gplcontainernotice",
+			condition: ImpliesNotice,
+			roots:     []string{"gplContainer.meta_lic"},
+			edges: []annotated{
+				{"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"gplContainer.meta_lic", "gplContainer.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "gplContainer.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "gplContainer.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gplcontainerrestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplContainer.meta_lic"},
+			edges: []annotated{
+				{"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"gplContainer.meta_lic", "gplContainer.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "gplContainer.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "gplContainer.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gploncontainernotice",
+			condition: ImpliesNotice,
+			roots:     []string{"apacheContainer.meta_lic"},
+			edges: []annotated{
+				{"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"},
+				{"apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+				{"gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gploncontainerrestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"apacheContainer.meta_lic"},
+			edges: []annotated{
+				{"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gplonbinnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"apacheBin.meta_lic"},
+			edges: []annotated{
+				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
+				{"apacheLib.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gplonbinrestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"apacheBin.meta_lic"},
+			edges: []annotated{
+				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
+				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gplonfpdynamicnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"gplBin.meta_lic"},
+			edges: []annotated{
+				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gplonfpdynamicrestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplBin.meta_lic"},
+			edges: []annotated{
+				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "gplonfpdynamicrestrictedshipped",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplBin.meta_lic", "apacheLib.meta_lic"},
+			edges: []annotated{
+				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
+				{"apacheLib.meta_lic", "gplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "independentmodulereversenotice",
+			condition: ImpliesNotice,
+			roots:     []string{"gplWithClasspathException.meta_lic"},
+			edges: []annotated{
+				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "independentmodulereverserestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplWithClasspathException.meta_lic"},
+			edges: []annotated{
+				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "independentmodulereverserestrictedshipped",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic"},
+			edges: []annotated{
+				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "independentmodulereversestaticnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"gplWithClasspathException.meta_lic"},
+			edges: []annotated{
+				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
+				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "independentmodulereversestaticrestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplWithClasspathException.meta_lic"},
+			edges: []annotated{
+				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "dependentmodulereversenotice",
+			condition: ImpliesNotice,
+			roots:     []string{"gplWithClasspathException.meta_lic"},
+			edges: []annotated{
+				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "dependentmodulereverserestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplWithClasspathException.meta_lic"},
+			edges: []annotated{
+				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "dependentmodulereverserestrictedshipped",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic"},
+			edges: []annotated{
+				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
+			},
+			expectedActions: []act{
+				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "ponrnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"proprietary.meta_lic"},
+			edges: []annotated{
+				{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"proprietary.meta_lic", "proprietary.meta_lic", "proprietary"},
+				{"proprietary.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "ponrrestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"proprietary.meta_lic"},
+			edges: []annotated{
+				{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
+				{"proprietary.meta_lic", "gplLib.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "ponrproprietary",
+			condition: ImpliesProprietary,
+			roots:     []string{"proprietary.meta_lic"},
+			edges: []annotated{
+				{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"proprietary.meta_lic", "proprietary.meta_lic", "proprietary"},
+			},
+		},
+		{
+			name:      "ronpnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"gplBin.meta_lic"},
+			edges: []annotated{
+				{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
+				{"proprietary.meta_lic", "proprietary.meta_lic", "proprietary"},
+				{"proprietary.meta_lic", "gplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "ronprestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"gplBin.meta_lic"},
+			edges: []annotated{
+				{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
+				{"proprietary.meta_lic", "gplBin.meta_lic", "restricted"},
+			},
+		},
+		{
+			name:      "ronpproprietary",
+			condition: ImpliesProprietary,
+			roots:     []string{"gplBin.meta_lic"},
+			edges: []annotated{
+				{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"proprietary.meta_lic", "proprietary.meta_lic", "proprietary"},
+			},
+		},
+		{
+			name:      "noticeonb_e_onotice",
+			condition: ImpliesNotice,
+			roots:     []string{"mitBin.meta_lic"},
+			edges: []annotated{
+				{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"mitBin.meta_lic", "mitBin.meta_lic", "notice"},
+				{"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"},
+			},
+		},
+		{
+			name:      "noticeonb_e_orestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"mitBin.meta_lic"},
+			edges: []annotated{
+				{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{},
+		},
+		{
+			name:      "noticeonb_e_ob_e_o",
+			condition: ImpliesByExceptionOnly,
+			roots:     []string{"mitBin.meta_lic"},
+			edges: []annotated{
+				{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"},
+			},
+		},
+		{
+			name:      "b_e_oonnoticenotice",
+			condition: ImpliesNotice,
+			roots:     []string{"by_exception.meta_lic"},
+			edges: []annotated{
+				{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			},
+		},
+		{
+			name:      "b_e_oonnoticerestricted",
+			condition: ImpliesRestricted,
+			roots:     []string{"by_exception.meta_lic"},
+			edges: []annotated{
+				{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{},
+		},
+		{
+			name:      "b_e_oonnoticeb_e_o",
+			condition: ImpliesByExceptionOnly,
+			roots:     []string{"by_exception.meta_lic"},
+			edges: []annotated{
+				{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"},
+			},
+		},
+		{
+			name:      "noticeonrecipnotice",
+			condition: ImpliesNotice,
+			roots:     []string{"mitBin.meta_lic"},
+			edges: []annotated{
+				{"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"mitBin.meta_lic", "mitBin.meta_lic", "notice"},
+				{"mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"},
+			},
+		},
+		{
+			name:      "noticeonreciprecip",
+			condition: ImpliesReciprocal,
+			roots:     []string{"mitBin.meta_lic"},
+			edges: []annotated{
+				{"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"},
+			},
+		},
+		{
+			name:      "reciponnoticenotice",
+			condition: ImpliesNotice,
+			roots:     []string{"mplBin.meta_lic"},
+			edges: []annotated{
+				{"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"mplBin.meta_lic", "mplBin.meta_lic", "reciprocal"},
+				{"mitLib.meta_lic", "mitLib.meta_lic", "notice"},
+			},
+		},
+		{
+			name:      "reciponnoticerecip",
+			condition: ImpliesReciprocal,
+			roots:     []string{"mplBin.meta_lic"},
+			edges: []annotated{
+				{"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
+			},
+			expectedActions: []act{
+				{"mplBin.meta_lic", "mplBin.meta_lic", "reciprocal"},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			stderr := &bytes.Buffer{}
+			lg, err := toGraph(stderr, tt.roots, tt.edges)
+			if err != nil {
+				t.Errorf("unexpected test data error: got %w, want no error", err)
+				return
+			}
+			expectedAs := toActionSet(lg, tt.expectedActions)
+			ResolveTopDownConditions(lg)
+			actualAs := WalkActionsForCondition(lg, tt.condition)
+			checkResolvesActions(lg, actualAs, expectedAs, t)
 		})
 	}
 }
diff --git a/tools/compliance/readgraph.go b/tools/compliance/readgraph.go
index face775..c809a96 100644
--- a/tools/compliance/readgraph.go
+++ b/tools/compliance/readgraph.go
@@ -39,16 +39,13 @@
 	// target contains the parsed metadata or nil if an error
 	target *TargetNode
 
-	// edges contains the parsed dependencies
-	edges []*dependencyEdge
-
 	// err is nil unless an error occurs
 	err error
 }
 
 // receiver coordinates the tasks for reading and parsing license metadata files.
 type receiver struct {
-	// lg accumulates the read metadata and becomes the final resulting LicensGraph.
+	// lg accumulates the read metadata and becomes the final resulting LicenseGraph.
 	lg *LicenseGraph
 
 	// rootFS locates the root of the file system from which to read the files.
@@ -138,10 +135,7 @@
 
 				// record the parsed metadata (guarded by mutex)
 				recv.lg.mu.Lock()
-				recv.lg.targets[r.file] = r.target
-				if len(r.edges) > 0 {
-					recv.lg.edges = append(recv.lg.edges, r.edges...)
-				}
+				lg.targets[r.target.name] = r.target
 				recv.lg.mu.Unlock()
 			} else {
 				// finished -- nil the results channel
@@ -150,6 +144,21 @@
 		}
 	}
 
+	if lg != nil {
+		esize := 0
+		for _, tn := range lg.targets {
+			esize += len(tn.proto.Deps)
+		}
+		lg.edges = make(TargetEdgeList, 0, esize)
+		for _, tn := range lg.targets {
+			tn.licenseConditions = LicenseConditionSetFromNames(tn, tn.proto.LicenseConditions...)
+			err = addDependencies(lg, tn)
+			if err != nil {
+				return nil, fmt.Errorf("error indexing dependencies for %q: %w", tn.name, err)
+			}
+			tn.proto.Deps = []*license_metadata_proto.AnnotatedDependency{}
+		}
+	}
 	return lg, err
 
 }
@@ -158,43 +167,48 @@
 type targetNode struct {
 	proto license_metadata_proto.LicenseMetadata
 
-	// name is the path to the metadata file
+	// name is the path to the metadata file.
 	name string
-}
 
-// dependencyEdge describes a single edge in the license graph.
-type dependencyEdge struct {
-	// target identifies the target node being built and/or installed.
-	target string
+	// lg is the license graph the node belongs to.
+	lg *LicenseGraph
 
-	// dependency identifies the target node being depended on.
-	//
-	// i.e. `dependency` is necessary to build `target`.
-	dependency string
+	// edges identifies the dependencies of the target.
+	edges TargetEdgeList
 
-	// annotations are a set of text attributes attached to the edge.
-	//
-	// Policy prescribes meaning to a limited set of annotations; others
-	// are preserved and ignored.
-	annotations TargetEdgeAnnotations
+	// licenseConditions identifies the set of license conditions originating at the target node.
+	licenseConditions LicenseConditionSet
+
+	// resolution identifies the set of conditions resolved by acting on the target node.
+	resolution LicenseConditionSet
 }
 
 // addDependencies converts the proto AnnotatedDependencies into `edges`
-func addDependencies(edges *[]*dependencyEdge, target string, dependencies []*license_metadata_proto.AnnotatedDependency) error {
-	for _, ad := range dependencies {
+func addDependencies(lg *LicenseGraph, tn *TargetNode) error {
+	tn.edges = make(TargetEdgeList, 0,len(tn.proto.Deps))
+	for _, ad := range tn.proto.Deps {
 		dependency := ad.GetFile()
 		if len(dependency) == 0 {
 			return fmt.Errorf("missing dependency name")
 		}
+		dtn, ok := lg.targets[dependency]
+		if !ok {
+			return fmt.Errorf("unknown dependency name %q", dependency)
+		}
+		if dtn == nil {
+			return fmt.Errorf("nil dependency for name %q", dependency)
+		}
 		annotations := newEdgeAnnotations()
 		for _, a := range ad.Annotations {
 			// look up a common constant annotation string from a small map
 			// instead of creating 1000's of copies of the same 3 strings.
 			if ann, ok := RecognizedAnnotations[a]; ok {
-				annotations.annotations[ann] = true
+				annotations.annotations[ann] = struct{}{}
 			}
 		}
-		*edges = append(*edges, &dependencyEdge{target, dependency, annotations})
+		edge := &TargetEdge{tn, dtn, annotations}
+		lg.edges = append(lg.edges, edge)
+		tn.edges = append(tn.edges, edge)
 	}
 	return nil
 }
@@ -207,50 +221,44 @@
 	go func() {
 		f, err := recv.rootFS.Open(file)
 		if err != nil {
-			recv.results <- &result{file, nil, nil, fmt.Errorf("error opening license metadata %q: %w", file, err)}
+			recv.results <- &result{file, nil, fmt.Errorf("error opening license metadata %q: %w", file, err)}
 			return
 		}
 
 		// read the file
 		data, err := io.ReadAll(f)
 		if err != nil {
-			recv.results <- &result{file, nil, nil, fmt.Errorf("error reading license metadata %q: %w", file, err)}
+			recv.results <- &result{file, nil, fmt.Errorf("error reading license metadata %q: %w", file, err)}
 			return
 		}
+		f.Close()
 
-		tn := &TargetNode{name: file}
+		tn := &TargetNode{lg: recv.lg, name: file}
 
 		err = prototext.Unmarshal(data, &tn.proto)
 		if err != nil {
-			recv.results <- &result{file, nil, nil, fmt.Errorf("error license metadata %q: %w", file, err)}
+			recv.results <- &result{file, nil, fmt.Errorf("error license metadata %q: %w", file, err)}
 			return
 		}
 
-		edges := []*dependencyEdge{}
-		err = addDependencies(&edges, file, tn.proto.Deps)
-		if err != nil {
-			recv.results <- &result{file, nil, nil, fmt.Errorf("error license metadata dependency %q: %w", file, err)}
-			return
-		}
-		tn.proto.Deps = []*license_metadata_proto.AnnotatedDependency{}
-
 		// send result for this file and release task before scheduling dependencies,
 		// but do not signal done to WaitGroup until dependencies are scheduled.
-		recv.results <- &result{file, tn, edges, nil}
+		recv.results <- &result{file, tn, nil}
 		recv.task <- true
 
 		// schedule tasks as necessary to read dependencies
-		for _, e := range edges {
+		for _, ad := range tn.proto.Deps {
+			dependency := ad.GetFile()
 			// decide, signal and record whether to schedule task in critical section
 			recv.lg.mu.Lock()
-			_, alreadyScheduled := recv.lg.targets[e.dependency]
+			_, alreadyScheduled := recv.lg.targets[dependency]
 			if !alreadyScheduled {
-				recv.lg.targets[e.dependency] = nil
+				recv.lg.targets[dependency] = nil
 			}
 			recv.lg.mu.Unlock()
 			// schedule task to read dependency file outside critical section
 			if !alreadyScheduled {
-				readFile(recv, e.dependency)
+				readFile(recv, dependency)
 			}
 		}
 
diff --git a/tools/compliance/readgraph_test.go b/tools/compliance/readgraph_test.go
index 6248209..6ff7a6c 100644
--- a/tools/compliance/readgraph_test.go
+++ b/tools/compliance/readgraph_test.go
@@ -108,29 +108,40 @@
 			}
 			sort.Sort(byEdge(tt.expectedEdges))
 			sort.Sort(byEdge(actualEdges))
+			t.Logf("actualEdges:")
+			for _, edge := range actualEdges {
+				t.Logf("  %s", edge.String())
+			}
+			t.Logf("expectedEdges:")
+			for _, edge := range actualEdges {
+				t.Logf("  %s", edge.String())
+			}
 			if len(tt.expectedEdges) != len(actualEdges) {
-				t.Errorf("unexpected number of edges: got %v with %d elements, want %v with %d elements",
-					actualEdges, len(actualEdges), tt.expectedEdges, len(tt.expectedEdges))
+				t.Errorf("len(actualEdges): got %d, want %d", len(actualEdges), len(tt.expectedEdges))
 			} else {
 				for i := 0; i < len(actualEdges); i++ {
 					if tt.expectedEdges[i] != actualEdges[i] {
-						t.Errorf("unexpected edge at element %d: got %s, want %s", i, actualEdges[i], tt.expectedEdges[i])
+						t.Errorf("actualEdges[%d]: got %s, want %s", i, actualEdges[i], tt.expectedEdges[i])
 					}
 				}
 			}
+
 			actualTargets := make([]string, 0)
 			for _, t := range lg.Targets() {
 				actualTargets = append(actualTargets, t.Name())
 			}
 			sort.Strings(tt.expectedTargets)
 			sort.Strings(actualTargets)
+
+			t.Logf("actualTargets: %v", actualTargets)
+			t.Logf("expectedTargets: %v", tt.expectedTargets)
+
 			if len(tt.expectedTargets) != len(actualTargets) {
-				t.Errorf("unexpected number of targets: got %v with %d elements, want %v with %d elements",
-					actualTargets, len(actualTargets), tt.expectedTargets, len(tt.expectedTargets))
+				t.Errorf("len(actualTargets): got %d, want %d", len(actualTargets), len(tt.expectedTargets))
 			} else {
 				for i := 0; i < len(actualTargets); i++ {
 					if tt.expectedTargets[i] != actualTargets[i] {
-						t.Errorf("unexpected target at element %d: got %s, want %s", i, actualTargets[i], tt.expectedTargets[i])
+						t.Errorf("actualTargets[%d]: got %s, want %s", i, actualTargets[i], tt.expectedTargets[i])
 					}
 				}
 			}
diff --git a/tools/compliance/resolution.go b/tools/compliance/resolution.go
index 0865ecd..6f15ca3 100644
--- a/tools/compliance/resolution.go
+++ b/tools/compliance/resolution.go
@@ -32,7 +32,7 @@
 // resolve the restricted condition originating from the GPL code.
 type Resolution struct {
 	attachesTo, actsOn *TargetNode
-	cs                 *LicenseConditionSet
+	cs                 LicenseConditionSet
 }
 
 // AttachesTo returns the target node the resolution attaches to.
@@ -48,16 +48,16 @@
 }
 
 // Resolves returns the set of license condition the resolution satisfies.
-func (r Resolution) Resolves() *LicenseConditionSet {
-	return r.cs.Copy()
+func (r Resolution) Resolves() LicenseConditionSet {
+	return r.cs
 }
 
 // asString returns a string representation of the resolution.
 func (r Resolution) asString() string {
 	var sb strings.Builder
-	cl := r.cs.AsList()
-	sort.Sort(cl)
-	fmt.Fprintf(&sb, "%s -> %s -> %s", r.attachesTo.name, r.actsOn.name, cl.String())
+	names := r.cs.Names()
+	sort.Strings(names)
+	fmt.Fprintf(&sb, "%s -> %s{%s}", r.attachesTo.name, r.actsOn.name, strings.Join(names, ", "))
 	return sb.String()
 }
 
@@ -94,67 +94,32 @@
 
 // AllConditions returns the union of all license conditions resolved by any
 // element of the list.
-func (rl ResolutionList) AllConditions() *LicenseConditionSet {
-	result := newLicenseConditionSet()
+func (rl ResolutionList) AllConditions() LicenseConditionSet {
+	result := NewLicenseConditionSet()
 	for _, r := range rl {
-		result.AddSet(r.cs)
+		result = result.Union(r.cs)
 	}
 	return result
 }
 
 // ByName returns the sub-list of resolutions resolving conditions matching
 // `names`.
-func (rl ResolutionList) ByName(names ConditionNames) ResolutionList {
-	result := make(ResolutionList, 0, rl.CountByName(names))
+func (rl ResolutionList) Matching(conditions LicenseConditionSet) ResolutionList {
+	result := make(ResolutionList, 0, rl.CountMatching(conditions))
 	for _, r := range rl {
-		if r.Resolves().HasAnyByName(names) {
-			result = append(result, Resolution{r.attachesTo, r.actsOn, r.cs.ByName(names)})
+		if r.Resolves().MatchesAnySet(conditions) {
+			result = append(result, Resolution{r.attachesTo, r.actsOn, r.cs.MatchingAnySet(conditions)})
 		}
 	}
 	return result
 }
 
-// CountByName returns the number of resolutions resolving conditions matching
-// `names`.
-func (rl ResolutionList) CountByName(names ConditionNames) int {
+// CountMatching returns the number of resolutions resolving conditions matching
+// `conditions`.
+func (rl ResolutionList) CountMatching(conditions LicenseConditionSet) int {
 	c := 0
 	for _, r := range rl {
-		if r.Resolves().HasAnyByName(names) {
-			c++
-		}
-	}
-	return c
-}
-
-// CountConditionsByName returns a count of distinct resolution/conditions
-// pairs matching `names`.
-//
-// A single resolution might resolve multiple conditions matching `names`.
-func (rl ResolutionList) CountConditionsByName(names ConditionNames) int {
-	c := 0
-	for _, r := range rl {
-		c += r.Resolves().CountByName(names)
-	}
-	return c
-}
-
-// ByAttachesTo returns the sub-list of resolutions attached to `attachesTo`.
-func (rl ResolutionList) ByAttachesTo(attachesTo *TargetNode) ResolutionList {
-	result := make(ResolutionList, 0, rl.CountByActsOn(attachesTo))
-	for _, r := range rl {
-		if r.attachesTo == attachesTo {
-			result = append(result, r)
-		}
-	}
-	return result
-}
-
-// CountByAttachesTo returns the number of resolutions attached to
-// `attachesTo`.
-func (rl ResolutionList) CountByAttachesTo(attachesTo *TargetNode) int {
-	c := 0
-	for _, r := range rl {
-		if r.attachesTo == attachesTo {
+		if r.Resolves().MatchesAnySet(conditions) {
 			c++
 		}
 	}
@@ -182,27 +147,3 @@
 	}
 	return c
 }
-
-// ByOrigin returns the sub-list of resolutions resolving license conditions
-// originating at `origin`.
-func (rl ResolutionList) ByOrigin(origin *TargetNode) ResolutionList {
-	result := make(ResolutionList, 0, rl.CountByOrigin(origin))
-	for _, r := range rl {
-		if r.Resolves().HasAnyByOrigin(origin) {
-			result = append(result, Resolution{r.attachesTo, r.actsOn, r.cs.ByOrigin(origin)})
-		}
-	}
-	return result
-}
-
-// CountByOrigin returns the number of resolutions resolving license conditions
-// originating at `origin`.
-func (rl ResolutionList) CountByOrigin(origin *TargetNode) int {
-	c := 0
-	for _, r := range rl {
-		if r.Resolves().HasAnyByOrigin(origin) {
-			c++
-		}
-	}
-	return c
-}
diff --git a/tools/compliance/resolutionset.go b/tools/compliance/resolutionset.go
index ea49db9..893ef26 100644
--- a/tools/compliance/resolutionset.go
+++ b/tools/compliance/resolutionset.go
@@ -19,34 +19,6 @@
 	"strings"
 )
 
-// JoinResolutionSets returns a new ResolutionSet combining the resolutions from
-// multiple resolution sets. All sets must be derived from the same license
-// graph.
-//
-// e.g. combine "restricted", "reciprocal", and "proprietary" resolutions.
-func JoinResolutionSets(resolutions ...*ResolutionSet) *ResolutionSet {
-	if len(resolutions) < 1 {
-		panic(fmt.Errorf("attempt to join 0 resolution sets"))
-	}
-	rmap := make(map[*TargetNode]actionSet)
-	for _, r := range resolutions {
-		if len(r.resolutions) < 1 {
-			continue
-		}
-		for attachesTo, as := range r.resolutions {
-			if as.isEmpty() {
-				continue
-			}
-			if _, ok := rmap[attachesTo]; !ok {
-				rmap[attachesTo] = as.copy()
-				continue
-			}
-			rmap[attachesTo].addSet(as)
-		}
-	}
-	return &ResolutionSet{rmap}
-}
-
 // ResolutionSet describes an immutable set of targets and the license
 // conditions each target must satisfy or "resolve" in a specific context.
 //
@@ -68,8 +40,8 @@
 //
 // An "unencumbered" condition would originate from the binary, and a "notice"
 // condition would originate from the .a library. A ResolutionSet for the
-// context of the Notice policy might apply both conditions to the binary while
-// preserving the origin of each condition. By applying the notice condition to
+// context of the Notice policy might attach both conditions to the binary to
+// act on the origin of each condition. By attaching the notice condition to
 // the binary, the ResolutionSet stipulates the policy that the release of the
 // unencumbered binary must provide suitable notice for the .a library.
 //
@@ -77,228 +49,71 @@
 // validating that a suitable notice has been built into the distribution, or
 // for reporting what notices need to be given.
 //
-// Resolutions for different contexts may be combined in a new ResolutionSet
-// using JoinResolutions(...).
-//
-// See: resolve.go for:
-//  * ResolveBottomUpConditions(...)
-//  * ResolveTopDownForCondition(...)
-// See also: policy.go for:
-//  * ResolveSourceSharing(...)
-//  * ResolveSourcePrivacy(...)
-type ResolutionSet struct {
-	// resolutions maps names of target with applicable conditions to the set of conditions that apply.
-	resolutions map[*TargetNode]actionSet
+// The action is defined by the context. In the above example, the action is
+// providing notice for the module acted on. In another context, the action
+// might be sharing the source-code or preserving the privacy of the module
+// acted on.
+type ResolutionSet map[*TargetNode]ActionSet
+
+// AttachesTo identifies the list of targets triggering action to resolve
+// conditions. (unordered)
+func (rs ResolutionSet) AttachesTo() TargetNodeList {
+	result := make(TargetNodeList, 0, len(rs))
+	for attachesTo := range rs {
+		result = append(result, attachesTo)
+	}
+	return result
 }
 
-// String returns a string representation of the set.
-func (rs *ResolutionSet) String() string {
+
+// AttachesToTarget returns true if the set contains conditions that
+// are `attachedTo`.
+func (rs ResolutionSet) AttachesToTarget(target *TargetNode) bool {
+	_, isPresent := rs[target]
+	return isPresent
+}
+
+
+// Resolutions returns the list of resolutions that `attachedTo`
+// target must resolve. Returns empty list if no conditions apply.
+func (rs ResolutionSet) Resolutions(attachesTo *TargetNode) ResolutionList {
+	as, ok := rs[attachesTo]
+	if !ok {
+		return nil
+	}
+	result := make(ResolutionList, 0, len(as))
+	for actsOn, cs := range as {
+		result = append(result, Resolution{attachesTo, actsOn, cs})
+	}
+	return result
+}
+
+// String returns a human-readable string representation of the set.
+func (rs ResolutionSet) String() string {
 	var sb strings.Builder
 	fmt.Fprintf(&sb, "{")
 	sep := ""
-	for attachesTo, as := range rs.resolutions {
-		fmt.Fprintf(&sb, "%s%s -> %s", sep, attachesTo.name, as.String())
+	for attachesTo, as := range rs {
+		fmt.Fprintf(&sb, "%s%s -> %s", sep, attachesTo.Name(), as.String())
 		sep = ", "
 	}
 	fmt.Fprintf(&sb, "}")
 	return sb.String()
 }
 
-// AttachesTo identifies the list of targets triggering action to resolve
-// conditions. (unordered)
-func (rs *ResolutionSet) AttachesTo() TargetNodeList {
-	targets := make(TargetNodeList, 0, len(rs.resolutions))
-	for attachesTo := range rs.resolutions {
-		targets = append(targets, attachesTo)
-	}
-	return targets
-}
+// ActionSet identifies a set of targets to act on and the license conditions
+// the action will resolve.
+type ActionSet map[*TargetNode]LicenseConditionSet
 
-// ActsOn identifies the list of targets to act on (share, give notice etc.)
-// to resolve conditions. (unordered)
-func (rs *ResolutionSet) ActsOn() TargetNodeList {
-	tset := make(map[*TargetNode]bool)
-	for _, as := range rs.resolutions {
-		for actsOn := range as {
-			tset[actsOn] = true
-		}
-	}
-	targets := make(TargetNodeList, 0, len(tset))
-	for target := range tset {
-		targets = append(targets, target)
-	}
-	return targets
-}
-
-// Origins identifies the list of targets originating conditions to resolve.
-// (unordered)
-func (rs *ResolutionSet) Origins() TargetNodeList {
-	tset := make(map[*TargetNode]bool)
-	for _, as := range rs.resolutions {
-		for _, cs := range as {
-			for _, origins := range cs.conditions {
-				for origin := range origins {
-					tset[origin] = true
-				}
-			}
-		}
-	}
-	targets := make(TargetNodeList, 0, len(tset))
-	for target := range tset {
-		targets = append(targets, target)
-	}
-	return targets
-}
-
-// Resolutions returns the list of resolutions that `attachedTo`
-// target must resolve. Returns empty list if no conditions apply.
-//
-// Panics if `attachedTo` does not appear in the set.
-func (rs *ResolutionSet) Resolutions(attachedTo *TargetNode) ResolutionList {
-	as, ok := rs.resolutions[attachedTo]
-	if !ok {
-		return ResolutionList{}
-	}
-	result := make(ResolutionList, 0, len(as))
+// String returns a human-readable string representation of the set.
+func (as ActionSet) String() string {
+	var sb strings.Builder
+	fmt.Fprintf(&sb, "{")
+	sep := ""
 	for actsOn, cs := range as {
-		result = append(result, Resolution{attachedTo, actsOn, cs.Copy()})
+		fmt.Fprintf(&sb, "%s%s%s", sep, actsOn.Name(), cs.String())
+		sep = ", "
 	}
-	return result
-}
-
-// ResolutionsByActsOn returns the list of resolutions that must `actOn` to
-// resolvee. Returns empty list if no conditions apply.
-//
-// Panics if `actOn` does not appear in the set.
-func (rs *ResolutionSet) ResolutionsByActsOn(actOn *TargetNode) ResolutionList {
-	c := 0
-	for _, as := range rs.resolutions {
-		if _, ok := as[actOn]; ok {
-			c++
-		}
-	}
-	result := make(ResolutionList, 0, c)
-	for attachedTo, as := range rs.resolutions {
-		if cs, ok := as[actOn]; ok {
-			result = append(result, Resolution{attachedTo, actOn, cs.Copy()})
-		}
-	}
-	return result
-}
-
-// AttachesToByOrigin identifies the list of targets requiring action to
-// resolve conditions originating at `origin`. (unordered)
-func (rs *ResolutionSet) AttachesToByOrigin(origin *TargetNode) TargetNodeList {
-	tset := make(map[*TargetNode]bool)
-	for attachesTo, as := range rs.resolutions {
-		for _, cs := range as {
-			if cs.HasAnyByOrigin(origin) {
-				tset[attachesTo] = true
-				break
-			}
-		}
-	}
-	targets := make(TargetNodeList, 0, len(tset))
-	for target := range tset {
-		targets = append(targets, target)
-	}
-	return targets
-}
-
-// AttachesToTarget returns true if the set contains conditions that
-// are `attachedTo`.
-func (rs *ResolutionSet) AttachesToTarget(attachedTo *TargetNode) bool {
-	_, isPresent := rs.resolutions[attachedTo]
-	return isPresent
-}
-
-// AnyByNameAttachToTarget returns true if the set contains conditions matching
-// `names` that attach to `attachedTo`.
-func (rs *ResolutionSet) AnyByNameAttachToTarget(attachedTo *TargetNode, names ...ConditionNames) bool {
-	as, isPresent := rs.resolutions[attachedTo]
-	if !isPresent {
-		return false
-	}
-	for _, cs := range as {
-		for _, cn := range names {
-			for _, name := range cn {
-				_, isPresent = cs.conditions[name]
-				if isPresent {
-					return true
-				}
-			}
-		}
-	}
-	return false
-}
-
-// AllByNameAttachTo returns true if the set contains at least one condition
-// matching each element of `names` for `attachedTo`.
-func (rs *ResolutionSet) AllByNameAttachToTarget(attachedTo *TargetNode, names ...ConditionNames) bool {
-	as, isPresent := rs.resolutions[attachedTo]
-	if !isPresent {
-		return false
-	}
-	for _, cn := range names {
-		found := false
-	asloop:
-		for _, cs := range as {
-			for _, name := range cn {
-				_, isPresent = cs.conditions[name]
-				if isPresent {
-					found = true
-					break asloop
-				}
-			}
-		}
-		if !found {
-			return false
-		}
-	}
-	return true
-}
-
-// IsEmpty returns true if the set contains no conditions to resolve.
-func (rs *ResolutionSet) IsEmpty() bool {
-	for _, as := range rs.resolutions {
-		if !as.isEmpty() {
-			return false
-		}
-	}
-	return true
-}
-
-// compliance-only ResolutionSet methods
-
-// newResolutionSet constructs a new, empty instance of resolutionSetImp for graph `lg`.
-func newResolutionSet() *ResolutionSet {
-	return &ResolutionSet{make(map[*TargetNode]actionSet)}
-}
-
-// addConditions attaches all of the license conditions in `as` to `attachTo` to act on the originating node if not already applied.
-func (rs *ResolutionSet) addConditions(attachTo *TargetNode, as actionSet) {
-	_, ok := rs.resolutions[attachTo]
-	if !ok {
-		rs.resolutions[attachTo] = as.copy()
-		return
-	}
-	rs.resolutions[attachTo].addSet(as)
-}
-
-// add attaches all of the license conditions in `as` to `attachTo` to act on `attachTo` if not already applied.
-func (rs *ResolutionSet) addSelf(attachTo *TargetNode, as actionSet) {
-	for _, cs := range as {
-		if cs.IsEmpty() {
-			return
-		}
-		_, ok := rs.resolutions[attachTo]
-		if !ok {
-			rs.resolutions[attachTo] = make(actionSet)
-		}
-		_, ok = rs.resolutions[attachTo][attachTo]
-		if !ok {
-			rs.resolutions[attachTo][attachTo] = newLicenseConditionSet()
-		}
-		rs.resolutions[attachTo][attachTo].AddSet(cs)
-	}
+	fmt.Fprintf(&sb, "}")
+	return sb.String()
 }
diff --git a/tools/compliance/resolutionset_test.go b/tools/compliance/resolutionset_test.go
index e50e823..89cdfeb 100644
--- a/tools/compliance/resolutionset_test.go
+++ b/tools/compliance/resolutionset_test.go
@@ -77,113 +77,46 @@
 	proprietary = []res{}
 )
 
-func TestResolutionSet_JoinResolutionSets(t *testing.T) {
-	lg := newLicenseGraph()
-
-	rsNotice := toResolutionSet(lg, notice)
-	rsShare := toResolutionSet(lg, share)
-	rsExpected := toResolutionSet(lg, append(notice, share...))
-
-	rsActual := JoinResolutionSets(rsNotice, rsShare)
-	checkSame(rsActual, rsExpected, t)
-}
-
-func TestResolutionSet_JoinResolutionsEmpty(t *testing.T) {
-	lg := newLicenseGraph()
-
-	rsShare := toResolutionSet(lg, share)
-	rsProprietary := toResolutionSet(lg, proprietary)
-	rsExpected := toResolutionSet(lg, append(share, proprietary...))
-
-	rsActual := JoinResolutionSets(rsShare, rsProprietary)
-	checkSame(rsActual, rsExpected, t)
-}
-
-func TestResolutionSet_Origins(t *testing.T) {
+func TestResolutionSet_AttachesTo(t *testing.T) {
 	lg := newLicenseGraph()
 
 	rsShare := toResolutionSet(lg, share)
 
-	origins := make([]string, 0)
-	for _, target := range rsShare.Origins() {
-		origins = append(origins, target.Name())
-	}
-	sort.Strings(origins)
-	if len(origins) != 2 {
-		t.Errorf("unexpected number of origins: got %v with %d elements, want [\"bin1\", \"bin2\"] with 2 elements", origins, len(origins))
-	}
-	if origins[0] != "bin1" {
-		t.Errorf("unexpected origin at element 0: got %s, want \"bin1\"", origins[0])
-	}
-	if origins[1] != "bin2" {
-		t.Errorf("unexpected origin at element 0: got %s, want \"bin2\"", origins[0])
-	}
-}
+	t.Logf("checking resolution set %s", rsShare.String())
 
-func TestResolutionSet_AttachedToTarget(t *testing.T) {
-	lg := newLicenseGraph()
+	actual := rsShare.AttachesTo().Names()
+	sort.Strings(actual)
 
-	rsShare := toResolutionSet(lg, share)
+	expected := []string{"bin1", "bin2", "image"}
 
-	if rsShare.AttachesToTarget(newTestNode(lg, "binc")) {
-		t.Errorf("unexpected AttachedToTarget(\"binc\"): got true, want false")
-	}
-	if !rsShare.AttachesToTarget(newTestNode(lg, "image")) {
-		t.Errorf("unexpected AttachedToTarget(\"image\"): got false want true")
-	}
-}
+	t.Logf("actual rsShare: %v", actual)
+	t.Logf("expected rsShare: %v", expected)
 
-func TestResolutionSet_AnyByNameAttachToTarget(t *testing.T) {
-	lg := newLicenseGraph()
+	if len(actual) != len(expected) {
+		t.Errorf("rsShare: wrong number of targets: got %d, want %d", len(actual), len(expected))
+		return
+	}
+	for i := 0; i < len(actual); i++ {
+		if actual[i] != expected[i] {
+			t.Errorf("rsShare: unexpected target at index %d: got %s, want %s", i, actual[i], expected[i])
+		}
+	}
 
-	rs := toResolutionSet(lg, bottomUp)
+	rsPrivate := toResolutionSet(lg, proprietary)
+	actual = rsPrivate.AttachesTo().Names()
+	expected = []string{}
 
-	pandp := ConditionNames{"permissive", "proprietary"}
-	pandn := ConditionNames{"permissive", "notice"}
-	p := ConditionNames{"proprietary"}
-	r := ConditionNames{"restricted"}
+	t.Logf("actual rsPrivate: %v", actual)
+	t.Logf("expected rsPrivate: %v", expected)
 
-	if rs.AnyByNameAttachToTarget(newTestNode(lg, "image"), pandp, p) {
-		t.Errorf("unexpected AnyByNameAttachToTarget(\"image\", \"proprietary\", \"permissive\"): want false, got true")
+	if len(actual) != len(expected) {
+		t.Errorf("rsPrivate: wrong number of targets: got %d, want %d", len(actual), len(expected))
+		return
 	}
-	if !rs.AnyByNameAttachToTarget(newTestNode(lg, "binc"), p) {
-		t.Errorf("unexpected AnyByNameAttachToTarget(\"binc\", \"proprietary\"): want true, got false")
-	}
-	if !rs.AnyByNameAttachToTarget(newTestNode(lg, "image"), pandn) {
-		t.Errorf("unexpected AnyByNameAttachToTarget(\"image\", \"permissive\", \"notice\"): want true, got false")
-	}
-	if !rs.AnyByNameAttachToTarget(newTestNode(lg, "image"), r, pandn) {
-		t.Errorf("unexpected AnyByNameAttachToTarget(\"image\", \"restricted\", \"notice\"): want true, got false")
-	}
-	if !rs.AnyByNameAttachToTarget(newTestNode(lg, "image"), r, p) {
-		t.Errorf("unexpected AnyByNameAttachToTarget(\"image\", \"restricted\", \"proprietary\"): want true, got false")
-	}
-}
-
-func TestResolutionSet_AllByNameAttachToTarget(t *testing.T) {
-	lg := newLicenseGraph()
-
-	rs := toResolutionSet(lg, bottomUp)
-
-	pandp := ConditionNames{"permissive", "proprietary"}
-	pandn := ConditionNames{"permissive", "notice"}
-	p := ConditionNames{"proprietary"}
-	r := ConditionNames{"restricted"}
-
-	if rs.AllByNameAttachToTarget(newTestNode(lg, "image"), pandp, p) {
-		t.Errorf("unexpected AllByNameAttachToTarget(\"image\", \"proprietary\", \"permissive\"): want false, got true")
-	}
-	if !rs.AllByNameAttachToTarget(newTestNode(lg, "binc"), p) {
-		t.Errorf("unexpected AllByNameAttachToTarget(\"binc\", \"proprietary\"): want true, got false")
-	}
-	if !rs.AllByNameAttachToTarget(newTestNode(lg, "image"), pandn) {
-		t.Errorf("unexpected AllByNameAttachToTarget(\"image\", \"notice\"): want true, got false")
-	}
-	if !rs.AllByNameAttachToTarget(newTestNode(lg, "image"), r, pandn) {
-		t.Errorf("unexpected AllByNameAttachToTarget(\"image\", \"restricted\", \"notice\"): want true, got false")
-	}
-	if rs.AllByNameAttachToTarget(newTestNode(lg, "image"), r, p) {
-		t.Errorf("unexpected AllByNameAttachToTarget(\"image\", \"restricted\", \"proprietary\"): want false, got true")
+	for i := 0; i < len(actual); i++ {
+		if actual[i] != expected[i] {
+			t.Errorf("rsPrivate: unexpected target at index %d: got %s, want %s", i, actual[i], expected[i])
+		}
 	}
 }
 
@@ -192,10 +125,12 @@
 
 	rsShare := toResolutionSet(lg, share)
 
+	t.Logf("checking resolution set %s", rsShare.String())
+
 	if rsShare.AttachesToTarget(newTestNode(lg, "binc")) {
-		t.Errorf("unexpected hasTarget(\"binc\"): got true, want false")
+		t.Errorf("actual.AttachesToTarget(\"binc\"): got true, want false")
 	}
 	if !rsShare.AttachesToTarget(newTestNode(lg, "image")) {
-		t.Errorf("unexpected AttachesToTarget(\"image\"): got false want true")
+		t.Errorf("actual.AttachesToTarget(\"image\"): got false want true")
 	}
 }
diff --git a/tools/compliance/test_util.go b/tools/compliance/test_util.go
index a183b90..8f4088a 100644
--- a/tools/compliance/test_util.go
+++ b/tools/compliance/test_util.go
@@ -86,7 +86,6 @@
 license_kinds: "legacy_by_exception_only"
 license_conditions: "by_exception_only"
 `
-
 )
 
 var (
@@ -111,23 +110,39 @@
 	}
 )
 
-// toConditionList converts a test data map of condition name to origin names into a ConditionList.
-func toConditionList(lg *LicenseGraph, conditions map[string][]string) ConditionList {
-	cl := make(ConditionList, 0)
-	for name, origins := range conditions {
-		for _, origin := range origins {
-			cl = append(cl, LicenseCondition{name, newTestNode(lg, origin)})
-		}
-	}
-	return cl
-}
-
 // newTestNode constructs a test node in the license graph.
 func newTestNode(lg *LicenseGraph, targetName string) *TargetNode {
-	if _, ok := lg.targets[targetName]; !ok {
-		lg.targets[targetName] = &TargetNode{name: targetName}
+	if tn, alreadyExists := lg.targets[targetName]; alreadyExists {
+		return tn
 	}
-	return lg.targets[targetName]
+	tn := &TargetNode{name: targetName}
+	lg.targets[targetName] = tn
+	return tn
+}
+
+// newTestCondition constructs a test license condition in the license graph.
+func newTestCondition(lg *LicenseGraph, targetName string, conditionName string) LicenseCondition {
+	tn := newTestNode(lg, targetName)
+	cl := LicenseConditionSetFromNames(tn, conditionName).AsList()
+	if len(cl) == 0 {
+		panic(fmt.Errorf("attempt to create unrecognized condition: %q", conditionName))
+	} else if len(cl) != 1 {
+		panic(fmt.Errorf("unexpected multiple conditions from condition name: %q: got %d, want 1", conditionName, len(cl)))
+	}
+	lc := cl[0]
+	tn.licenseConditions = tn.licenseConditions.Plus(lc)
+	return lc
+}
+
+// newTestConditionSet constructs a test license condition set in the license graph.
+func newTestConditionSet(lg *LicenseGraph, targetName string, conditionName []string) LicenseConditionSet {
+	tn := newTestNode(lg, targetName)
+	cs := LicenseConditionSetFromNames(tn, conditionName...)
+	if cs.IsEmpty() {
+		panic(fmt.Errorf("attempt to create unrecognized condition: %q", conditionName))
+	}
+	tn.licenseConditions = tn.licenseConditions.Union(cs)
+	return cs
 }
 
 // testFS implements a test file system (fs.FS) simulated by a map from filename to []byte content.
@@ -270,6 +285,21 @@
 	return ReadLicenseGraph(&fs, stderr, roots)
 }
 
+// logGraph outputs a representation of the graph to a test log.
+func logGraph(lg *LicenseGraph, t *testing.T) {
+	t.Logf("license graph:")
+	t.Logf("  targets:")
+	for _, target := range lg.Targets() {
+		t.Logf("    %s%s in package %q", target.Name(), target.LicenseConditions().String(), target.PackageName())
+	}
+	t.Logf("  /targets")
+	t.Logf("  edges:")
+	for _, edge := range lg.Edges() {
+		t.Logf("    %s", edge.String())
+	}
+	t.Logf("  /edges")
+	t.Logf("/license graph")
+}
 
 // byAnnotatedEdge orders edges by target then dep name then annotations.
 type byAnnotatedEdge []annotated
@@ -296,33 +326,137 @@
 	return l[i].target < l[j].target
 }
 
+// act describes test data resolution actions to define test action sets.
+type act struct {
+	actsOn, origin, condition string
+}
+
+// String returns a human-readable string representing the test action.
+func (a act) String() string {
+	return fmt.Sprintf("%s{%s:%s}", a.actsOn, a.origin, a.condition)
+}
+
+// toActionSet converts a list of act test data into a test action set.
+func toActionSet(lg *LicenseGraph, data []act) ActionSet {
+	as := make(ActionSet)
+	for _, a := range data {
+		actsOn := newTestNode(lg, a.actsOn)
+		cs := newTestConditionSet(lg, a.origin, strings.Split(a.condition, "|"))
+		as[actsOn] = cs
+	}
+	return as
+}
+
 // res describes test data resolutions to define test resolution sets.
 type res struct {
 	attachesTo, actsOn, origin, condition string
 }
 
 // toResolutionSet converts a list of res test data into a test resolution set.
-func toResolutionSet(lg *LicenseGraph, data []res) *ResolutionSet {
-	rmap := make(map[*TargetNode]actionSet)
+func toResolutionSet(lg *LicenseGraph, data []res) ResolutionSet {
+	rmap := make(ResolutionSet)
 	for _, r := range data {
 		attachesTo := newTestNode(lg, r.attachesTo)
 		actsOn := newTestNode(lg, r.actsOn)
-		origin := newTestNode(lg, r.origin)
 		if _, ok := rmap[attachesTo]; !ok {
-			rmap[attachesTo] = make(actionSet)
+			rmap[attachesTo] = make(ActionSet)
 		}
-		if _, ok := rmap[attachesTo][actsOn]; !ok {
-			rmap[attachesTo][actsOn] = newLicenseConditionSet()
-		}
-		rmap[attachesTo][actsOn].add(origin, r.condition)
+		cs := newTestConditionSet(lg, r.origin, strings.Split(r.condition, ":"))
+		rmap[attachesTo][actsOn] |= cs
 	}
-	return &ResolutionSet{rmap}
+	return rmap
 }
 
+// tcond associates a target name with '|' separated string conditions.
+type tcond struct {
+	target, conditions string
+}
+
+// action represents a single element of an ActionSet for testing.
+type action struct {
+	target *TargetNode
+	cs     LicenseConditionSet
+}
+
+// String returns a human-readable string representation of the action.
+func (a action) String() string {
+	return fmt.Sprintf("%s%s", a.target.Name(), a.cs.String())
+}
+
+// actionList represents an array of actions and a total order defined by
+// target name followed by license condition set.
+type actionList []action
+
+// String returns a human-readable string representation of the list.
+func (l actionList) String() string {
+	var sb strings.Builder
+	fmt.Fprintf(&sb, "[")
+	sep := ""
+	for _, a := range l {
+		fmt.Fprintf(&sb, "%s%s", sep, a.String())
+		sep = ", "
+	}
+	fmt.Fprintf(&sb, "]")
+	return sb.String()
+}
+
+// Len returns the count of elements in the slice.
+func (l actionList) Len() int      { return len(l) }
+
+// Swap rearranges 2 elements of the slice so that each occupies the other's
+// former position.
+func (l actionList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+
+// Less returns true when the `i`th element is lexicographically less than
+// the `j`th element.
+func (l actionList) Less(i, j int) bool {
+	if l[i].target == l[j].target {
+		return l[i].cs < l[j].cs
+	}
+	return l[i].target.Name() < l[j].target.Name()
+}
+
+// asActionList represents the resolved license conditions in a license graph
+// as an actionList for comparison in a test.
+func asActionList(lg *LicenseGraph) actionList {
+	result := make(actionList, 0, len(lg.targets))
+	for _, target := range lg.targets {
+		cs := target.resolution
+		if cs.IsEmpty() {
+			continue
+		}
+		result = append(result, action{target, cs})
+	}
+	return result
+}
+
+// toActionList converts an array of tcond into an actionList for comparison
+// in a test.
+func toActionList(lg *LicenseGraph, actions []tcond) actionList {
+	result := make(actionList, 0, len(actions))
+	for _, actn := range actions {
+		target := newTestNode(lg, actn.target)
+		cs := NewLicenseConditionSet()
+		for _, name := range strings.Split(actn.conditions, "|") {
+			lc, ok := RecognizedConditionNames[name]
+			if !ok {
+				panic(fmt.Errorf("Unrecognized test condition name: %q", name))
+			}
+			cs = cs.Plus(lc)
+		}
+		result = append(result, action{target, cs})
+	}
+	return result
+}
+
+// confl defines test data for a SourceSharePrivacyConflict as a target name,
+// source condition name, privacy condition name triple.
 type confl struct {
 	sourceNode, share, privacy string
 }
 
+// toConflictList converts confl test data into an array of
+// SourceSharePrivacyConflict for comparison in a test.
 func toConflictList(lg *LicenseGraph, data []confl) []SourceSharePrivacyConflict {
 	result := make([]SourceSharePrivacyConflict, 0, len(data))
 	for _, c := range data {
@@ -334,30 +468,40 @@
 		cprivacy := fields[1]
 		result = append(result, SourceSharePrivacyConflict{
 				newTestNode(lg, c.sourceNode),
-				LicenseCondition{cshare, newTestNode(lg, oshare)},
-				LicenseCondition{cprivacy, newTestNode(lg, oprivacy)},
+				newTestCondition(lg, oshare, cshare),
+				newTestCondition(lg, oprivacy, cprivacy),
 			})
 	}
 	return result
 }
 
 // checkSameActions compares an actual action set to an expected action set for a test.
-func checkSameActions(lg *LicenseGraph, asActual, asExpected actionSet, t *testing.T) {
-	rsActual := ResolutionSet{make(map[*TargetNode]actionSet)}
-	rsExpected := ResolutionSet{make(map[*TargetNode]actionSet)}
+func checkSameActions(lg *LicenseGraph, asActual, asExpected ActionSet, t *testing.T) {
+	rsActual := make(ResolutionSet)
+	rsExpected := make(ResolutionSet)
 	testNode := newTestNode(lg, "test")
-	rsActual.resolutions[testNode] = asActual
-	rsExpected.resolutions[testNode] = asExpected
-	checkSame(&rsActual, &rsExpected, t)
+	rsActual[testNode] = asActual
+	rsExpected[testNode] = asExpected
+	checkSame(rsActual, rsExpected, t)
 }
 
 // checkSame compares an actual resolution set to an expected resolution set for a test.
-func checkSame(rsActual, rsExpected *ResolutionSet, t *testing.T) {
+func checkSame(rsActual, rsExpected ResolutionSet, t *testing.T) {
+	t.Logf("actual resolution set: %s", rsActual.String())
+	t.Logf("expected resolution set: %s", rsExpected.String())
+
+	actualTargets := rsActual.AttachesTo()
+	sort.Sort(actualTargets)
+
 	expectedTargets := rsExpected.AttachesTo()
 	sort.Sort(expectedTargets)
+
+	t.Logf("actual targets: %s", actualTargets.String())
+	t.Logf("expected targets: %s", expectedTargets.String())
+
 	for _, target := range expectedTargets {
 		if !rsActual.AttachesToTarget(target) {
-			t.Errorf("unexpected missing target: got AttachesToTarget(%q) is false in %s, want true in %s", target.name, rsActual, rsExpected)
+			t.Errorf("unexpected missing target: got AttachesToTarget(%q) is false, want true", target.name)
 			continue
 		}
 		expectedRl := rsExpected.Resolutions(target)
@@ -365,8 +509,8 @@
 		actualRl := rsActual.Resolutions(target)
 		sort.Sort(actualRl)
 		if len(expectedRl) != len(actualRl) {
-			t.Errorf("unexpected number of resolutions attach to %q: got %s with %d elements, want %s with %d elements",
-				target.name, actualRl, len(actualRl), expectedRl, len(expectedRl))
+			t.Errorf("unexpected number of resolutions attach to %q: %d elements, %d elements",
+				target.name, len(actualRl), len(expectedRl))
 			continue
 		}
 		for i := 0; i < len(expectedRl); i++ {
@@ -375,34 +519,86 @@
 					target.name, i, actualRl[i].asString(), expectedRl[i].asString())
 				continue
 			}
-			expectedConditions := expectedRl[i].Resolves().AsList()
-			actualConditions := actualRl[i].Resolves().AsList()
-			sort.Sort(expectedConditions)
-			sort.Sort(actualConditions)
-			if len(expectedConditions) != len(actualConditions) {
-				t.Errorf("unexpected number of conditions apply to %q acting on %q: got %s with %d elements, want %s with %d elements",
+			expectedConditions := expectedRl[i].Resolves()
+			actualConditions := actualRl[i].Resolves()
+			if expectedConditions != actualConditions {
+				t.Errorf("unexpected conditions apply to %q acting on %q: got %04x with names %s, want %04x with names %s",
 					target.name, expectedRl[i].actsOn.name,
-					actualConditions, len(actualConditions),
-					expectedConditions, len(expectedConditions))
+					actualConditions, actualConditions.Names(),
+					expectedConditions, expectedConditions.Names())
 				continue
 			}
-			for j := 0; j < len(expectedConditions); j++ {
-				if expectedConditions[j] != actualConditions[j] {
-					t.Errorf("unexpected condition attached to %q acting on %q at index %d: got %s at index %d in %s, want %s in %s",
-						target.name, expectedRl[i].actsOn.name, i,
-						actualConditions[j].asString(":"), j, actualConditions,
-						expectedConditions[j].asString(":"), expectedConditions)
-				}
-			}
 		}
 
 	}
+	for _, target := range actualTargets {
+		if !rsExpected.AttachesToTarget(target) {
+			t.Errorf("unexpected extra target: got expected.AttachesTo(%q) is false, want true", target.name)
+		}
+	}
+}
+
+// checkResolvesActions compares an actual action set to an expected action set for a test verifying the actual set
+// resolves all of the expected conditions.
+func checkResolvesActions(lg *LicenseGraph, asActual, asExpected ActionSet, t *testing.T) {
+	rsActual := make(ResolutionSet)
+	rsExpected := make(ResolutionSet)
+	testNode := newTestNode(lg, "test")
+	rsActual[testNode] = asActual
+	rsExpected[testNode] = asExpected
+	checkResolves(rsActual, rsExpected, t)
+}
+
+// checkResolves compares an actual resolution set to an expected resolution set for a test verifying the actual set
+// resolves all of the expected conditions.
+func checkResolves(rsActual, rsExpected ResolutionSet, t *testing.T) {
+	t.Logf("actual resolution set: %s", rsActual.String())
+	t.Logf("expected resolution set: %s", rsExpected.String())
+
 	actualTargets := rsActual.AttachesTo()
 	sort.Sort(actualTargets)
-	for i, target := range actualTargets {
+
+	expectedTargets := rsExpected.AttachesTo()
+	sort.Sort(expectedTargets)
+
+	t.Logf("actual targets: %s", actualTargets.String())
+	t.Logf("expected targets: %s", expectedTargets.String())
+
+	for _, target := range expectedTargets {
+		if !rsActual.AttachesToTarget(target) {
+			t.Errorf("unexpected missing target: got AttachesToTarget(%q) is false, want true", target.name)
+			continue
+		}
+		expectedRl := rsExpected.Resolutions(target)
+		sort.Sort(expectedRl)
+		actualRl := rsActual.Resolutions(target)
+		sort.Sort(actualRl)
+		if len(expectedRl) != len(actualRl) {
+			t.Errorf("unexpected number of resolutions attach to %q: %d elements, %d elements",
+				target.name, len(actualRl), len(expectedRl))
+			continue
+		}
+		for i := 0; i < len(expectedRl); i++ {
+			if expectedRl[i].attachesTo.name != actualRl[i].attachesTo.name || expectedRl[i].actsOn.name != actualRl[i].actsOn.name {
+				t.Errorf("unexpected resolution attaches to %q at index %d: got %s, want %s",
+					target.name, i, actualRl[i].asString(), expectedRl[i].asString())
+				continue
+			}
+			expectedConditions := expectedRl[i].Resolves()
+			actualConditions := actualRl[i].Resolves()
+			if expectedConditions != (expectedConditions & actualConditions) {
+				t.Errorf("expected conditions missing from %q acting on %q: got %04x with names %s, want %04x with names %s",
+					target.name, expectedRl[i].actsOn.name,
+					actualConditions, actualConditions.Names(),
+					expectedConditions, expectedConditions.Names())
+				continue
+			}
+		}
+
+	}
+	for _, target := range actualTargets {
 		if !rsExpected.AttachesToTarget(target) {
-			t.Errorf("unexpected target: got %q element %d in AttachesTo() %s with %d elements in %s, want %s with %d elements in %s",
-				target.name, i, actualTargets, len(actualTargets), rsActual, expectedTargets, len(expectedTargets), rsExpected)
+			t.Errorf("unexpected extra target: got expected.AttachesTo(%q) is false, want true", target.name)
 		}
 	}
 }