Skip to content

About

PA-03-Task-Manager-Personal-Assistant

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

PA-03 · Task Manager Personal Assistant

Reads what colleagues said in the groups and threads a principal has designated, turns it into per-person and per-team task lists, and keeps them current. Assigns nobody, sends nothing, guesses no owner, scores no priority and deletes no task.

Two sentences decide everything in this package.

A task's owner is somebody who agreed to it, and the person who raised it is not the same person

Someone needs to redo the pricing slide before Friday is a sentence with a name attached to it — the name of whoever typed it. A tool that reads the message and assigns the work has just given a task to the person who noticed it needed doing, and the first they hear of it is a reminder.

That is not an edge case. On any desk the person who raises work is systematically not the person who does it: a lead flags, a colleague mentions, a client asks. So a candidate carries two separate things — raised_by, a fact read through the message and never edited, and suggested_owner, a judgement somebody recorded while reading, which may be blank and is the only field an assignment may come from. Two columns, never one.

The one case where they coincide — I will get the vendor contract out today — is a person volunteering, and this package prints it rather than hiding it, because the rule is not never use the sender. On the sample desk 3 of 8 owned tasks have an owner who is also the raiser and 5 do not; the harness asserts both counts are above nought, because a rule that never let them coincide would be a rule forbidding people to take their own work on.

And an unowned task is not an unassigned task. A task with nobody against it is work nobody has agreed to. Read as a gap to be filled it lands on whoever looks least busy or on the principal by default, and either way somebody is now responsible for something they never accepted. There is no owner guesser here: it is reported as unowned, by name, with the sentence it came from and the group it was said in, and a person decides.

A task travels and the sentence that produced it does not — unless the reader was in the group it was said in

A task raised in the pricing thread and assigned to somebody who is not on that thread is an ordinary Tuesday. The task has to reach them: that is the whole point of the desk. The sentence must not, because the pricing thread is a room they were not in.

So the check is not a prohibition, it is a biconditional:

  • the task line is present on the owner's list always;
  • the source sentence is present exactly when that reader is a member of the source group;
  • and absent exactly when they are not — where it says so, names the group, and names who to ask.

A list that silently dropped what it could not show would have a hole the reader cannot see, and they would ask a colleague instead.

A team list is stricter. It reaches everybody on the team, so a sentence appears on it only where every member was in the source group. One member outside is enough to withhold the line from all of them, because a document's readers are its readers and there is no such thing as showing one paragraph to four people out of five. The consequence is deliberate and visible in the samples: T-09 is quoted in full on Cormac's own list and withheld from the Platform team list that Cormac also reads.

The same task therefore produces two different lines on two different people's lists, from one run, and that is correct. Every employee before this one in the series had one rule per file; this one has one rule per reader.

Every due date is read against the day the words were said

Before Friday means the Friday after the day it was said. Read against the day the tool happens to run, the same words mean a different Friday every week — so a task that came due a fortnight ago reads as due at the end of this one, and a list of what is late silently becomes a list of what is coming up.

Both answers are printed side by side in the capture report, with the rule that produced each. On the sample desk 6 of 11 candidates would get a different date if their words were read against the run date.

The forms are a closed list: today, tomorrow, end of week, end of month, in a week, and any weekday optionally prefixed by, on or before. A weekday named is the next occurrence and the day it was said counts. Anything else is not a date — as soon as possible leaves the candidate with no due date, and the report names the words it could not read so that whoever approves it can write one down.

What this package does not have

absent because
an owner guesser an unowned task is not an unassigned task
a priority scorer a list sorted by a score has a bottom, and the bottom is where work goes to be forgotten with an explanation attached
a due-date guesser a day nobody said is a deadline somebody then gets chased against
a done_on column that minus the due date, per person, over a fortnight, is a performance record — and the outward file here is a list the person it is about receives
deletion a task is closed, deferred or dropped and a reading is declined; a desk that can delete cannot say what happened
an address or a telephone number membership is the access control, and a way of reaching somebody would be a second route the membership table does not govern

Before the first run

Three files govern this desk and all three ship empty. Every run refuses, once, listing every gap in all three together — 23 of them on a fresh install (Sample Output/refused/the_three_governing_files_ship_empty.txt).

file what it decides
desk-mandate.yaml the desk, its zone, the window, and where the ten tables are
desk-team.yaml who approves, who compiles, whose name a request goes out under
task-policy.yaml the nudge cap and interval, the escalation points, and whether a request naming nobody becomes a task at all

They are empty on purpose. Each is a decision about whose conversation gets read or about who is made responsible for what, and a tool that filled them in would be taking that decision quietly. task-policy.yaml also writes out seven things this package will not do, each shipping as no, so switching one on is a visible edit to a file somebody owns.

unowned_request_becomes_a_task has no default. Can we get the deposit question closed? is work somebody wants done and nobody has been asked to do; answered yes it becomes an unowned task, answered no nothing is created and the sentence is named in the capture report or it is lost. Both are defensible and they are not the same desk.

The ten tables

