Skip to content

Upgrade guide covers every release up to the current one #707

Closed

Description

@0x054

Parent

#698

What to build

The upgrade guide stops at 0.15 while the package is at 0.25.0, and one recipe subclasses ferro.Ferro, which does not exist. Each release from 0.16 to the current one gets a section listing what an upgrade asks of the user (from CHANGELOG.md and the release PRs), and every before/after recipe uses real classes, shows both declaration styles, and runs. The implicit-routing removal is attributed to the release CHANGELOG.md records (0.14).

Pages: howto/upgrade-guide.md

Acceptance criteria

  • Every fact on the page matches the code at the time of the PR; each High finding in the audit rows below is fixed, and each Medium/Low finding is fixed or answered in the PR body with the reason it was left.
  • Each page is one kind (tutorial, how-to, reference or explanation) and opens with one sentence saying what it covers, then an example on the first screen (writing-for-humans rules 1–2).
  • Each page uses one running example, declared once near the top and reused; each section shows only what changed (rule 3).
  • Every code block has a lead-in sentence ending in a colon and a result sentence after it, and shows its result: printed output, or the asserted value inside the embedded snippet range (rules 7–8). Snippet end: markers sit below the assert or print that holds the result.
  • Every copyable block either shows the async with engines.session(): wrapper or sits under a sentence that says it runs inside one and links to Connections › Sessions; the page's first block shows the wrapper.
  • Every inline Python block that does real work runs under the harness ({test=run prelude=<name>}) or moves into an example script; a block left compile-only says why in its fence marker.
  • Every lambda passed to a query method names its parameter after the model in lowercase singular (AGENTS.md I-8); python -m tests._docs_checks reports no violation for the owned files.
  • Every error check in an owned example fails when the expected error is not raised (try/except/else: raise AssertionError, or the harness helper).
  • Field-declaring examples show both declaration styles as tabs, each backed by a runnable script (AGENTS.md I-7), and the twins use the one Annotated idiom recorded in the docs conventions.
  • Headings are short sentence-case noun phrases naming the feature (rule 5); how-to titles name the goal (rule 24); no minimising words (rule 17); admonitions follow rule 20.
  • No ADR numbers, issue numbers, codenames, dated or release-bound notes, or contributor-only references in page text; version markers are self-contained blocks at the end of a section.
  • Reference material that has a home in Reference is linked, not repeated; each topic ends with a pointer to its reference entry (rule 4).
  • Every version from 0.16.0 to the version in pyproject.toml has a section, or a one-line note that it needs no action.

Files owned

  • Create: docs/examples/upgrade_*.py (one pair per recipe that declares fields)
  • Modify: docs/pages/howto/upgrade-guide.md

Interfaces

Test scenarios

  • Happy path: the strict site build succeeds and every snippet range on the owned pages renders without leading indentation.
  • Happy path: every owned example script runs to completion under tests/test_docs_examples.py, and every inline block marked {test=run ...} runs.
  • Error path: deleting the raise an owned example's error check expects makes that example's test fail.
  • Edge case: python -m tests._docs_checks over the owned files exits 0; renaming one lambda parameter to t makes it exit 1 naming the file and line.

Verify

uv run --no-sync zensical build --clean --strict
uv run --no-sync pytest tests/test_docs_examples.py -q --no-cov -p no:cacheprovider -n 8
uv run --no-sync python -m tests._docs_checks docs/pages/howto/upgrade-guide.md

Blocked by

Audit findings

Rows from the docs audit this ticket covers (file, line, rule, fix)

docs/pages/howto/upgrade-guide.md

  • Kind (rule 1): how-to (correct), with per-boundary agent prompts.
  • Running example (rule 3): none (one per boundary, which is fine for this kind of page).
  • Verdict: Its structure works (boundary sections, before/after tabs, a prompt per boundary). It stops
    at 0.15 while the package is 0.25.0, it has a broken class Event(Ferro) example, and it uses
    lambda t: throughout. Grade: C.

Version check: every version named (0.11–0.15) exists in CHANGELOG.md. pyproject.toml is 0.25.0.
Nothing on the page covers 0.16–0.25.

Sev Line Rule Finding Suggested fix
H 20–29, 49 fact Coverage ends at 0.15. The current version is 0.25.0 (pyproject.toml:3, CHANGELOG.md:4). A reader on 0.15 → 0.25 finds no row and cannot tell "nothing to do" from "not written". Several 0.16–0.25 changes can bite: query literals canonicalised against save() (0.16, can change SQLite after()/equality results), multi-PK models rejected at class definition, retired enum labels refusing writes, and connect(auto_migrate=…) refused on a migrations-tracked database. Add a row "0.15.x or later → 0.25" and either a short "Upgrading to 0.16–0.25: no breaking changes, but note …" section or explicit per-boundary sections. Let the maintainer comment require a row even when nothing breaks.
H 336, 359 9, fact class Event(Ferro): / class Account(Ferro):. There is no ferro.Ferro (hasattr(ferro, "Ferro") → False). The keep-recipes do not run as written. They also omit imports and use FerroField where every other page uses Field. class Event(Model): with from ferro import Field, Model and Field(db_type="timestamp"). Same for Account.
H 333–361 I-7 The keep-recipes declare fields with Field() options (db_type=, db_check=) in assignment style only. Add an Annotated twin, e.g. tabs "Keep (assignment)" / "Keep (Annotated)", or nest Assignment/Annotated tabs inside "Keep".
H 150, 164–165, 184, 194, 487; prompts 111, 445 I-8 Lambda parameters are t / m, not the model name: User.where(lambda t: t.age >= 18), order_by(lambda t: t.created_at, …). lambda user: user.age >= 18, lambda user: user.active == True, lambda event: event.created_at. The table cell becomes where(lambda user: ...).
M 168–177, 488 fact The page says implicit routing was "removed in 0.13" (the runtime error says the same). CHANGELOG.md has no such entry under v0.13.0. "single-handle routing" (#201) is recorded under v0.14.0 (line 879). The table row at line 29 ("stopping at 0.13 … plus the connection-routing note") depends on this. Confirm the release that removed it and align the page, the runtime message and the table.
M 37–47 fact "This catches every deprecation-based change." A reader jumping from 0.11 straight to 0.25 hits removed APIs (AttributeError, RuntimeError), not DeprecationWarnings, so the gate catches nothing. Add: "If you are skipping past 0.14, the deprecated APIs are already removed and fail with AttributeError/RuntimeError; run the suite on 0.13 first, or apply the prompts before upgrading."
M 340, 363, 376, 132 fact (stale) The convert recipes say "reviewed Alembic migration" only. Ferro now ships its own migrations door (ferro migrate new, hand-written steps). "a reviewed migration (a hand-written step in ferro migrate, or an Alembic revision)".
M 154–166, 179–196, 205–227, 269–282 7 Before/after tab groups have no result sentence. Readers are not told what the "After" returns or raises. One sentence after each group, e.g. "Both queries return the same rows; only the predicate spelling changed."
L 9, 198, 229, 262, 284 5 "Upgrade Guide" is in title case. Several H3s are sentences ("create() no longer overwrites on primary-key conflict"), and identifiers in headings lack code font. Title "Upgrade guide"; "create() on a primary-key conflict", "save() and upserts", "limit()/offset() on mutations", "Typed exceptions".
L 22–29 completeness The table lacks "0.11.x or earlier → 0.15" (all three sections) and "0.14.x → 0.15" is the only 0.15 single-hop row. Generate the table as "from X: read sections X+1…current". A range rule reads better than enumerated pairs.
L 90, 320 22 "ADR-0005" and the repo path docs/solutions/patterns/derived-type-and-naming-decision-table.md point at files not on the site. Link to GitHub, or drop them.
L 58, 101, 436 ext ??? example collapsible prompts are a good use of details. Keep them. —

Activity

  1. added
    documentationImprovements or additions to documentation
    ready-for-agentUnblocked and fully specified; an agent may claim it
    size:MNeeds a plan; one or two local workers
    on Oct 19, 2026
  2. added theissue type on Oct 19, 2026
  3. self-assigned this
    on Oct 19, 2026
  4. 0x054 commented on Oct 19, 2026

    @0x054
    ContributorAuthor

    Status: verify-passed
    Worker: worker-707
    Branch: sdd/707-upgrade-guide
    PR: #741
    Verify: passed e27d99a (and on trial merge into feat/docs-rewrite acd1127)

    Re-review of the fix round: spec PASS, quality PASS. The 4 dead anchors, the stale v0.13 output in guide/connections.md and the mislabelled 0.14 tab are all addressed. The only red on the merge is 3 tests/test_docs_migrations.py RLS tests, already on the base (fixed by #744).

  5. 0x054 commented on Oct 19, 2026

    @0x054
    ContributorAuthor

    Merged in #741 into feat/docs-rewrite

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationready-for-agentUnblocked and fully specified; an agent may claim itsize:MNeeds a plan; one or two local workers

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions