Skip to content

AGENTS.md: rewrite I-8 for the lambda-only query API, add a docstring invariant, record the docs conventions #703

Closed

Description

@0x054

Parent

#698

What to build

AGENTS.md I-8 still orders predicate styles "lambda > col() > operator" and calls operator style "compatible today", but both col() and operator predicates were removed in 0.14 and where() rejects non-callables. Five auditors flagged it.

  • I-8 describes the API that exists: lambda predicates, the parameter named after the model in lowercase singular, and order_by's column-name string or lambda selector. The col() and operator clauses and the "slated for deprecation" text go. It names the lint (python -m tests._docs_checks) that enforces the naming once the harness ticket (Docs harness: run inline blocks with a prelude, run docstring examples, and check lambda names and error checks #704) lands.
  • A new invariant (I-14, docstrings) records the conventions the docstring tickets apply: Google style as griffe parses it; a one-line infinitive summary ending with a period (class summaries a noun phrase); every parameter in Args:; a one-line docstring on every public dataclass or Pydantic field; Markdown autorefs, never Sphinx roles; no ADR numbers, issue numbers, codenames or Rust internals; examples in the lambda style against the shared reference prelude; explanations longer than a paragraph live in a guide and are linked.
  • docs/solutions/patterns/ gets two notes (I-5): docs-page-conventions.md (one kind per page, one running example per page, snippet end: markers below the result, the session wrapper rule, generated SQL beside queries once SQL inspection and logging: print or log the SQL Ferro renders and runs for a query or mutation #700 lands, the glossary file, the one Annotated idiom for twins: Annotated[T, Field(...)] = default) and docstring-conventions.md (the I-14 rules with before/after examples).

Edits follow the writing-for-agents skill.

Acceptance criteria

  • I-8 mentions neither col() nor operator-style predicates except to say they were removed in 0.14.
  • AGENTS.md has an ## I-14 section with every rule listed above.
  • Both solutions notes exist with the frontmatter docs/solutions/README.md requires, and the README index lists them if it keeps an index.
  • The Annotated idiom the note names is the one the twins will be converted to, and the note gives one before/after pair.

Files owned

  • Create: docs/solutions/patterns/docs-page-conventions.md, docs/solutions/patterns/docstring-conventions.md
  • Modify: AGENTS.md, docs/solutions/README.md

Interfaces

  • Consumes: nothing from other tickets
  • Produces: AGENTS.md I-8 (rewritten) and I-14 (docstrings), read by every page and docstring ticket.
  • Produces: docs/solutions/patterns/docs-page-conventions.md and docstring-conventions.md, read by every page and docstring ticket.

Test scenarios

  • Test expectation: none, because this ticket changes contributor guidance only; the Verify block checks the text is present.

Verify

grep -q '^## I-14' AGENTS.md
! grep -nE 'slated for deprecation|compatible today' AGENTS.md
test -f docs/solutions/patterns/docs-page-conventions.md
test -f docs/solutions/patterns/docstring-conventions.md

Blocked by

None (can start immediately)

Audit findings

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

Cross-cutting patterns

  1. I-8 lambda parameter naming is broken in most query examples. About 70 single-letter lambdas: existence_tests.py 11, populated_relations.py 16, partial_selects.py 17, aggregations.py 24, inline queries.md 12. queries.md:62 explicitly teaches "t by convention". Only predicates.py and traversal.py comply.
  2. AGENTS.md I-8 is out of date with the code. col() and operator-style predicates were removed in 0.14, so the "lambda > col() > operator / slated for deprecation" rule describes nothing that exists. One page link (queries.md:874, "three predicate styles") still carries the old story. Fix AGENTS.md as well as the page.
  3. Results hidden from the reader (rule 8): 27 snippets in queries.md alone. Snippet end: markers sit just above the asserts that hold the answer. The pages whose snippets include their asserts (partial_selects, aggregations) read noticeably better. Moving the markers fixes most of it.
  4. No running example (rule 3) on 2 of 3 pages. models-and-fields.md uses 14 unrelated models. queries.md has 4 incompatible Transaction models plus inline references to models no schema on the page defines (Post, user.posts, user.deleted_at).
  5. Schema facts drift from the DDL lowering. About 12 wrong type cells or claims in models-and-fields.md (str→TEXT, datetime→TIMESTAMP, enum→TEXT, UUID width, int→BIGINT), and singular/plural table names in queries.md (2). Generating the type table from resolve_column_storage in a test would stop this class of drift.
  6. Headings mix Title Case, sentence case and slogans (rule 5): about 35 headings across the 3 pages. H2 Title Case with H3 sentence case on the same page. Sentence and slogan headings ("One verb, loud dead ends", "Zero rows, zero groups") name nothing to search for.
  7. No links to the API reference (rule 4/22) on all 3 pages. api/fields.md, api/model.md and api/queries.md exist but are never linked. The pages retype option tables and limit lists instead.
  8. Generated SQL is missing or simplified (rule 13). Aggregations shows no GROUP BY, models-and-fields shows DDL once out of about 10 schema features, and 4 queries.md SQL blocks are hand-simplified (unquoted reserved words, invented aliases) while the lead-ins claim "ships to the database as".

Also seen: 3 try/except-without-else example blocks that cannot fail (rule 9). Tab labels are inconsistent (1), and content.tabs.link is not enabled in zensical.toml; with it on and the labels matched, a reader's Assignment/Annotated choice would follow them across every tab set.

Cross-cutting patterns

  1. mkdocstrings config renders internals and noise (9/9 API pages). show_if_no_docstring = true, show_source = true, no filters and no merge_init_into_class: about 180 docstring-less members, dunders on every dataclass, __ferro_*__ registry state, and 191 source blocks. One config change (filters, merge init, source off) plus about 60 short attribute docstrings fixes most of it.
  2. Sphinx roles in Google-style docstrings (8/9 pages, about 220 literal :class:/:func:/:meth:/:data: occurrences), plus one #294 line that became a heading. Convert them to mkdocstrings cross-refs.
  3. Missing public API entries (5 objects). FieldProxy, QueryNode, RelationProxy and ValueExpr are exported from ferro.query and undocumented; ModelConnection and EngineManager.session are undocumented, though they are the core of routing. Two entries use private module paths (query.builder.Query, migrations.steps.chunked).
  4. Stale facts that contradict code or sibling pages (7). The architecture implementation-status note and SchemaIR bullet, lambda t: t.active (raises), the type-safety IDE completion claim, Postgres JSON instead of jsonb, the missing time row, performance's identity-map caching, and performance's "eager loading on the roadmap".
  5. I-8 parameter naming (lambda t:) in predicates: 13 occurrences across architecture (3), type-safety (3), performance (3), identity-map (1) and api/queries.md table rows. The AGENTS.md I-8 text itself is stale about operator style still working.
  6. Inline field-declaring examples are not test-backed (2 pages, 2 tabbed blocks). I-7 requires compile checks; tests/test_docs_examples.py covers only docs/examples/*.py.
  7. Title Case and non-noun headings (6/6 concept pages, about 35 headings) against rule 5's sentence case. Several are slogans ("No Session, No Identity", "Where It Doesn't", "What This Doesn't Change").
  8. Internal tracking IDs and contributor detail in user-facing text. ADR numbers (about 100 rendered mentions), #NNN, "FF-F F-2", "Phase 8.5", test-file names and a docs/plans/ link. Readers cannot act on these. Link the ADR where the reasoning helps, and drop the rest.

Activity

  1. added
    documentationImprovements or additions to documentation
    ready-for-agentUnblocked and fully specified; an agent may claim it
    size:SOne context window, <= 3 files; cloud-eligible
    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-703
    Branch: sdd/703-agents-i8-i14
    PR: #727
    Verify: passed 337bcbf

    Review by reviewer-703: Spec PASS, Quality PASS. Four Minor findings only, no trial merge needed (base unchanged). Review is posted on the PR.

  5. 0x054 commented on Oct 19, 2026

    @0x054
    ContributorAuthor

    Merged in #727 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:SOne context window, <= 3 files; cloud-eligible

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions