Release 0.81.0 — the door an author could not find - #24
Merged
Merged
Conversation
Part L shipped the mechanism and left the person it was built for with no
way in. docs/extending.md still cited spec v0.20, so the one document
naming extensions contradicted what had been released; nothing taught how
to write one; and the console's install box asked for "a path", which is
a path on the HOST. Through a browser that is the container's filesystem,
so an operator holding an extension they had just written had no route at
all to a remote Station short of publishing it to git first, and the
local-file door served only somebody with a shell there, who would have
used the CLI.
An uploaded archive is a fifth door into the same resolver: {name, b64},
the shape ingest has carried since J.8, so a browser that can already
send a document sends an extension with no new mechanism. It is
unverified by construction, because there is no forge and no index
identity behind an upload and nothing could have been verified; it is
refused before it is written when it is over
MONKEYLLM_STATION_EXT_UPLOAD_MAX_MB (25), since this door is for an
extension's own code and vendored wheels belong to the local-file route.
Every seam now declares its handler's contract. What a curation handler
receives was prose in the spec and nowhere in the code, so the kit could
answer "it works" about a handler with the wrong parameters, found on the
first ingest at whatever hour that ran. The kit checks the signature at
install by reading the author's source and never importing it: a heavy
handler's module imports the very dependency L.5 keeps out of this
process, so importing to catch a typo would break the rule that protects
the deployment, and would run third-party code at kit time, which L.2
rule 5 is careful to say the kit does not do.
The rule hinges on defaults, not on **kwargs. The first cut said kwargs
excused a misspelled parameter and was wrong in the exact case it was
written for: given on_event(event, forrest, **rest), **rest absorbs the
forest the host passes and forrest is still unfilled. The spec paragraph
was corrected to match the code rather than the reverse.
L.16 is the authoring surface, and its rule is that prose is written
while schemas are derived. The teaching text lives in docs/extending.md,
rewritten around Part L, where it is read without running anything; the
manifest schema, the seam contracts and the role kinds come from the
definitions themselves, because a transcribed schema lies at the first
new seam, silently, to exactly the person with no other source. F.203
adds a seam at runtime and asserts the served document changes. GET
/v1/extensions/authoring is deliberately not under the admin gate:
writing is not installing, an extension is written on a laptop and
installed by whoever governs the deployment, and gating the documentation
on that authority withholds it from the only person who needs it.
The Extensions console gains the file picker and an authoring panel that
lists the seams read from the Station and hands out a folder for a coding
agent. api.js exports one base64 encoder, so ingest and the extension
upload no longer carry two.
Worth keeping: the new contract check immediately failed a v0.80 fixture
of our own, an events handler declared echo(value), a signature no real
events call could fill, which passed a whole release because nothing
checked.
Spec v0.81 (L.2, L.3, L.9 rule 1, L.16), F.199-F.205 in
tests/test_v081_authoring.py. Suite green on 3.11 and 3.12.
Signed-off-by: Jimmy Wesley <[email protected]>
Nothing in this repository said what a version number means. The release workflow enforces that the tag equals `version` in pyproject.toml, which is a consistency check and not a policy: it never said which number to pick, and the rule that had been followed for thirty releases lived in one person's head. Written down now in CONTRIBUTING, "Versions, and what a tag means". The minor is the spec version a release implements, so 0.81.x implements docs/monkeyllm-spec-v0.81.md and a contract change always moves it, because a contract change always cuts a spec first. The patch is every release that cuts no spec: a fix, a console, a document, a measurement. The major stays 0, deliberately. And while the major is 0, a patch may change behaviour. That is the honest reading of a 0.x version and it is now stated rather than left to be discovered, which has one consequence that had to be chased through the tree: a station_compat of ">=0.79,<1.0" then protects nobody. Part L had just sold that range as a guarantee. So L.1 now says what the host's version promises and what it does not, docs/extending.md teaches the pin, and the L.16 authoring reference prints the exact range to copy at the one place an author copies it from. tests/test_version_agreement.py pins what the release guard cannot see: the number is written twice, in pyproject.toml and in monkeyllm.__version__, and only the first is compared to the tag. It also checks that the minor names a spec file that exists, because a release whose minor names no spec is a release nobody can check against a contract. Signed-off-by: Jimmy Wesley <[email protected]>
Spec v0.81: the door an author could not find. An uploaded archive is a fifth install source, so an extension written on a laptop reaches a remote Station without being published to git first; every seam declares its handler's contract and the conformance kit checks the signature at install, reading the source and never importing it; and the L.16 authoring surface serves prose that is written beside schemas that are derived. extensions/whisper moves to ">=0.81,<0.82" with the bump rather than after it. It shipped declaring ">=0.79,<1.0", which under the versioning policy this release writes down is a range that promises what nobody keeps: the extension this project ships should pin the way it tells everyone else to. Its suite reads monkeyllm.__version__ instead of a literal, so the range is actually exercised and a failure at the next minor is the pin working. Signed-off-by: Jimmy Wesley <[email protected]>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release 0.81.0 — the door an author could not find
One spec version, v0.81, and the package moves 0.80.0 → 0.81.0. It comes
from the shape of the release before it: 0.80.0 shipped the extension
mechanism and left the person it was built for with no way in.
docs/extending.mdstill cited spec v0.20, so the one document namingextensions contradicted what had just been published; nothing anywhere
taught how to write one; and the console's install box asked for a path.
A path is on the host — through a browser that is the container's
filesystem, so an operator holding an extension they had just written had
no route to a remote Station short of publishing it to git first. The
local-file door served only somebody with a shell there, who would have
used the CLI.
What changed
An uploaded archive is a source (L.2). A fifth door into the same
resolver, not a fifth resolver: bytes arrive as
{name, b64}, the shapeingest has carried since J.8, so a browser that can already send a document
sends an extension with no new mechanism. It is
unverifiedbyconstruction — there is no forge and no index identity behind an upload,
so nothing could have been verified, and the tier says that rather than
implying a check happened. It is refused before it is written when it
exceeds
MONKEYLLM_STATION_EXT_UPLOAD_MAX_MB(25): this door is for anextension's own code, dependencies are resolved at install, and a
vendored-wheel bundle belongs to the local-file route.
Every seam declares its handler's contract (L.3, L.9 rule 1). What a
curationhandler receives, what aneventshandler receives and what eachreturns were prose in the specification and nowhere in the code, so the
conformance kit could answer it works about an extension whose handler
took the wrong parameters — found on the first ingest, at whatever hour that
ran. The kit now checks the signature at install, and it does so by reading
the author's source without importing it: a
heavyhandler's moduleimports the very dependency L.5 exists to keep out of this process, so a
check that imported would break the rule protecting the deployment in order
to catch a typo, and would run third-party code at kit time, which L.2 rule
5 is careful to say the kit does not do.
The rule hinges on defaults, not
**kwargs. The first cut saidkwargsexcused a misspelled parameter and was wrong in the exact case it was
written for: given
on_event(event, forrest, **rest),**restabsorbs theforestthe host passes andforrestis still unfilled. The specificationparagraph was corrected to match the code, not the reverse.
The authoring surface (L.16). Prose is written and schemas are derived.
The teaching text lives in
docs/extending.md, rewritten around Part L,where it is read without running anything; the manifest schema, the seam
contracts and the role kinds come from the definitions themselves, because
a transcribed schema lies at the first new seam — silently, to exactly the
person who has no other source. F.203 adds a seam at runtime and asserts the
served document changes.
GET /v1/extensions/authoringis deliberatelynot under the admin gate: writing is not installing, an extension is
written on a laptop and installed by whoever governs the deployment, and
gating the documentation on that authority withholds it from the only
person who needs it — J.5.12's reasoning about skills, applied again.
A patch may break you, and the version now says so. Nothing in this
repository said what a version number means. The release workflow enforces
that the tag equals
versioninpyproject.toml, which is a consistencycheck and not a policy: it never said which number to pick, and the rule
followed for thirty releases lived in one person's head.
CONTRIBUTING.mdnow carries it — the minor is the spec version a release implements, the
patch is every release that cuts no spec, the major stays
0deliberately,and while it is
0a patch may change behaviour.That last sentence had one consequence to chase through the tree: a
station_compatof>=0.79,<1.0then protects nobody, and Part L had justsold that range as a guarantee. So L.1 states what the host's version
promises and what it does not,
docs/extending.mdteaches the pin, theL.16 reference prints the exact range at the one place an author copies it
from, and
extensions/whisperpins to>=0.81,<0.82— the extensionthis project ships pins the way it tells everyone else to. Its suite reads
monkeyllm.__version__rather than a literal, so the range is actuallyexercised and a failure at the next minor is the pin working.
Also in this release
the source field, and a Write an extension panel that lists the seams
read from this Station and hands out a folder (
SKILL.mdplus thegenerated references) for a coding agent.
api.jsnow exports one base64encoder, so ingest and the extension upload no longer carry two.
tests/test_version_agreement.pypins what the release guard cannotsee: the number is written twice, in
pyproject.tomland inmonkeyllm.__version__, and only the first is compared to the tag. Italso checks that the minor names a spec file that exists, because a
release whose minor names no spec is a release nobody can check against a
contract.
eventshandler declared
echo(value), a signature no realeventscall couldfill, which passed a whole release because nothing checked.
Leftovers, named
implemented and not measured — it needs a signed tag and gpg on the
runner.
verifiedtier hasnothing to resolve against.
included.
Acceptance
F.199 – F.205. Full suite green locally on the release commit — 1842
collected, 0 failures, exit 0 on both matrix legs (Python 3.11.15 and
3.12.1) — and running in CI on this PR.
python -m build+twine checkpassed (wheel 246 kB, sdist 561 kB; the wheel carries
monkeyllm/extensions/contracts.py,authoring.pyandcli_ext.py, andnothing of the Station).