Hi Nathan,
I think you're seeing the expected behavior. There's a few separate issues here.
1) What happens when you use a branch graft such as task t2 < in=$out@t1[B:two]
Well, at task2, you requested that $in use $out@t1 as its input and, because it's a branch graft, specifically that it should only ever use the "two" branch of the "B" branch point. Other than that, t1 nor any of its children will have no further knowledge that B.two was ever part of the derivation. I've taken to calling this the "destructive" nature of branch grafts -- that branches are removed from the realization (branch derivation) after a branch graft is applied. Since there is no other branch point besides baseline at t2, its realization is "Baseline.baseline". Later, task t3, re-introduces the branch point "B", and you'll see both branches of it there -- but this is completely independent of task t2.
2) Where do symlinks in task directories come from?
There are two ways of naming a realization:
a) its full realization name, which explicitly enumerates all branch points (and the branch selected for each branch point) that are included in the realization
b) its canonical realization name, which is used to name the realization on disk for technical reasons.
The technical reason: To keep the workflow extensible -- when you introduce a new branch point, you want to re-use previous runs of the workflow that are compatible and canonical realization names make this possible. When you create a branch point, the first branch is the "baseline" branch and will be called "baseline" in the directory structure. Further, when the baseline branch is being used in a realization, it is dropped from the canonical realization name. This way, if you add a new branch point, all previous realization names don't suddenly become invalid (The baseline branch must mean the same thing as the previous task definition!). The symlinks are created form the full realization name to the canonical realization name just to make things slightly less confusing.
Jon