Performance and scale.

Defer edge creation.

Don't create edges until the count is known to avoid repeated allocate+
copy operatios.

Limit resolutions.

Allow only a single resolution condition set per target, and overwrite
intermediate results. Reduces memory and obviates allocations.

Propagate fewer conditions.

Instead of propagating notice conditions to parents in graph during
initial resolve, leave them on leaf node, and attach to ancestors in
the final walk. Reduces copies.

Parallelize resolutions.

Use goroutines, mutexes, and waitgroups to resolve branches of the
graph in parallel. Makes better use of available cores.

Don't accumulate resolutions inside non-containers.

During the final resolution walk, only attach actions to ancestors from
the root down until the 1st non-aggregate. Prevents an explosion of
copies in the lower levels of the graph.

Drop origin for scale.

Tracking the origin of every potential origin for every restricted
condition does not scale. By dropping origin, propagating from top
to bottom can prune many redundant paths avoiding an exponential
explosion.

Conditions as bitmask.

Use bit masks for license conditions and condition sets. Reduces maps
and allocations.

Bug: 68860345
Bug: 151177513
Bug: 151953481

Test: m all
Test: m systemlicense
Test: m listshare; out/soong/host/linux-x86/bin/listshare ...
Test: m checkshare; out/soong/host/linux-x86/bin/checkshare ...
Test: m dumpgraph; out/soong/host/linux-x86/dumpgraph ...
Test: m dumpresolutions; out/soong/host/linux-x86/dumpresolutions ...

where ... is the path to the .meta_lic file for the system image. In my
case if

$ export PRODUCT=$(realpath $ANDROID_PRODUCT_OUT --relative-to=$PWD)

... can be expressed as:

${PRODUCT}/gen/META/lic_intermediates/${PRODUCT}/system.img.meta_lic

Change-Id: Ia2ec1b818de6122c239fbd0824754f1d65daffd3
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 102e35a..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 -> struct{}{}.
-	conditions map[string]map[*TargetNode]struct{}
-}
-
-// 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]struct{})
-		}
-		cs.conditions[lc.name][lc.origin] = struct{}{}
+		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]struct{})
-		}
-		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]struct{})
-				for origin := range origins {
-					other.conditions[name][origin] = struct{}{}
-				}
-			}
-		}
+// 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]struct{})
-			other.conditions[name][origin] = struct{}{}
-		}
-	}
-	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]struct{})
-		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]struct{})}
-}
-
-// 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]struct{})
-		}
-		cs.conditions[name][origin] = struct{}{}
-	}
-}
-
-// 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 f26e7e8..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
@@ -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 c107520..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
+	wg := lg.wgTD
+
+	if wg != nil {
+		lg.mu.Unlock()
+		wg.Wait()
+		return
+	}
+	wg = &sync.WaitGroup{}
+	wg.Add(1)
+	lg.wgTD = wg
 	lg.mu.Unlock()
 
-	if rs != nil {
-		return rs
-	}
-
 	// 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
+	// (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] = 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]struct{})
-
-	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] = struct{}{}
-		}
-
-		// 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 6fbbbd6..75c8399 100644
--- a/tools/compliance/policy/shipped.go
+++ b/tools/compliance/policy/shipped.go
@@ -26,12 +26,12 @@
 
 	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
 			}
 		}
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 c88b3e6..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,34 +167,37 @@
 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
@@ -194,7 +206,9 @@
 				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 29f3212..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]struct{})
-	for _, as := range rs.resolutions {
-		for actsOn := range as {
-			tset[actsOn] = struct{}{}
-		}
-	}
-	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]struct{})
-	for _, as := range rs.resolutions {
-		for _, cs := range as {
-			for _, origins := range cs.conditions {
-				for origin := range origins {
-					tset[origin] = struct{}{}
-				}
-			}
-		}
-	}
-	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]struct{})
-	for attachesTo, as := range rs.resolutions {
-		for _, cs := range as {
-			if cs.HasAnyByOrigin(origin) {
-				tset[attachesTo] = struct{}{}
-				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)
 		}
 	}
 }