Welcome, Guest. Please Login
Tinderbox
  News:
IMPORTANT MESSAGE! This forum has now been replaced by a new forum at http://forum.eastgate.com and no further posting or member registration is allowed. The forum is still accessible via read-only access for reference purposes. If you wish to discuss content here, please use the new forum. N.B. - posting in the new forum requires a fresh registration in the new forum (sorry - member data can't be ported).
  HomeHelpSearchLogin  
 
Pages: 1
Send Topic Print
Squential Tasks (Read 7355 times)
negativebase
Full Member
*
Offline



Posts: 1

Squential Tasks
Aug 13th, 2007, 2:55pm
 
I will admit upfront. I am attempting to emulate the parallel and sequential task features  ominfocus. I have a project set up with a number of actions
All of which have different context Which collected by agents as appropriate. How can I have the sequential tasks not show until the perquisite action has completed. When I look a t my contact i don't to see and action if the previous one hasn't been competed
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Squential Tasks
Reply #1 - Aug 13th, 2007, 4:47pm
 
How are you testing for the previous task? Is the state stored in an attribute?
Back to top
 
« Last Edit: Aug 13th, 2007, 4:47pm by Mark Anderson »  

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Ioa Petra-ka
Full Member
*
Offline



Posts: 103
Portland, Oregon, USA
Re: Squential Tasks
Reply #2 - Feb 26th, 2008, 4:03pm
 
This is a tricky one, and one that I am currently developing as well. Since it is on my list of things to do, I might as well just "think aloud" and post the results. The fundamental problem is that Tinderbox, as least as far as I can tell, does not have a good way to find the first available child that matches a specified expression. It is easy enough to create an agent that will detect and handle the first note in a container, but what if the first note is completed?

The collect_if() function is promising, but as far as I can tell, there is no way to ensure the proper ordering from a set, or derive specific variables from it using secondary expressions other than min() and max() which aren't of any use to us in this scenario.

We'll start simple and add complexity as we go on.

The first thing to do is set up an attribute to store the 'readiness' of any action. Let's call this Urgency. I'm using a number type attribute, where 0 means the action is not available for whatever reason, 1 means it is available, and 2 means that it is "flagged" for whatever reason. Various agents set this attribute. For example, if an action has a due date and goes overdue, it gets set to 2.

Next, you need a prototype for sequential projects with the following expression in the OnAdd attribute:

Code:
if(SiblingOrder=1) {
	Urgency=1;
} else {
	Urgency=0;
} 



When a note gets added to containers with this prototype, they will check their SiblingOrder number. If it is '1', that means it is the first note in the list, and that means it is available, so Urgency=1. Anything greater than '1' gets a Urgency=0. Simple enough.

Next, you just need a way to mark an action as complete, and the next one in the list as available. This can be done a number of ways, but here is a method using stamps. Place this code into a stamp:

Code:
Completed=true; if($Prototype(parent)=Project) { $Urgency(nextSibling)=1; } 



This is very efficient CPU-wise, but as I said---rather static. The expression only gets evaluated when notes are added to the project, and the code that sets up the next action as available is rather "dumb" but only executed when you mark a note as complete. If you want a system that is fully dynamic, you'll have to put the expression into the Rule for the action. Here is an example:

Code:
if($Prototype(parent)="Project Sequence" & SiblingOrder = 1) {
	Urgency = 1;
} else {
	Urgency = 0;
} 



Now each action is checking itself to make sure it is a direct child of a sequential project, and if that is true, it detects if it is in the first position. If so, it marks itself as available, otherwise it marks itself as unavailable.

So now we have a list of tasks that is dynamic. Shuffle them around and they will adjust themselves, add or remove tasks, same. But what happens when the first task is set as completed? Using a stamp to set the next sibling won't work anymore, because the Rules for both will rapidly reset themselves. It is still looking for SiblingOrder=1, but now SiblingOrder=2 is the next action.

At this point, I'm going to take a look at the CPU situation, because we are putting a great deal of logic into each action, and realistically it has to be in the action since containers cannot adequately test children in the way we require. Since a to-do list might have many hundreds, even thousands, of actions---this is going to end up creating a slow file. So I would recommend creating a sequential action prototype that gets set OnAdd from a sequential project. When a task gets dumped into a sequential project, it will be assigned a special, more CPU intensive prototype. Actions in parallel projects can be blissfully oblivious as to the state of the siblings around them, and needn't be constantly checking themselves.

Better yet, you could establish some system for marking when a project is actively being worked on. This could probably be directly tied to a starting datestamp, to make it simple, and something you might want to track anyway. In this manner, an agent could look for actions whose parent projects have a datestamp other than 'never,' and turn on the more intensive logic then. But this step might be overkill if you only have a couple hundred actions.

So assume that the code from this point on will be in these active, sequential actions. They will no longer be checking their parent prototype.

Here is a simple example:

Code:
if(Completed=false & (SiblingOrder=1 | $Completed(prevSibling)=true)) {
	Badge=next;
	Urgency=1
} else {
	Badge=;
	Urgency=0;
}; 



The first thing it checks for is whether or not the action is completed. If it is not completed, then it first checks to see if it has SiblingOrder=1, meaning it is at the top of the list. If so, then it is the next action. Failing that, it could also match a check on the previous sibling for completion. Say it is SiblingOrder=3, but the prevSibling has been completed: Mark it as a next action.

You'll note I'm setting the Badge as well. I'm doing this instead of having a dedicated "next action" attribute. This of course is a personal choice, and any number of preparatory things could be arranged in this if/else clause. But for now it helps us easily see if everything is working the way it should.

Continued below...
Back to top
 
 

Av
  IP Logged
Ioa Petra-ka
Full Member
*
Offline



Posts: 103
Portland, Oregon, USA
Part II
Reply #3 - Feb 26th, 2008, 4:03pm
 
So far, we are assuming that you'll work on sequential projects strictly in sequential order. If you are like me, you sometimes jump ahead and mark something as done. In this case, you'll end up with *two* next actions because two will match the prevSibling completion test. You might decided a previously completed task wasn't really completed after-all, or shuffle the order of completed tasks around. Clearly, simply check for completion and the completion of the previous task is not going to be enough.

This is relatively simple to fix. First, create an attribute called SequentialState, as a numeric type. Then, place this rule into the sequential project prototype:

Code:
SequentialState=collect_if(child,$Urgency=1,$SiblingOrder) 



This scans all of the children of the project, finds the note that has set itself to available, and then stores the SiblingOrder of that note in SequentialState.

Next, we need to have each action make sure that its own SiblingState is not greater than the project's SequentialState.

Revise the rule for the action prototype:

Code:
if(Completed=false & ($ChildCount(parent)=1 | SiblingOrder <= $SequentialState(parent)) & (SiblingOrder=1 | $Completed(prevSibling)=true)) {
	Badge=next;
	Urgency=1;
} else {
	Badge=;
	Urgency=0;
}; 



You can see an additional expression clause has been added in the middle. The new expression has two possible positive matches. This is to avoid a chicken-and-egg problem. Currently if a container has no children, collect_if() will return '0' to a numerical attribute type. So if you are only checking for SiblingOrder <= SequentialState(parent), no tasks will ever match that since the lowest possible SiblingOrder is 1. So instead we allow the ChildCount of the parent to be 1 as the bootstrap condition. I could just check to see if SequentialState(parent) is zero, but that functionality may change in the future, whereas checking for ChildCount=1 is pretty safe.

I should note, there is a *possibility* for glitching to occur. If an action with Urgency=1 is dragged into a parallel project, and it's reset rule fails to run before the Project's collect_if rule runs, you might run into problems. A way around this is to put 'Urgency=0' in the Project OnAdd---which will always be executed instantly, most importantly, before the rules timer resets.

Now you can mark an action as complete anywhere in the project, and the next action will skip right over it once you catch up to that position. Additionally, you can go back and change your mind about an older action. If you remove it's completion tag, it now becomes the lowest SiblingOrder action and marks itself as next. Same goes for shuffling tasks around.

There is really only one other consideration in emulating OmniFocus style task selection, and that is nested projects. However, I think by now you have the idea, so I won't describe that whole process in depth. Basically, you'll just want to have the Action rule check to see if the next sibling is a project at the same indent level, and if it is, to activate it (whether or not all of the sub-actions within it depends on that nested project's sequential or parallel status). Then the next action will be within the nested project. Likewise, next actions will need to be aware of nested projects in the prevSibling position, and react to their state accordingly. The details of how all of that is automated is up to you. I have a "task group" prototype that marks itself as complete as soon as all its children are marked complete. I don't want regular projects to automatically mess with their completion state. Then the action's urgency set rule looks for whether or not the previous sibling is a completed task group. If it is, then it sets itself as next action.

Finally, this method used a simplified "availability" flag. You'll probably want something more complicated that allows for some action states to block a project from having any next actions---and you certainly wouldn't want a rule blowing away high urgency flags. Either using a separate attribute for blocking states, or using more numbers in the Urgency scale would be two ways of going about this.

In summary: Let Actions decide their status based on the actions around them. Projects need only track which Action is currently active. No agents are required; all processing is done in the Action rules. Minimise how many actions are currently running this set of rules to keep your list running quickly.

I haven't fully tested this method, but I have a working model based on the examples provided, and under basic usage it seems to be function. A little laggy (as in typical variable Rule-based lag as they do not execute constantly in the background), but functional.
Back to top
 
« Last Edit: Feb 26th, 2008, 4:54pm by Ioa Petra-ka »  

Av
  IP Logged
Ioa Petra-ka
Full Member
*
Offline



Posts: 103
Portland, Oregon, USA
Re: Squential Tasks
Reply #4 - Feb 26th, 2008, 4:53pm
 
Update: I've found that using ChildCount=1 as a boot-strap test is flaky. There are times when the project rule runs directly after marking an item complete. Since the all the action rules haven't run yet, nothing has marked itself as Urgency=1, and thus SequenceState=0. Nothing matches. So checking for SequenceState(parent)=0 is currently the way to get around this.
Back to top
 
 

Av
  IP Logged
Pages: 1
Send Topic Print