people · teams · groups · membership · messages · candidates · tasks · priorities · nudges · absences

Eight must have rows. nudges and absences may be empty, because a fortnight in which nobody had to be chased and a desk where nobody is away are both states a real desk reaches.

groups.designated has three states: yes may be read, no may not, and blank is a group nobody has decided about. Nothing is read from a blank — a blank is not a yes — and the run is not refused, because a desk that could produce no lists until every group was triaged is a desk where somebody types no into the column to make the tool work. The mandate report names the undecided groups instead. A value that is neither yes, nor no, nor blank is refused: that is a decision recorded in words this tool cannot read, on the one column that decides whether a conversation is read at all.

Full column-by-column detail, with what goes wrong in each case, is in plugins/pa-03-task-manager-personal-assistant/skills/pa-03-task-manager-personal-assistant/references/the-ten-tables.md.

Running it

cd plugins/pa-03-task-manager-personal-assistant/skills/pa-03-task-manager-personal-assistant/scripts

python3 mandate_report.py  --mandate … --team … --policy …
python3 channel_report.py  …     # what each reader may be shown
python3 capture_report.py  …     # raiser vs suggested owner; due dates
python3 task_report.py     …     # what is open, late, unowned, unbanded
python3 nudge_report.py    …     # what may be asked about, and the drafts
python3 handoff_report.py  …     # what the next person needs to know
python3 build_lists.py     … --out lists/

Exit codes: 0 nothing to report · 1 findings · 3 refused.

50 findings across the seven scripts, each under its own code (PA03-M01 … PA03-L08), and 33 refused switches, each refusing under its own name with its own reason — because a single generic refusal teaches the reader that the tool will not do that class of thing and they stop reading.

build_lists.py writes one file per person, one per team and a register, then reads every file back off the disk and checks the biconditional in both directions against the membership rows — not against the function that decided them, because a check that asks the same question twice checks nothing. A sentence present where its reader was outside the room, or absent where they were inside it, refuses.

Every person gets a file every run, including an empty one, because a list that only arrives when there is something outstanding is a list whose arrival is itself the message.

Status requests: drafts, always

Nothing is sent. The nudge report writes what each request would say and stops, for a named person to read and send. A request is not drafted when the task is not due yet, when nobody owns it, when it wants nothing, when the cap is reached, when the interval has not elapsed, or when the request would go from the sender to the sender. Not one of those reasons is how long its owner has had it.

A task at the cap with no answer goes to the principal instead — a different action, taken by a different person, because somebody who has not answered twice is not somebody who needs asking a third time.

What is in this repository

Sample Input/ 13 files · 9,047 bytes — the whole invented desk
Sample Output/ 160 files · 97,967 bytes, every one produced by the scripts here
↳ refused/ 144 refusals, each under its own sentence
↳ written/ 6 person lists, 2 team lists and the register — 9 files · 18,752 bytes
Build Tools/fixture/verify.py 2,836 lines · 854 checks, no failures
Build Tools/gen_samples.py regenerates Sample Output/ from the committed input
Build Tools/preflight_public_scanners.py run before pushing anywhere scanned

Every person, team, group, message, candidate and task is invented. Ardglass Works does not exist and neither does anybody named in it. That matters more here than it looks: this fixture records, for named colleagues, what they were asked to do, what they agreed to, what they have not finished, how many times they were chased and whether they replied. A real desk in the same shape would be a performance record on every person in it.

Verifying it

python3 "Build Tools/fixture/verify.py"

Eight passes, and each exists because a package can be wrong in a way the previous pass cannot see.

pass what it will not let through
coverage 50 codes, 33 refused switches and 115 named refusals — every one reached, or recorded with the reason it cannot be produced from a fixture edit
contact no address and no telephone number anywhere, with an exemption list that is empty and asserted empty, and probes assembled at run time so the harness does not trip its own scan
publication 184 real task, messaging, mail, calendar, document and automation products blocked on word boundaries — in the files and in everything any run printed — with 20 candidates written down as deliberately absent and the reason for each
manifest the plugin installs: frontmatter shape, and a description inside 1024 in characters and in bytes — the byte count is what two earlier employees in this series got wrong
invariants read off the written files, each with an assertion that the case was not vacuous
negative cases 31 codes each with an input that silences them, 19 with a written reason they cannot have one, and one positive control so that quiet means quiet rather than crashed
mutation 18 mutations in both senses — gone for a needle the clean run prints, appears for one only a broken package produces, which is the only sense that tests a guard the package enforces on itself
hygiene width in characters in source and output, nothing defined or imported and unused, and every one of 119 variants proved to change what some script prints

The mutation pass clears the bytecode cache around every mutation and runs the subprocesses with it switched off. Without that it was intermittently wrong: a mutation and its restore land inside the same filesystem second, and when the two file sizes also agree a later subprocess loads the cached mutated module while the file on disk is clean. A harness that gives a different answer on a second run is worse than one that fails.


Built by New Digital Intelligence.

About

PA-03-Task-Manager-Personal-Assistant

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages