A click citing a ref this deployment cannot resolve is refused
A Bot acts on a page by citing a ref from a snapshot, and the server turns that ref back into the
element before the boundary judges it. When the lookup failed, the action went ahead anyway with the
element half of the decision left empty — so a rule like "never click anything named submit" was not
declining to match, it was never shown the element, the shipped default permitted, and the click
landed on whatever that ref points at now.
The computer's own staleness check does not cover this. It compares a citation against its own
counter, so it catches the cases where the two disagree; the case that bites is the one where the
computer is content and only this deployment is out of step, which is what restarting a computer
under a stored snapshot leaves behind. The same click on the same button under the same policy was
refused before a redeploy and carried out after it.
A citation this server holds a snapshot for and cannot resolve is now refused, and the person is told
to take a fresh snapshot. Actions that name no element — scrolling, a page-level keypress, a shell
call, a file read — are untouched, and a computer this deployment holds no snapshot for still has its
citation forwarded, because there it is the only party that can answer. The refusal is raised after
the decision row is written, so an action somebody tried to take still appears on the trail.
A deployment may see refusals it did not see before. That is the point: those are the actions that
were being carried out without the boundary seeing what they touched. A Bot that meets one takes a
fresh snapshot and continues.
A package ships its skills, so tool selection works on a clone
Tool selection narrows a Bot's tools to the ones its matching skills declare, and a deployment starts
with no skills at all. There was no skills.yaml, nothing seeded any, and nothing ever created one
— so on every fresh clone there was nothing to match against and the narrowing never switched on.
Left to a screen it would have stayed that way until somebody sat down and mapped tools to skills by
hand, in each deployment, again after each new connector.
A tenant package may now carry skills.yaml. Each skill has a slug, a title, a summary, its
instructions, and the serverId/toolName refs it needs. They are seeded on boot as deployment
skills, everybody sees them in the / menu, and connecting a connector is the only step left.
skills.yaml is optional, so every existing package loads unchanged and ships no skills. A package
may declare tools for a connector nobody has added: an unknown ref sits inert, because the offer is
still intersected with the Bot's grants. Naming a tool in a package grants nothing, exactly as
before.
A skill somebody wrote in the deployment keeps its name. If a package ships a slug a person already
took, theirs stands, the package loses that one, and the deployment starts — a name is not worth
refusing to boot over.
The example package ships four: /find-a-document, /whats-changed, /who-owns-this and
/check-a-claim.
The tools a skill needs can be picked where the skill is written
A package's skills arrive with their tools declared. A skill somebody writes here could not: the
tools field existed on the save endpoint and on no screen, so a skill written in the product declared
nothing, and the only way to change that was to call the API by hand. Writing or editing a skill now
lists the tools of every connected server, grouped by server, with the ones that change something
marked.
Picking a tool here is not granting it. The offer is still intersected with what the Bot was granted,
so a skill naming a tool its Bot does not hold selects the skill and loads nothing — which is why
anybody may write a skill while connecting a server stays an administrator's decision. The screen says
so, next to the choice.
A tool the skill names that no connected server offers is shown too, under its own heading, rather
than left out. A package ships skills declaring tools for connectors nobody has added yet, and a
skill outlives the server it was written against, so a screen that drew only what matched was
stating part of the declaration as though it were all of it.