The notion of a priority is that it represents a case where you use the fact that node A is an immediate child of node B to resolve an ambiguity by rejecting that particular parse. In particular, consider the expression "1+2*3". Here the ambiguity surrounds the number "2". It can be part of a parse beginning at position 0 and ending at position 2, or a parse beginning at position 2 and ending at position 4. The goal of priorities is to disambiguate this case.

In order to implement the solution to this problem, it is necessary to have a formal specification for under precisely what circumstances node A cannot nest inside node B. Your formal specification is that node A cannot nest inside node B if it is the first or last child of node B. This makes perfect sense if you approach the situation only from the perspective of binary infix operators. Since the problem of disambiguation using priorities typically arises in expression grammars, and the expression grammars of most modern programming languages use infix binary operators for expressions, it is not terribly surprising that this approach would be mistaken for the correct one.

However, when you generalize to arbitrary context free grammars such that terminals and nonterminals can be intermixed any way you choose, this starts to break down as you propose it. Consider for example the following grammar:

```
syntax Exp ::= Int | "^" Exp Exp | Exp Exp "$"
```

In this grammar, the string "^ 5 6 7 $" is ambiguous. If I declared priorities one way, it would parse as (^ 5 6) 7 $, and if I declared them the other way it would parse as ^ 5 (6 7 $). However, if I declare the former, then it becomes the case that the ^ production cannot nest directly inside the $ production. This causes the "5 ^ 6 7 $" term to fail to parse, even though the string is actually unambiguous. And if I declare the latter, then $ cannot nest inside ^, and therefore I cannot parse the string "^ 5 6 $ 7".

In order to resolve this, it is necessary that we obey the following property:

* If the priorities say that A cannot nest inside B, then we reject any parse in which A is an immediate child of B _and A is inside a nonterminal that begins or ends the production of B_)

Thus this works because in the production `syntax Exp ::= "^" Exp Exp`, the first nonterminal is not adjacent to the end of the production, while the second nonterminal is.

What the point of this illustrates, I think, is that the proper behavior of a parser that supports priorities is _dependent on the production itself_. That is to say, the behavior of the parser's priority rule cannot be determined from the AST alone: depending on which production the ASTNode was generated from, the correct behavior of the filter changes. In order to make the decision, it is necessary to know where in the production the terminals are.

Now that that's explained, let's approach the second point here. You would like to make a one-to-one mapping between productions and KApps? But that is _precisely_ what I am proposing. I am simply proposing the following design:

```
class ProductionTerm extends Term {
   Production prod;
   List<Term> children;

  KApp toKApp() {
    return new KApp(prod.getKLabel(), new KList(children));
  }
}

class Production extends ASTNode {
  KLabelConstant klabel;
  List<ProductionItem> items;
}

class KApp extends Term {
  Term label;
  Term child;
}

class KLabelConstant extends KLabel {
  String label;
}

class Context {
Map<String, Set<Production>> productions; //takes a label as a key
}
```

For comparison's sake, if I understand you correctly, here's what you are proposing, if I am generous:

```
class KApp extends Term {
  Term label; // may or may not be a KLabelConstant, so you have to check every single time
  Term child; // may or may not be a KList, and may or may not have the same arity as the label
}

class KLabelConstant {
  String label; //may or may not be an actual KLabel, might be a cons instead
}

class Context {
  Map<String, Set<Production>> productions; //takes a label as a key
  Map<String, Production> productions; //also takes a label as a key, but does something completely different
}
```

Do you see the problems with the second design? If not, I can't help you, except to say that it is /not/ a design I will allow to be merged.