Writing a task skill that fails at registration
A skill declares the sources it needs, so an unreachable one is a startup error rather than a wrong answer.
A tool that needs a booted installation and cannot have one does not fail. It reads the files instead, answers with less, and says so — and the saying so is the part that makes the answer usable.
Three paths lead to the same registry and they are not equal. Where a console command exists it runs, and where it does not the runtime is booted in this process. Both return everything the registry holds; they differ in what they cost, not in what they know.
The third path exists because the first two can be unavailable — a failsafe installation, a missing database, an extension that throws while it is being loaded. It reads the package files from disk. It never executes them, which is the reason it can answer at all and also the reason it answers with less.
Every entry a package declares in a file, and nothing that is registered while the application runs. For most installations that is the larger part of the registry, which is precisely what makes the shortfall dangerous: a partial answer that looks complete is worse than no answer, because nothing about it invites a second look.
{
"answeredBy": "packages",
"declared": ["installation", "packages"],
"reason": "the installation could not be booted",
"omitted": "dynamically registered entries, never read"
}
answeredBy is what reached the question and declared is what the tool was allowed to read. The two differing is the whole definition of a degraded answer in this server, and it is a comparison a caller can make without knowing anything about registries.
A partial registry never looks complete: source, reason and the unread files travel with the result.
Dynamic registrations are the whole of the difference — entries an extension adds in its own bootstrap, which exist only once something has run. No file on disk names them, so no amount of reading files finds them, and a tool that pretended otherwise would be inventing.
Nothing has to be configured. The fallback is chosen because the two paths above it were unavailable, so making one of them available is the entire fix — and the next answer says installation rather than packages.
# the gap closes when the runtime can boot $ ddev start ✓ answered by installation
A skill declares the sources it needs, so an unreachable one is a startup error rather than a wrong answer.
Every result carries which of the five sources reached it, and what the substitution left out.