Bump to 0.17.0, publish the missing example pages, and route the agent orientation - #308
Merged
Merged
Conversation
The collision hint added two commits ago chose between two messages by whether the colliding extras key was inherited from the base. Both arms assume a per-attempt override exists. A caller who put a declared field and an extras key of the same name in one config, with no retry schedule anywhere, got told "the per-attempt override sets it both ways" about an override they never wrote. Three states, not two: no override, so no advice and the section 8.1 message stands alone; an override whose colliding key came from the base, so name the base's channel; an override that sets the key both ways itself, so say to remove one. Found by running examples/provider-extras, which has no retry config at all and printed the false advice in its own output. Every unit test for the hint supplied an override, so the path was never exercised. The new test covers it and asserts the request never goes out, since the refusal happens before the transport is reached.
The version lands in five places, not the three the release doc names: pyproject, __version__, the smoke-test assertion, and then uv.lock and the bundled AGENTS.md, which both embed it and regenerate from it. The docs sweep found no stale wording. What it found instead was sixteen examples on disk and thirteen pages on the site. Two of the three missing shipped in the previous commit range and one has been missing since 0.16.0, so the examples were reaching the sdist and the bundled index while the published site did not know they existed. The docs-in-sync rule says a page lands with its code, and it did not. Three pages written in the established shape, with their output sections taken from real runs where credentials allowed: the reask demo and provider-extras against a local endpoint, retrieval-rag from its print statements with the indices marked as shape rather than expected values, since it needs two API keys. A guard now compares the example directories against both the pages and the mkdocs nav. The nav half matters on its own: a page missing from it is unreachable even when the file exists, and mkdocs reports that as INFO rather than failing the strict build. Removing either a page or a nav line fails the guard.
docs/agent/tldr.md and docs/agent/non-obvious-shapes.md are the generator's input for the AGENTS.md bundled in the wheel, and they are deliberately not in the site nav: they are written in agent register rather than as browsable prose. The site already has a channel for that register. The llmstxt plugin emits /llms.txt and /llms-full.txt for exactly this audience, and those two files were the only content written for it and the only content the plugin did not carry. Meanwhile mkdocs builds every page under docs_dir whether the nav references it or not, so they were publishing as unlinked HTML through the browse path they were never written for. Now an llmstxt section, listed first because it is the orientation the rest reads against. The ingest grows 602KB to 624KB and the index gains a heading; the HTML stays unlinked, which is what a page that exists to be the canonical URL for an ingest entry should be. Guarded against the plugin config rather than a rendered artifact, so it needs no site build. Nothing failed before: a missing section is silent, and the strict build calls an unreferenced page INFO.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The navigation guard still passes when an example’s navigation entry is commented out.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Prepares OpenArmature v0.17.0, fills documentation gaps, and corrects misleading provider collision advice.
Changes:
- Synchronizes package version references.
- Publishes three example pages and routes agent orientation into LLM documentation feeds, with regression guards.
- Suppresses per-attempt override advice when no override applies.
| File | Description |
|---|---|
uv.lock |
Updates local package version. |
tests/unit/test_llm_provider.py |
Tests collisions without overrides. |
tests/test_smoke.py |
Updates expected version. |
tests/test_examples_smoke.py |
Adds example publication guard. |
tests/test_agents_md_drift.py |
Guards agent feed inclusion. |
src/openarmature/llm/providers/openai.py |
Corrects collision advice conditions. |
src/openarmature/AGENTS.md |
Updates generated version stamp. |
src/openarmature/__init__.py |
Sets runtime version. |
pyproject.toml |
Sets release version. |
mkdocs.yml |
Adds example navigation and agent feed section. |
docs/examples/structured-output-reask.md |
Documents structured-output recovery. |
docs/examples/retrieval-rag.md |
Documents retrieval and reranking. |
docs/examples/provider-extras.md |
Documents extras behavior. |
docs/examples/index.md |
Links the three added pages. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Two review findings, both in work added by this PR. The example-docs guard searched mkdocs.yml as text, so a commented-out nav entry satisfied it while the page had genuinely left the navigation. Verified: commenting the line out left the guard passing. A mention in a comment or a path under `plugins:` would have done the same. That is the defect the guard exists to catch, one level up, and the same shape as the sdist guard this PR replaced for asserting on the exclude list's text rather than the built artifact. It now loads the config and walks `nav` recursively. SafeLoader rejects mkdocs-material's python tags, so the loader ignores unknown tags rather than slicing the nav block out by line offsets, which would be text matching again. Both removing and commenting out a nav line now fail it. The provider-extras page said structural keys reject always, two bullets after saying a matching value is a no-op. Both cannot hold, and the code sides with the second: the reject arm returns early when the extras value equals the managed one, with no special case for structural keys. What is actually unconditional about model, messages, tools and tool_choice is WHEN they are managed, not how they reject. Every other reject-arm key is managed only where the mapping produced it, so an unset temperature lets an extras temperature through. The structural four are managed regardless, so a conflict rejects even where the body carries nothing of that name, which is what stops an extras tool array reaching the wire on a no-tools call. All four arms of the rewritten claim were probed against the real provider.
chris-colinsky
added a commit
that referenced
this pull request
Oct 5, 2026
The release workflow compares pyproject's version to the pushed tag
through packaging.version.Version, so an rc needs the rc version in
pyproject: Version("0.17.0") != Version("0.17.0rc1") and the test job
fails before any publish step runs.
RELEASING.md calls for these as two separate commits, one before each
tag, because the normalized forms differ. The bump in #308 was the
real-release form done early, correct for v0.17.0 and wrong for the rc.
v0.16.0-rc1 carried 0.16.0rc1 in all three places and v0.16.0 carried
0.16.0, which is the precedent.
Five files rather than three: uv.lock locks the local package's own
version, and the bundled AGENTS.md stamps it into its header. Both
regenerate.
Verified against the workflow's own comparison: the rc tag matches and
the real-release tag does not, which is what the second bump is for.
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 prep for v0.17.0, plus two defects the prep surfaced. No behaviour change beyond the collision message in the first commit.
The version bump lands in five places, not three
RELEASING.mdnamespyproject.tomland__version__. Two more track it and regenerate from it:pyproject.tomlvsrc/openarmature/__init__.py__version__tests/test_smoke.pyuv.locksrc/openarmature/AGENTS.mdBoth of the last two are version-only diffs. The
conformance.tomlsince = "0.16.0"entries are historical records of which release a proposal shipped in and stay as they are.The docs sweep found no stale wording, and one gap
The stale-reference half came up clean. I grepped for the renamed
StructuredOutputInvalidfields, the pre-0122 extras shape, "silently dropped/lost/ignored", the olddisable_llm_payloadflag name, spec-pin references and the 0085 status. Nothing indocs/,README.mdorexamples/carries wording this cycle invalidated.What it found instead was sixteen examples on disk and thirteen pages on the site.
structured-output-reaskprovider-extrasretrieval-ragThe examples were reaching the sdist and the bundled
AGENTS.mdindex while the published site did not know they existed. The docs-in-sync rule says a page lands with its code; for two of these it did not, and #304 merged without them.Three pages written in the established shape. Output sections come from real runs where credentials allowed: the reask demo and
provider-extrasagainst a local endpoint,retrieval-ragfrom its print statements with the indices marked as shape rather than expected values, since it needs an OpenAI and a Cohere key.A guard now compares the example directories against both the pages and the mkdocs nav. The nav half matters on its own: a page absent from
mkdocs.ymlis unreachable even when the file exists, andmkdocs build --strictreports that as INFO rather than failing. Deleting either a page or a nav line fails the guard.The agent orientation was in the wrong channel
docs/agent/tldr.mdanddocs/agent/non-obvious-shapes.mdare the generator's input for the wheel'sAGENTS.md, and they are deliberately out of the site nav because they are written in agent register rather than as browsable prose.The site already has a channel for that register: the
llmstxtplugin emits/llms.txtand/llms-full.txt, andmkdocs.yml's own comment says it exists to match the charter's agent-friendly framing. Those two files were the only content written for that audience and the only content the plugin did not carry — while mkdocs built them as unlinked HTML anyway, since it renders every page underdocs_dirregardless of nav.So they are now an
llmstxtsection, listed first because they are the orientation the rest reads against. The ingest goes 602KB to 624KB and the index gains a heading. The HTML stays unlinked, which is the right shape for a page whose job is to be the canonical URL an ingest entry points at.Guarded against the plugin config rather than a rendered artifact, so it needs no site build.
One defect, found by running an example rather than by a test
The collision hint added in #304 chose between two messages by whether the colliding
extraskey was inherited from the base config. Both arms assume a per-attempt override exists.examples/provider-extrashas no retry config at all, and printed this in its own output:There is no per-attempt override. The caller put a declared field and an extras key of the same name in one config, and got told about an override they never wrote.
Three states, not two:
Every unit test for that hint supplied a
per_attempt_override, so the path was never exercised. This is the second time in three days that a single-shape test suite hid a defect in a field I had just changed, which is an argument for running the examples in the gate rather than only compiling them.Evidence
llmstxtagent sectionNonewhere no override appliesThe new no-override test also asserts the request never reaches the transport, since the refusal happens pre-send.
Not in this PR
The CHANGELOG date. The 0.17.0 heading says
2026-09-25and has to match the tag day, so it gets set at tag time rather than drifting again here.