Read what arrived in a LinkedIn inbox, work out what each request actually is, and write the reply, the polite decline or the meeting offer as a draft for the owner to send. It answers nobody, declines nobody and sends nothing.
Two sentences decide everything here.
A wrong decline is invisible and a wrong engagement is not. Decline the right person by mistake and they go away: they do not write again, they do not complain, and nobody on the desk ever learns it happened. Engage the wrong one and it costs ten minutes and announces itself. The two errors are not symmetric, so they are never traded off against each other — this package never declines on its own judgement, and the unsure pile is its most valuable output rather than its embarrassment. A triage tool that shrinks that pile by guessing has made itself look better and the desk worse, and the desk cannot tell. The other half of the same sentence: a rule learned from one ruling is a rule about the case that was ruled. Every standing rule cites the owner's ruling on one real request, carries the day it was made, and is reported with the requests it has decided since — and a rule is as old as the ruling behind it, not as old as its last use.
Nothing is sent, and the reason is ours before it is anybody
else's. A message from this inbox is a named person speaking under
their own identity to somebody who will hold them to it. That is
true whatever any platform's terms say this month. The other half is
about somebody else's rules and is why this package does not state
them: a claim about a third party's rules has an owner and a date,
or this package does not make it. The desk records what it
established, who established it and when, in platform-rules.yaml;
this package prints that back with the name and the date attached,
never restates it as a finding of its own, and reports it as stale
once it is older than the interval the desk agreed. That recorded
answer changes what is printed and never what is done — not one
code path reads it to decide anything, and recorded as permitted
this package still sends nothing.
plugins/uo-05-linkedin-inbox-assistant/ |
the skill: seven scripts, four empty templates, one reference note |
Sample Input/ |
14 files, 11,123 bytes — an invented desk with ten senders |
Sample Output/ |
158 files, 87,656 bytes — every report, every written file, and 140 refusals |
Build Tools/fixture/verify.py |
3,293 lines, 706 checks, no failures |
Sable Ridge Advisory is invented, and so is every person, sender, request, interest, ruling, rule, slot and route in it. LinkedIn is the only real name anywhere in this repository — it is this employee's own name, and a person asking for help with their LinkedIn inbox has to be able to find it. No other product is named, in any file or any output.
The centrepieces are all in the sample, and the harness reads each one off the written files:
- L-01 rests on an afternoon 177 days ago and has decided three requests since. One rule, three findings at once: it has become policy, it is due for review, and it declines people.
- L-02 came into force the day after its ruling, so the age printed for it (18 days) is the age of the ruling and not of the rule. One day's difference is all it takes to prove which one is being used.
- U-03 was never generalised. That is the healthy number to watch: most rulings are about one person and should stay that way.
- T-05 cites an interest recorded as
not-wantedand is categorisedaskanyway — somebody saw that the profile points one way and this case is different. That is not an error; it is exactly the judgement a ruling should capture, and it is the only thing in this run waiting on the owner. - Q-06 is a press enquiry. It is escalated to a named person immediately rather than going into any pile, because a pile is a place things wait.
- S-06 was declined in June and has written again. The draft says so and names the date — a second decline written as though it were the first reads as a desk that does not remember them.
- Five of the ten senders are strangers, which is the ordinary
case for an inbox and the case
an_unknown_sender_becomesdecides the fate of. - The rules check is 120 days old against an agreed 90, so it is reported stale.
| file | reader | carries | must never carry |
|---|---|---|---|
drafts/<request>.txt |
the sender, once the owner sends it | their own words quoted back, the owner's name, and for a meeting offer the times in the slots table | the reason behind the conclusion; any assessment of them; any commitment; any time not in the slots table |
desk/<owner>.txt |
the owner alone | every reason, the unsure pile, the rulings the rules rest on | the draft mark |
routed/<person>.txt |
one colleague | the request, the sender's words, and why it reached them | any of the owner's times |
register.txt |
nobody | what this run produced | any sender's words; any reason |
And the confidentiality rule inverts here. Every employee before this one protected somebody else from what the desk knew. This one keeps the desk's knowledge of itself away from the sender — because the draft is addressed to the person the triage is about. The sender is at once the subject of the assessment and the recipient of the message.
Every check runs over the files as written, not over the values that produced them, and in both directions: the drafts are checked for the absence of every reason, and the owner's file for the presence of every one of them, because a check that only looked for absence would pass on a run that dropped the reason altogether — and a dropped reason is worse than a misfiled one, since nobody is looking for it.
scripts/mandate_report.py can this inbox be worked at all
scripts/sender_report.py who wrote in, and what is known of them
scripts/triage_report.py what was decided, and on what
scripts/rule_report.py the standing rules and what they decided
scripts/reply_report.py how long people have waited
scripts/handoff_report.py what a person still has to do
scripts/build_drafts.py the drafts, and the checks on them
python3 scripts/mandate_report.py \
--mandate "Sample Input/desk-mandate.yaml" \
--team "Sample Input/desk-team.yaml" \
--policy "Sample Input/inbox-policy.yaml" \
--rules "Sample Input/platform-rules.yaml"
python3 scripts/build_drafts.py \
--mandate "Sample Input/desk-mandate.yaml" \
--team "Sample Input/desk-team.yaml" \
--policy "Sample Input/inbox-policy.yaml" \
--rules "Sample Input/platform-rules.yaml" \
--out drafts/
Exit 0 clean, 1 findings, 3 refused. The four governing files
ship empty; the first run refuses once and lists all 27 gaps in
all four together.
an_unknown_sender_becomes has no default. Answered ask, every
stranger the interest profile does not cover lands on the owner's desk
and the pile grows until they stop reading it. Answered decline, the
desk is quiet and the wrong person goes away without anybody finding
out. Both cost something and they are not the same desk, so this
package will not choose for you.
python3 "Build Tools/fixture/verify.py"
706 checks, no failures, in either layout — the build tree or this repository — and it says which it found. Eight passes:
| pass | what it asserts |
|---|---|
| COVERAGE | 50 codes, 36 refused switches and 123 named refusals, each reached by something here or recorded with the reason it cannot be |
| CONTACT | no address and no telephone number anywhere, with an empty exemption list asserted empty and five planted examples the probes must find |
| PUBLICATION | 212 product names blocked over the files, everything written and everything printed, with 32 candidates written down as deliberately absent — one of them the platform itself, permitted with its reason — and 9 exempt files walked again by a narrower check |
| MANIFEST | the plugin can install: frontmatter shape, and a description inside 1024 in characters and in bytes |
| INVARIANTS | the draft/desk split in both directions, no draft naming a time outside the slots table, no time at all in a colleague's file, the register carrying neither words nor reasons, a rule's age measured from its ruling, a second decline naming the first, nothing ending in nothing — and the recorded platform answer changing what is printed while leaving every written byte identical |
| NEGATIVE | 28 codes with a variant that silences them, 22 with a written reason they cannot have one, and one positive control |
| MUTATION | 32 mutations: 11 in the gone sense and 21 in the appears sense, each naming the refusal's own sentence |
| HYGIENE | source, printed output and written files inside 78 characters; nothing imported or defined and unused; no statement that evaluates to nothing; 124 variants each proved to change what some script prints |
It sends nothing, declines nobody, guesses at no unsure case, learns no rule by itself and deletes nothing.
It looks nobody up. What it holds about a sender is the name and headline they put in front of the desk themselves — a search because somebody wrote to you turns a message into a file on them.
It scores and ranks nothing. A score on a person sorts, and the bottom of a sorted list of people is where somebody goes to be ignored with a figure attached. What is recorded is a category from a closed list and the row that decided it, so a reader can disagree with the reason.
There is no address and no telephone number anywhere in this package, in any table or any output — the eighth employee in this series to hold to that, and here the reason is its own: the draft is addressed to the person the triage is about.