docs(guidelines): internal-doc writing style, size discipline, six harvest runs - #10030
docs(guidelines): internal-doc writing style, size discipline, six harvest runs#10030saltas888 wants to merge 17 commits into
Conversation
There was a problem hiding this comment.
1 issue found across 3 files
Confidence score: 5/5
- In
dev/guidelines/changelog.md, the main risk is process drift: targetingdevelopfor a docs-only change can bypass the base-branch policy and lead to guidance landing out of the expected release flow—retarget this PR tostableto keep documentation updates aligned with branch rules.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="dev/guidelines/changelog.md">
<violation number="1" location="dev/guidelines/changelog.md:55">
P3: This docs-only change targets develop, but per the base-branch rules, changes that can't affect a running product (including docs, tooling, CI) should target stable. Consider retargeting to stable so the guidance ships sooner rather than waiting for the next minor release train.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
Re-trigger cubic
|
|
||
| ## When to Skip | ||
|
|
||
| Skip the fragment entirely when the change has **no user-facing effect** — an internal |
There was a problem hiding this comment.
P3: This docs-only change targets develop, but per the base-branch rules, changes that can't affect a running product (including docs, tooling, CI) should target stable. Consider retargeting to stable so the guidance ships sooner rather than waiting for the next minor release train.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At dev/guidelines/changelog.md, line 55:
<comment>This docs-only change targets develop, but per the base-branch rules, changes that can't affect a running product (including docs, tooling, CI) should target stable. Consider retargeting to stable so the guidance ships sooner rather than waiting for the next minor release train.</comment>
<file context>
@@ -50,6 +50,14 @@ uv run towncrier create -c "Added breadcrumb navigation for hierarchical schemas
+## When to Skip
+
+Skip the fragment entirely when the change has **no user-facing effect** — an internal
+type-annotation correction, a refactor with no behavior change, cleanup of internal docs or
+spec-kit scaffolding. `housekeeping` is for internal changes a user could still plausibly notice
</file context>
There was a problem hiding this comment.
I know but there's a big deviation on the patterns that are described in develop and stable, therefore in stable we will have to describe code that actually doesn't exist. I'd need to check if we can split some parts
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Shadow auto-approve: would not auto-approve. Auto-approval blocked by 2 unresolved issues from previous reviews.
Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 3 files (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Shadow auto-approve: would not auto-approve. Auto-approval blocked by 2 unresolved issues from previous reviews.
Re-trigger cubic
b14e38b to
001fd00
Compare
There was a problem hiding this comment.
1 issue found across 7 files (changes from recent commits).
Confidence score: 5/5
- In
dev/guidelines/backend/python.md, extract/opsmill still points “New error handling conventions” to the old location even though guidance moved todev/guidelines/backend/exceptions.md, which can send agents to stale instructions and cause inconsistent exception-handling patterns — update the routing/reference mapping to the new doc path.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="dev/guidelines/backend/python.md">
<violation number="1" location="dev/guidelines/backend/python.md:403">
P3: Now that Exception Handling lives in the new `dev/guidelines/backend/exceptions.md`, the extract/opsmill tooling still routes agents to `dev/guidelines/backend/python.md` for "New error handling conventions" — both in `.agents/commands/speckit.opsmill.extract.md` (lines ~106-107 and the template table) and `.agents/skills/speckit-opsmill-extract/SKILL.md` (lines ~108-109). Following those instructions would send a future contributor to a file that no longer carries the exception-handling content. The git-workflow.md change here shows the intent to repoint references; consider updating these .agents routing entries to `dev/guidelines/backend/exceptions.md` to keep the move consistent.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| @@ -267,6 +267,22 @@ async def set(self, key: str, value: str, expires: KVTTL | int | None = None) -> | |||
|
|
|||
There was a problem hiding this comment.
P3: Now that Exception Handling lives in the new dev/guidelines/backend/exceptions.md, the extract/opsmill tooling still routes agents to dev/guidelines/backend/python.md for "New error handling conventions" — both in .agents/commands/speckit.opsmill.extract.md (lines ~106-107 and the template table) and .agents/skills/speckit-opsmill-extract/SKILL.md (lines ~108-109). Following those instructions would send a future contributor to a file that no longer carries the exception-handling content. The git-workflow.md change here shows the intent to repoint references; consider updating these .agents routing entries to dev/guidelines/backend/exceptions.md to keep the move consistent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At dev/guidelines/backend/python.md, line 403:
<comment>Now that Exception Handling lives in the new `dev/guidelines/backend/exceptions.md`, the extract/opsmill tooling still routes agents to `dev/guidelines/backend/python.md` for "New error handling conventions" — both in `.agents/commands/speckit.opsmill.extract.md` (lines ~106-107 and the template table) and `.agents/skills/speckit-opsmill-extract/SKILL.md` (lines ~108-109). Following those instructions would send a future contributor to a file that no longer carries the exception-handling content. The git-workflow.md change here shows the intent to repoint references; consider updating these .agents routing entries to `dev/guidelines/backend/exceptions.md` to keep the move consistent.</comment>
<file context>
@@ -476,5 +400,6 @@ For additional information around testing patterns refer to [./testing.md](./tes
## See Also
+- [Exception Handling](exceptions.md) - Catching, scoping, and suppressing exceptions
- [Backend Architecture](../../knowledge/backend/architecture.md) - Backend architecture overview
- [Git Workflow](../git-workflow.md) - Git workflow and commit conventions
</file context>
There was a problem hiding this comment.
Do these skills need to reference this exact file? It creates this kind of issue
There was a problem hiding this comment.
The skills need a concrete load target in the current routing design, but python.md is no longer the right target for exception handling. The parent comment still applies: these stale references should be repointed to dev/guidelines/backend/exceptions.md; this PR does not show a stable alternative routing mechanism.
PR #10018 (INBOX-20) got a reviewer ask for the whole PR to be just the 5-line repository.py annotation fix: no dev/specs/ spec-kit scaffolding, no changelog fragment for a change with no user-facing effect. Neither constraint was written down anywhere, so an agent following the normal speckit pipeline had no way to know to trim them. Document both: - changelog.md: skip the fragment when a change has no user-facing effect; housekeeping is not a catch-all for anything code-adjacent. - repository-organization.md: the spec-kit design record should be proportional to the change it documents, not a fixed-cost byproduct of running the workflow. - git-workflow.md: cross-reference both from the Pull Requests section so the rule is reachable from root AGENTS.md's Coding Standards link. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013MwudkACUQdCZTJ5aVBnr3
PR #10079 widened RelationshipManager.update()'s data parameter from an invariant list to a covariant Sequence to drop a call-site type: ignore. The reviewer's "definitely would have missed this one" was for the carve-out that makes it safe: str satisfies Sequence, so isinstance(data, str) must be checked before isinstance(data, Sequence), or a bare peer id gets iterated character-by-character. Nothing in the guidelines named this gotcha, so document it next to the neighboring isinstance-narrowing and list/Sequence-variance sections. The PR's other two review threads (skip-changelog for no-user-visible- effect changes, and proportional dev/specs/ ceremony) restate lessons already codified on this branch by c1b89c4 (INBOX-20) — that commit just hasn't reached develop yet, so PR #10079's branch never saw it. No doc gap, no edit needed there. The approving review's PeerWithRelationshipMetadata read/write-split suggestion is a real, confirmed observation (manager.py and node/create.py populate it asymmetrically) but is scoped to that one class, not a recurring authoring convention — discarded from this harvest as PR-local tech debt rather than encoded as a rule. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WgpvpBsruPYD3fYpyfzL7R
…NBOX-19] PR #10002 (INBOX-19) re-enabled ruff's BLE (blind-except) rule and resolved 78 violations: 8 narrowed to specific exception types, 70 kept `except Exception` with a justification comment + `# noqa: BLE001`. Reviewer @ogenstad's threads on that PR, plus an independent cubic-dev-ai finding, surfaced three durable gaps beyond "narrow when you can" (already documented in python.md's Exception Handling section): - No existing guidance asked whether a catch is needed *before* choosing its scope. @ogenstad on api/auth.py: the guarded event-emission goes to an internal queue that can't block the response, so the defensive catch is likely unnecessary altogether - a background task after the response is the better shape when isolation is genuinely required. Same pattern flagged on oauth2.py and oidc.py. - "Deliberate design choice" (the bar for `# noqa: BLE001`) was previously illustrated only by "top-level boundary" (task worker loop, request handler) - too narrow for the batch/collection and best-effort shapes this PR actually used 70 times over. Named all three explicitly with a worked example. - cubic-dev-ai flagged that the justification comment on m066_consolidate_duplicate_number_pools.py's except ("failures become MigrationResult errors") overstates safety: the `return` happens inside `async with db.start_transaction()`, so `InfrahubDatabase.__aexit__` (backend/infrahub/database/__init__.py:298-307) sees no exception and *commits* the partial work instead of rolling it back. Verified directly against both files. The new subsection requires a justification comment to state the actual commit/rollback consequence when nested inside a transaction, with a before/after example built on the real bug shape. Also documented (@ogenstad, twice, on validators/tasks.py and infrahub_load_tester.py): a lint-suppression PR that surfaces a pre-existing behavioral bug should ship the annotation only and file the bug separately, not fix it inline. New git-workflow.md bullet under Pull Requests, cross-linked from the noqa subsection above since the same transaction/commit bug is the concrete example of exactly this pattern. Extended dev/knowledge/backend/async-tasks.md's existing "post-commit follow-up is best-effort" contract with one sentence: it was scoped to per-item batch dispatch, but the same shape (confirm the call can fail, then isolate via a background task rather than an inline try/except) applies to a single inline side effect in a request handler too. Not encoded as a lesson: the three specific bugs flagged in review (m066 commit-not-rollback, tasks.py retry-defeating catch, infrahub_load_tester.py's undefined `all_branches` on failure) are PR-local defects, not conventions - the review thread itself already treats them as follow-up candidates pending a human filing decision. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6uYDCYNXbWUdkFEJLW3Zx
…accrete rule
Internal docs had no concision rule and no size discipline, so harvested
lessons arrived padded and always additive: over the last four months
dev/guidelines and .agents/rules took +222/-16 lines, and this branch's own
harvests pushed backend/python.md to 480 lines against its 100-400 range.
The routing rules ("edit before create", "strengthen before duplicate") stop
duplicate rules, not growth — nothing in the flow ever removed a line.
Two additions:
- dev/guidelines/documentation.md gains "Writing Style / For Internal Docs",
covering dev/, the AGENTS.md files, and .agents/ — rule first, plain words,
no provenance, no padding, a budget, and pay-for-it: cut what the new rule
supersedes and check the file's size range before appending.
- The harvesting-review skill leads with "Refine, don't accrete", flagged as
outranking its other rules: measure the file first, compress or split one
that is at its limit, cut superseded prose, and report added/removed line
counts, since a harvest that deletes nothing accreted rather than refined.
Paid for the skill's new section by compressing its 1A load-trigger block,
which had grown into eight lines telling the reader to keep entries short.
Also drops the routing example that pointed at dev/guidelines/changelog.md,
which no longer exists now that changelog conventions live in the
creating-changelog-entries skill, and applies the new brevity rule to the
sections this branch added that read long.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
python.md had reached 480 lines against the 100-400 range that repository-organization.md sets for dev/guidelines, and this branch's harvests added 55 of those. Applying the rule the previous commit introduced: the file at its limit gets split, not extended. Exception Handling and the # noqa: BLE001 subsection move verbatim to dev/guidelines/backend/exceptions.md, which leaves python.md at 405 lines and gives the exception rules their own loadable home. Dropped the standalone "broad except is justified only at a top-level boundary" paragraph on the way, since the noqa list's first bullet already says it. Load-triggers updated so the new file is reachable: entries in backend/AGENTS.md, root AGENTS.md, and dev/README.md, plus a See Also link from python.md. The two inbound anchor links (git-workflow.md and knowledge/backend/async-tasks.md) now point at the new file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PR #10146 (INBOX-30) removed a stale mypy override with no source change, and its review threads surfaced three durable gaps. Two were suggested candidates going in; investigation confirmed one and sharpened the other, plus turned up a third while mining the same threads. - cubic-dev-ai flagged a changelog fragment missing towncrier's `+` orphan prefix. The rule already exists in four places (the skill file, two backend/AGENTS.md refs, git-workflow.md, and the PR template checklist), so this is "covered but still flagged," not missing: the doc states the rule but never the failure mode, which is the concrete detail cubic had to supply. Added the consequence (bogus issue link / skipped fragment) to creating-changelog-entries/SKILL.md's Common Mistakes list. - Reviewer @ogenstad's "this needs to be rebased" corrected an escalation that reasoned from "0 commits behind, so a rebase is a no-op." That reasoning was actually correct at the moment it was made — the defect was trusting it unchanged after time passed (waiting on the review) and the upstream base got fixed in the interim (#10147). Neither rebase/SKILL.md (which documents a different mistake: counting against a stale local ref instead of origin/<base>) nor monitoring-pull- requests/SKILL.md addressed re-verifying a stale snapshot. Added a callout to the latter's Phase 2: re-fetch and recompute immediately before deciding, reproduce against the base's current tip, and treat a reviewer's rebase suggestion as a cue to re-verify rather than repeat an earlier count. - Self-disclosed in the same thread: `invoke lint`/`invoke backend.lint` run `ruff check --diff` (tasks/main.py:39, tasks/backend.py:101), which reports only auto-fixable rewrites and exits 0 on an unfixable violation. CI's python-lint job runs a plain `ruff check` (.github/workflows/ci.yml:325-326), so a locally-green lint run is not proof CI's will be. Verified both invocations directly before writing this down. Documented next to the commands themselves in root AGENTS.md's Linting & Formatting section. Not encoded: @ogenstad's unresolved "not sure we need a changelog entry for something like this" — no reply landed and the fragment shipped as-is, so there's no correction to derive a rule from. The existing housekeeping rule already tells the author to ask when unsure; whether this specific case should have triggered that is a human call, not something this thread settles. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KWG4Cvk9ZzseV73X9o1QTj
92018ec to
6b63305
Compare
| @@ -267,6 +267,22 @@ async def set(self, key: str, value: str, expires: KVTTL | int | None = None) -> | |||
|
|
|||
There was a problem hiding this comment.
Do these skills need to reference this exact file? It creates this kind of issue
| ### `str` satisfies `Sequence` — exclude it before narrowing | ||
|
|
||
| When a parameter accepts `T | Sequence[T] | ...` and `isinstance(data, Sequence)` (or `Iterable`/`Collection`) is how the code tells "one item" from "many", check `str` first whenever `T` includes `str`. A bare string satisfies `Sequence` in its own right, so without the carve-out it falls into the "many" branch and gets iterated character-by-character instead of treated as a single item — silently, if the single-item branch also accepts `str`. | ||
|
|
||
| ```python | ||
| # ❌ Bad - a bare id like "abc-123" satisfies Sequence and gets shredded into one item per character | ||
| if not isinstance(data, Sequence): | ||
| data = [data] | ||
|
|
||
| # ✅ Good - str is excluded first, so a single id stays a single item | ||
| if isinstance(data, str) or not isinstance(data, Sequence): | ||
| data = [data] | ||
| ``` | ||
|
|
||
| Widening a parameter from `list[T]` to `Sequence[T]` means widening this runtime check in step: an annotation that newly accepts `str` while the `isinstance` check still assumes a `list` misroutes every bare string. Test both the bare `str` and the newly-accepted non-`list` sequence (a `tuple`). |
There was a problem hiding this comment.
This is a personal take but I am not a huge fan of this pattern. I think we should get rid of them instead of patching potential typing bugs with a dedicated section inside our documentations.
In my opinion, let's use a Sequence or a list directly.
There was a problem hiding this comment.
Agreed, replaced the section with a rule against the pattern itself, take Sequence[T] and let callers wrap. Kept one line on the str carve-out for existing code.
| - **Say it once**: if the rule is already written elsewhere, link to it instead of restating it | ||
| - **Budget**: a new rule is a few lines plus one example. If it needs more than that, it's an | ||
| explanation for `dev/knowledge/`, not a guideline | ||
| - **Pay for it**: cut the prose the new rule supersedes, and check the file against its size range |
There was a problem hiding this comment.
Should we use the pruning-residues skill and iterate over it if there is any enhancement to do on it?
There was a problem hiding this comment.
The harvesting skill now routes lessons into the skill that owns the workflow and runs the diff through pruning-residues when available. It's not in our skills-lock yet, will add it as a follow-up.
| ### Linting & Formatting | ||
|
|
||
| ```bash | ||
| uv run invoke format # Format all Python code | ||
| uv run invoke lint # Lint all Python code | ||
| cd frontend/app && pnpm biome:fix # Format/lint frontend | ||
| uv run invoke docs.lint # Lint documentation | ||
| ``` | ||
|
|
||
| `invoke lint`/`invoke backend.lint` run `ruff check --diff`, which reports only auto-fixable issues | ||
| and exits 0 on an unfixable violation (e.g. an unsuppressed `BLE001`) that CI's plain `ruff check` | ||
| still fails on. Run `uv run ruff check <path>` directly to see the full picture before trusting a | ||
| clean local run. | ||
|
|
There was a problem hiding this comment.
Just a comment in case this sounds useful: a /pre-ci skill exists with a --fast option that trigger a bunch of CI checks locally. These checks include these lint steps
Twelve merged PRs audited; the lessons that generalize are routed into the internal-doc layer, and the citation rot earlier runs left behind is fixed in the same pass. New rules: a benchmark must exercise the input shape a conditional optimization is gated on; reset shared Jotai atoms, mocks and URL state between component tests in one file; tasks/*.py imports stay function-local; a path-exclusion check must not use a bare startswith; a component's initialize() clears every derived cache, not just the obvious field; changelog fragment names use the GitHub issue number, never an internal tracker ID; don't add a return value to a mutating method just so a test can assert on it; a Map lookup seeded from the array you index it with is still a type lie when asserted with !; no file.py:line citations in internal docs. Strengthened where a rule existed but a reviewer still had to raise it: the module-singleton reset-hook case in the frontend unit-test guide, and a cross-link to the add_tags() pitfall where the async-task guide teaches the pattern that reproduces it. Pruned: stale PR/issue citations across five files, a defect-snapshot note that described a current bug rather than a durable convention, and a templates.md reference to a method that had since been renamed. Replayed from stable onto the internal-doc-style branch so both harvests land as one stack. Two reconciliations where the branches overlapped: - The skill's rot sweep now sits under the "Refine, don't accrete" principle the base branch added rather than beside it, and the apply step applies both. - The no-file.py:line rule joins the sibling work-item-citation rule in documentation.md's Don't list; the base branch's "No provenance" bullet points at both instead of restating them. Splitting ASGI Middleware out of python.md pays for the path-matching lesson this run adds. With it the file would have reached 431 lines against a 100-400 range, and the rule the base branch introduced says a file at its limit gets split, not extended. python.md ends at 393. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit facc5d3)
Fifteen merged PRs audited across develop and release-1.11. Three of the lessons were already written down and a reviewer still had to raise them, so those are strengthened in place rather than duplicated. Strengthened: - backend-component-design: the whole object graph is built at the entry point in one pass, not part-way through a run, and invalid wiring raises while the graph is built instead of degrading to a runtime fallback. One reviewer made this point four times in two PRs against a rule that is auto-injected on every turn; it only forbade construction inside __init__. - backend/testing: names the parametrize shape that actually got written — dict keys in the decorator, values looked up inside the test. - frontend/page-architecture: the no-mirroring rule was stated for forms and useState only, so URL state copied into a Jotai atom slipped past it. Added: - query-pattern: pass limit/offset to the base Query constructor, since execute() reads self.limit/self.offset to choose how to run and pages the query in chunks when both are None; and read a collect() column with get_as_list_of_type rather than unpacking rows. - code-doc-style: spec vocabulary is as unreadable as a spec ID in a test name or docstring. - documentation: measurements go in as relative comparisons, not absolute figures that depend on the environment they were taken in. - frontend/writing-component-tests: a test has to fail when the behavior breaks — assert the value and not the static text around it, and check the component reads the flag the setup varies. - python: the tasks/*.py function-local import exception covers a thin wrapper, not logic hosted in tasks/. Pruned: - typescript.md taught useMemo/useCallback dependency arrays while knowledge/frontend/react.md says not to use them at all under the React Compiler. A reviewer had to ask which was right. - schema-definitions.md pointed at an issue for planned improvements that closed on 2026-07-20. - query-pattern.md was 520 lines against a 200-400 range and this run adds to it, so its five near-identical result-dataclass walkthroughs collapse into one example plus an accessor table. The file ends at 459. Net -40 lines. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit 4c4a19d)
A harvesting-review run over the week's review threads, restricted to the PRs the in-flight harvests (#10145, #10098) did not read: open and recently-merged PRs across develop, stable, and release-1.11. New rules and knowledge: - mutations.md: retry_db_transaction placement — wrap only rollback-able transaction scopes, skip under a caller-supplied transaction (#10121) - query-pattern.md: READ queries with insert_limit=False need their own LIMIT; auto-paginated reads need a total-order ORDER BY (#10132) - creating-migrations.md: fix data bugs at the migration layer, not in runtime save paths (#10105); per-item error collection (#10132); batch by the memory-bounding unit (#10132) - database-schema.md: generic kinds exist only as labels — n.kind never matches a generic; type concrete-only inputs as list[NodeSchema] (#9805) - events.md: changelog models mask secrets only at construction — post-hoc assignment leaks them into events (#10105) - async-tasks.md: InfrahubBatch is concurrent, not ordered (#10113) - testing.md + testing-python.md rules: wiring tests parse source with ast/inspect instead of instrumenting production code (#10121); poll-don't-sleep for async effects (#10133); branch-attributable removal assertions (#10132); pure-function extraction before skipping the cheap test tier (#10137) - checklist.md: new Settings fields must reach both compose entry points — one generated and CI-checked, one hand-maintained (#10122) - backend/AGENTS.md: new REST endpoints are ask-first — prefer existing GraphQL for SDK needs (#8594); route creating-migrations.md in Guides - pre-ci.md: invoke lint tasks run ruff check --diff, which exits 0 on unfixable violations — added the plain CI-parity ruff check (#10146) - development/grafana/AGENTS.md (new): only defined datasource variables, sweep drill-down links, regenerate the standalone compose (#10153) - docs/AGENTS.md: Excalidraw exports use an opaque white background (#9953) Strengthened in place: - creating-changelog-entries skill: removed the 'most maintenance still gets a fragment' push that contradicted the no-user-facing-effect boundary; added lint/typing config cleanups as a named example (#10146) Paid for by compressing testing.md's nested-dataclass example and query-pattern.md's duplicated accessor/return-properties sections. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYisRTn3sPygP55cxbVqzG (cherry picked from commit ca2190d)
Review follow-ups from #10030's threads, applied on top of the three cherry-picked harvest runs (#10098, #10145, #10157): - backend/AGENTS.md: keep the coding-standards list contiguous and let the exceptions.md pointer follow it, dropping the duplicated exception-handling bullet (cubic, polmichel) - speckit.opsmill.extract command + skill: error-handling conventions now route to dev/guidelines/backend/exceptions.md, and the target list is marked as routing examples to re-verify before writing (cubic, polmichel) - dev/guidelines/backend/python.md: replace the str-satisfies-Sequence survival section with a rule against one-or-many unions - prefer Sequence[T]/list[T] parameters and let callers wrap (polmichel) - AGENTS.md: compress the ruff --diff caveat and point at /pre-ci, which carries the CI-parity check (polmichel) - dev/guidelines/repository-organization.md: point the Git Workflow cross reference at its #pull-requests anchor (cubic) - harvesting-review skill 0.8.0: a split or move repoints every inbound reference including .agents/skills and .agents/commands routes; a lesson whose root cause is a fragile pattern becomes a rule steering away from the pattern, not a survival guide; lessons owned by an existing skill (creating-changelog-entries, pre-ci, pruning-residues) are routed into that skill instead of a parallel dev/ rule. Paid for by compressing the sweep's fix-every-hit prose and the report template comments. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 37 files (changes from recent commits).
Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
- harvesting-review skill: the sweep greps now include .agents/rules, which the prose already claimed; pruning-residues is identified as an org skills-plugin skill not vendored in this repo - mutations.md: the retry decorator also replays on Neo.ClientError.Statement.EntityNotFound, not only TransientError - testing.md: wire the StaleEntryCleaner example (constructor + instantiation) so the snippet is reproducible - writing-component-tests.md: vi.resetAllMocks in the isolation example, clearAllMocks leaves mockReturnValue overrides in place - writing-unit-tests.md: promote Testing Module-Level Singletons out of Mocking to its own section, it is about module state, not mocks - typescript.md: relative link to react.md instead of a backticked absolute path - development/grafana/AGENTS.md: run convert_compose_standalone.py from development/, the script resolves default paths against the working directory Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
0 issues found across 7 files (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.
Re-trigger cubic
Conflict: dev/guidelines/backend/python.md — this branch splits Exception Handling and ASGI Middleware out of the file; develop's copies had meanwhile gained the best-effort-side-effects subsection (#10103). Kept the split and ported that subsection into dev/guidelines/backend/exceptions.md, where the noqa BLE001 section now cross-references it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Repointed them to exceptions.md, and the harvesting skill now requires repointing all inbound references on a split, including .agents, so this shouldn't recur. |
| reference and either skips the fragment or renders a bogus issue link instead of an orphan entry. | ||
| - **Hand-writing the fragment file.** Use `towncrier create` so the name and location are correct. | ||
| - **Placing it in a sub-package directory** (e.g. `backend/changelog/`) instead of the configured fragments directory. | ||
| - **Naming the fragment after an internal tracker ID** (Jira, Linear, etc.) instead of the GitHub issue number or `+`. Towncrier's `issue_format` turns the fragment name straight into a GitHub issue URL — an internal ticket ID renders a broken link in the shipped changelog. |
There was a problem hiding this comment.
Just to be sure: do we agree that the following naming is correct since the + is the first character? +ifc-2546-lorem-ipsum.md.
There was a problem hiding this comment.
Almost — the + does suppress the issue link so it's safe, but it's missing the type segment (needs .changed.md etc.) or towncrier won't pick it up. The ticket ID never renders in the output either way, so the slug is better spent on a description. Fixed in b7d06e0. Also found two fragments on develop missing the + (IFC-2747.fixed.md, infp-677.changed.md) that will ship broken links — queued a fix for those.
| Every run of this skill only adds. Nothing else revisits what a previous run wrote, so the layer | ||
| grows monotonically — a doc entry that was true and useful the week it landed can quietly become | ||
| stale, redundant, or wrong, and stays in place forever unless a run like this one checks it. Do this | ||
| sweep every time, not as an occasional separate cleanup — it is cheap (a handful of greps, not a | ||
| re-read of every doc) and it is what keeps "harvested" from becoming a synonym for "bloated." |
There was a problem hiding this comment.
Wdyt about explicitly referring to an existing skill? Like "/pruning-residues"?
It would be interesting to see whether this skill uses it without explicit statement, or not.
There was a problem hiding this comment.
I saw your following commit about that
There was a problem hiding this comment.
Already explicit since ae7986f (pushed before this comment) — named in both the routing rule and the apply step. Sounds like your follow-up found the same commit.
| green while the optimization silently regresses later. Before trusting a benchmark result on a | ||
| perf PR, check that the query/input it drives actually hits the changed code, not just a | ||
| similarly-named neighbor. | ||
|
|
There was a problem hiding this comment.
I'm not sure about this part of the text:
- It ties pytest-benchmark to CodSpeed, which is the tool we use to create and interpret the results of pytest-benchmark.
- This text says "Do not trust CodSpeed results". In that case, I think we should either write better tests or drop CodSpeed.
There was a problem hiding this comment.
Fair, reworded in b7d06e0. The point isn't that CodSpeed is untrustworthy — it's that a benchmark hitting a different path measures the neighbor, so "no change" is an honest report of the wrong thing. Dropped the tool from that sentence.
|
|
||
| **The whole graph is built there, in one pass, before the work starts.** A component that builds a collaborator part-way through a run — when the flow reaches the step that needs it — has the same problem as one that builds it in `__init__`, and is harder to follow because the wiring is spread across the execution. Pass the collaborator in, and pass per-run values to the entry method instead of holding them as constructor state. | ||
|
|
||
| **Invalid wiring fails while you build the graph.** Validate the combination at construction and raise; never let a missing or mismatched collaborator surface later as a silently skipped step or a degraded fallback. Where a generic ties two sides together, parameterize both so the mismatch is a type error rather than a runtime discovery — a `Handler[Any]` paired with `Output[Any]` type-checks against anything and defers the failure to the run. |
| instead of writing it into `dev/knowledge`/`dev/guidelines`. | ||
| instead of writing it into `dev/knowledge`/`dev/guidelines`. The same test applies when the root | ||
| cause is a fragile *pattern* rather than a defect: if the honest fix is to stop writing the pattern | ||
| (a `str | Sequence[str]` union and its `isinstance` dispatch, for one), the lesson is the one-line |
There was a problem hiding this comment.
Not sure about this specific example in the text, it feels over-customized for this use case.
There was a problem hiding this comment.
Agreed, dropped in b7d06e0 — that was the str|Sequence example naming this PR's own case inside a general rule, exactly the over-customization the skill tells authors to avoid elsewhere.
docs/AGENTS.md's doc-type table and workflow pointed at guides/AGENTS.md and topics/AGENTS.md. Those were moved to docs/archive/ in #8958 and deleted in c5acd83; the guidance now lives in dev/guides/docs/writing-a-guide.md and writing-a-topic.md, already named further down the same file. Also dropped the two File Structure entries for the deleted files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
- dev/knowledge/backend/testing.md: reframe the benchmark lesson around the input rather than the reporting tool. The rule is that a benchmark taking a different path measures its neighbour, so "no change" is an honest report of the wrong thing; dropped the wording that read as "don't trust CodSpeed" - .agents/skills/harvesting-review/SKILL.md: drop the str|Sequence example from the fragile-pattern guardrail. Naming this PR's own case inside a general rule is the over-customization the skill's own style rules forbid - .agents/skills/creating-changelog-entries/SKILL.md: merge the orphan-prefix and tracker-ID mistakes into one bullet stating the filename shape. Answers whether +ifc-2546-lorem-ipsum is valid: the + suppresses the issue link so it is, but the type segment is required and the ticket ID never renders - docs/AGENTS.md: fully qualify the topic-guide path, matching #10259 Net -1 line across the four files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
Confidence score: 5/5
- In
.agents/skills/creating-changelog-entries/SKILL.md, the documented failure mode for non-numeric fragment names doesn’t match Towncrier’s actual parsing rules, which could mislead contributors and cause avoidable changelog-fragment naming mistakes in future PRs—update the guidance to reflect the\d+/+-orphan behavior configured in this repo.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".agents/skills/creating-changelog-entries/SKILL.md">
<violation number="1" location=".agents/skills/creating-changelog-entries/SKILL.md:90">
P3: The stated failure mode for a non-numeric fragment name is inaccurate. Towncrier only parses the fragment-name issue segment when it is an integer (`\d+`) or a `+`-orphan slug (this project's config sets `orphan_prefix = "+"`). A name like `IFC-2747.fixed.md` matches neither, so Towncrier skips it with a warning rather than running `issue_format` on it — it is dropped from the changelog, not shipped as a GitHub link to a nonexistent issue. The core advice (use an issue number or a `+` slug, don't name fragments after internal ticket IDs) is correct, but the described consequence misleads an agent about what happens: the fragment silently never appears.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| - **Getting the filename shape wrong.** It is `<issue-or-+slug>.<type>.md`; the type segment is | ||
| required, and a file without one is not picked up. Everything before it is either a GitHub issue | ||
| number or a `+`-prefixed slug, because `issue_format` turns a bare name straight into a GitHub | ||
| issue URL: `IFC-2747.fixed.md` ships a link to an issue that does not exist. The `+` marks the |
There was a problem hiding this comment.
P3: The stated failure mode for a non-numeric fragment name is inaccurate. Towncrier only parses the fragment-name issue segment when it is an integer (\d+) or a +-orphan slug (this project's config sets orphan_prefix = "+"). A name like IFC-2747.fixed.md matches neither, so Towncrier skips it with a warning rather than running issue_format on it — it is dropped from the changelog, not shipped as a GitHub link to a nonexistent issue. The core advice (use an issue number or a + slug, don't name fragments after internal ticket IDs) is correct, but the described consequence misleads an agent about what happens: the fragment silently never appears.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .agents/skills/creating-changelog-entries/SKILL.md, line 90:
<comment>The stated failure mode for a non-numeric fragment name is inaccurate. Towncrier only parses the fragment-name issue segment when it is an integer (`\d+`) or a `+`-orphan slug (this project's config sets `orphan_prefix = "+"`). A name like `IFC-2747.fixed.md` matches neither, so Towncrier skips it with a warning rather than running `issue_format` on it — it is dropped from the changelog, not shipped as a GitHub link to a nonexistent issue. The core advice (use an issue number or a `+` slug, don't name fragments after internal ticket IDs) is correct, but the described consequence misleads an agent about what happens: the fragment silently never appears.</comment>
<file context>
@@ -84,12 +84,14 @@ uv run towncrier create -c "Migrated the frontend build to pnpm workspaces" +pnp
+- **Getting the filename shape wrong.** It is `<issue-or-+slug>.<type>.md`; the type segment is
+ required, and a file without one is not picked up. Everything before it is either a GitHub issue
+ number or a `+`-prefixed slug, because `issue_format` turns a bare name straight into a GitHub
+ issue URL: `IFC-2747.fixed.md` ships a link to an issue that does not exist. The `+` marks the
+ entry as an orphan and suppresses the link, so `+ifc-2546-lorem-ipsum.changed.md` is valid — but
+ the ticket ID never appears in the output, so spend the slug on a description instead.
</file context>
cubic flagged these on #10270, the stable extraction; the files are byte-identical so they were live here too. The lint claim was factually wrong. Verified against tasks/main.py and tasks/backend.py: _lint_ruff runs 'uv run ruff check tasks models utilities python_testcontainers' and backend.ruff runs 'uv run ruff check backend', both plain. The only --diff is 'ruff format --check --diff', the formatter step. So the invoke tasks do exit nonzero on an unsuppressed BLE001 inside the paths they cover, and the real reason the whole-repo check is not redundant is coverage: CI runs 'ruff check . --exclude python_sdk', so a violation in development/, tests/, or a root-level script passes locally and fails in CI. Corrected in .agents/commands/pre-ci.md (both phases) and root AGENTS.md. - dev/guidelines/documentation.md: the citation example named core/regeneration/models.py::TargetSelection, a real module on develop but absent from stable. Replaced with a generic some/module.py::SomeClass, which is correct on both branches and cannot rot. - .agents/skills/harvesting-review/SKILL.md: the report template pointed at '(§6)' for house style, but §6 is Report; it now points at 'Refine, don't accrete'. The rot-sweep glob 'AGENTS.md */AGENTS.md' matched only one level deep, missing frontend/app/AGENTS.md and development/grafana/AGENTS.md; $(git ls-files '*AGENTS.md') covers all five and skips .venv, which a recursive glob would have pulled in. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same fixes as on #10030 (757b34f), keeping every file byte-identical across the two branches. - the invoke-lint justification was factually wrong: main.lint and backend.ruff both run a plain 'ruff check', the only --diff is the formatter's. The real reason the whole-repo check matters is coverage, since CI lints everything outside the four dirs main.lint covers - the citation example named a develop-only module; now a generic placeholder - the report template's '(§6)' house-style pointer aimed at Report - the rot-sweep glob missed AGENTS.md files two levels deep Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
0 issues found across 4 files (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.
Re-trigger cubic
PR #10220 (INBOX-29) re-enabled ruff TRY400 across 36 backend logging sites. Its review was unusually dense - two cubic findings, a rebutted release-vehicle finding, and a long CI-triage thread - and investigation turned up five durable gaps. - cubic-dev-ai flagged graphql/app.py's ClientDisconnect site being converted to log.exception when it's a routine, expected condition (the traceback only shows the body-read path). The author's own research.md stated the criterion ("convert unless the traceback would be actively harmful or worthless") and misapplied it on this exact site - meaning the criterion existed only in a throwaway per-PR spec doc, never in the durable guideline. Added a log.exception vs log.error section to exceptions.md with both the worthless case (this one) and the harmful case (cross-linked to webhooks.md's TracebackSuppressionFilter, the mechanism the same PR's webhook site depends on). - cubic also flagged the same PR's tasks.md citing absolute line numbers that its own commits shifted mid-review. That rule already exists almost verbatim in documentation.md ("cite the module path and symbol only... a spec's own line-numbered citations routinely rot before the feature it describes even merges") - so this is "covered but still flagged," not missing. Neither speckit-plan nor speckit-tasks, the skills that actually generate research.md/plan.md/tasks.md, pointed at that rule while enumerating sites. Added a one-line pointer to each. - The same post-review fix (28/6 to 27/7 conversions) went stale in five sibling spec files (plan.md, research.md, tasks.md, alignment-check.md, the implementation report) before cubic finished flagging all five individually. Root AGENTS.md already tells authors to verify a claim against the diff before writing it down; extended that bullet to also require propagating a later correction across every file in dev/specs/<feature>/ that restates the same figure, not just the one a reviewer pointed at. - cubic asked whether this should target stable instead of develop ("repo tooling... cannot affect a running product"). The rebuttal was right (the diff converts 27 runtime logging call sites; the closest precedents targeted develop) but the underlying policy it invoked - "release-vehicle guidance" - doesn't exist anywhere in dev/ or AGENTS.md; grepped for it directly. Added the rule both sides were actually reasoning from into git-workflow.md's Branch Strategy: a tooling/lint/CI change with a runtime source diff targets develop like a product change; only a zero-source-diff change targets stable. - The PR's CI came back red repeatedly on self-hosted-runner exhaustion, and each reconcile pass proved out two techniques monitoring-pull- requests/SKILL.md didn't have: citing a specific run on the base branch as proof a failure predates the PR (rather than an inferred "probably pre-existing"), and re-running a failed job on the same SHA instead of pushing a fix-attempt commit first, since ci.yml sets concurrency.cancel-in-progress: true and a new push cancels the experiment. Added both to Phase 2's existing staleness callout. Not encoded: a Vale spelling-exceptions judgment call (reword a fragment vs. add a one-off word to the shared vocabulary) - no evidence this recurs, and the decision is a generic technical-writing tradeoff rather than an Infrahub-specific gotcha. The "rebase deliberately skipped" call and the runner-exhaustion diagnosis itself are the existing staleness rule working correctly and an infra incident, respectively - not new lessons. Swept the destination layer for citation rot per the skill's step 5; found none to prune. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015QQtPSrTWwyKv5U4vpVTNZ
There was a problem hiding this comment.
1 issue found across 6 files (changes from recent commits).
Confidence score: 5/5
- In
dev/guidelines/backend/exceptions.md, theas excbinding in the “good” examples is unused, so copied snippets can trigger Ruff F841 and create confusion against nearby examples that do useexc; remove the unused binding (or use it consistently in logging) to keep the guidance copy-paste safe.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="dev/guidelines/backend/exceptions.md">
<violation number="1" location="dev/guidelines/backend/exceptions.md:123">
P3: Both examples bind `as exc` but never reference `exc`, which trips ruff F841 if copied, and contradicts the file's own `log.error(..., error=str(exc))` examples that do use it. Drop the unused binding so the ✅ Good example is a clean idiom to copy.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
|
|
||
| ```python | ||
| # ❌ Bad - a client aborting mid-request is routine; the traceback is non-actionable noise | ||
| except ClientDisconnect as exc: |
There was a problem hiding this comment.
P3: Both examples bind as exc but never reference exc, which trips ruff F841 if copied, and contradicts the file's own log.error(..., error=str(exc)) examples that do use it. Drop the unused binding so the ✅ Good example is a clean idiom to copy.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At dev/guidelines/backend/exceptions.md, line 123:
<comment>Both examples bind `as exc` but never reference `exc`, which trips ruff F841 if copied, and contradicts the file's own `log.error(..., error=str(exc))` examples that do use it. Drop the unused binding so the ✅ Good example is a clean idiom to copy.</comment>
<file context>
@@ -105,6 +105,32 @@ except Exception as exc: # noqa: BLE001
+
+```python
+# ❌ Bad - a client aborting mid-request is routine; the traceback is non-actionable noise
+except ClientDisconnect as exc:
+ log.exception("Exception ClientDisconnect in handler")
+
</file context>
| except ClientDisconnect as exc: | |
| except ClientDisconnect: |
…o stable (#10270) * docs(skills): bring the harvesting-review skill and its house style to stable Extracted from #10030 so the next harvest runs with the improved skill instead of waiting for the develop -> stable release train. Every file here is byte-identical to #10030's version, so the branches converge rather than drift. - .agents/skills/harvesting-review/SKILL.md: 'Refine, don't accrete' leads the skill and outranks its other rules (measure the target file against its size range, compress or split one at its limit, repoint every inbound reference on a move, cut what the new rule supersedes, report added/removed lines). Adds the per-run rot sweep that fixes stale citations and defect-snapshot notes in the same PR, and routes a lesson into the skill that owns its workflow. - dev/guidelines/documentation.md: the 'For Internal Docs' writing style the skill points at, plus the no-line-number and relative-measurement rules. The skill's house-style pointer would dangle without this. - .agents/commands/pre-ci.md: plain 'ruff check' CI-parity step, since the invoke tasks run 'ruff check --diff' and exit 0 on violations with no autofix. - .agents/skills/monitoring-pull-requests/SKILL.md: don't escalate from a stale 'commits behind' count. Deliberately not included, because they would not be correct on stable yet: the speckit-extract repoint (targets dev/guidelines/backend/exceptions.md, which only exists on develop), and the .agents/rules/* and creating-changelog-entries changes (their stable copies have diverged, and #10259 already edits them against stable). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: apply cubic's four findings Same fixes as on #10030 (757b34f), keeping every file byte-identical across the two branches. - the invoke-lint justification was factually wrong: main.lint and backend.ruff both run a plain 'ruff check', the only --diff is the formatter's. The real reason the whole-repo check matters is coverage, since CI lints everything outside the four dirs main.lint covers - the citation example named a develop-only module; now a generic placeholder - the report template's '(§6)' house-style pointer aimed at Report - the rot-sweep glob missed AGENTS.md files two levels deep Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Why
Reviewers kept raising the same things, and each lesson lived in a review thread and died there. This PR consolidates six
/harvesting-reviewpasses over PRs reviewed 2026-07-16 → 2026-08-07 into the internal-doc layer, so a future author (human or agent) follows the convention the first time. It also introduces the discipline the harvests themselves turned out to need: a harvest that only adds makes the layer worse, so every addition here is paid for with compression or pruning.Every lesson was reconstructed against the before/after code, verified against the current codebase, and checked against existing coverage before landing, per
.agents/skills/harvesting-review/.Closed in favor of this PR (their commits are cherry-picked here): #10098, #10145, #10157.
Docs only — no code, no generated files, no schema.
The conventions now in place
One row per lesson: the source PR whose review surfaced it, and where it now lives.
Backend
try/exceptis needed at all;# noqa: BLE001needs a named reason; inside a transaction a caught-and-returned failure commits (verified againstInfrahubDatabase.__aexit__)dev/guidelines/backend/exceptions.md(new, split frompython.md)T | Sequence[T]unions — takeSequence[T]and let callers wrap (a barestrsatisfiesSequence[str]and gets shredded)dev/guidelines/backend/python.mdtasks/*.pybackend imports stay function-local — and the exception covers a thin wrapper, not logic hosted intasks/dev/guidelines/backend/python.mdstartswithdev/guidelines/backend/asgi-middleware.md(new, split frompython.md)retry_db_transactionreplays the whole wrapped scope (onTransientErrororEntityNotFound): wrap only rollback-able scopes, skip underdb.is_transaction, mind nested retried callersdev/knowledge/backend/mutations.mdlimit/offsetto the baseQuery;insert_limit = Falsewithout an own LIMIT never finishes paging; auto-pagination needs a total-orderORDER BY; readcollect()columns withget_as_list_of_typedev/knowledge/backend/query-pattern.mdn.kindis concrete-only — generics exist as labels; type concrete-only query inputs aslist[NodeSchema]dev/knowledge/backend/database-schema.mddev/knowledge/backend/events.mdInfrahubBatchis concurrent, not ordered; the best-effort contract also covers a single inline side effect;add_tags()mid-run drops earlier tags (cross-linked where the guide teaches the pattern)dev/knowledge/backend/async-tasks.md,dev/guides/backend/creating-async-tasks.mdsave(); per-item try/collect intoMigrationResult.errors; batch by the memory-bounding unitdev/guides/backend/creating-migrations.md(now routed frombackend/AGENTS.md— it was loaded by nothing)Settingsfield must reach the hand-maintaineddevelopment/compose anchor, not just the generated onedev/guidelines/backend/checklist.mdConfigurationbackend/AGENTS.mdBackend testing
ast/inspect), never by instrumenting production codedev/guidelines/backend/testing.md,.agents/rules/testing-python.mddev/guidelines/backend/testing.mddev/guidelines/backend/testing.mddev/guidelines/backend/testing.mddev/knowledge/backend/testing.mdFrontend
vi.resetAllMocks), and URL state between tests in one filedev/guides/frontend/writing-component-tests.mddev/guides/frontend/writing-component-tests.mddev/guides/frontend/writing-unit-tests.mdMaplookup seeded from the array you index it with is still a type lie under!dev/guidelines/frontend/typescript.mddev/guidelines/frontend/page-architecture.mdComponent design and code style (
.agents/rules/— edits to existing rules, no new files)initialize()/reset()clears every derived cache.agents/rules/backend-component-design.md.agents/rules/code-doc-style.mdProcess and documentation
dev/specs/scaffolding on a trivial fix; a lint-suppression PR ships the suppression only and files the bug separatelydev/guidelines/git-workflow.md,dev/guidelines/repository-organization.mddev/guidelines/documentation.mdFor Internal Docsfile.py:linecitations in internal docs; measurements go in as relative comparisonsdev/guidelines/documentation.mdAGENTS.md+, never a tracker ID; the+orphan-prefix failure mode;housekeepingis not a catch-all — no user-facing effect means no fragment.agents/skills/creating-changelog-entries/SKILL.md,docs/docs/development/changelog.mdxinvoke lintrunsruff check --diff, blind to unfixable violations —/pre-cicarries the CI-parityruff checkstep.agents/commands/pre-ci.md, rootAGENTS.md.agents/skills/monitoring-pull-requests/SKILL.mddevelopment/development/grafana/AGENTS.md(new)docs/AGENTS.mdPruned in the same PR
Stale
PR #NNNN/Migrated in #NNNNcitations across 5 frontend docs (17 hits) andtemplates.md(4 hits, plus the renamed method the rot was hiding:_apply_template()→handle_object_template());typescript.md'suseMemodependency-array teaching, which contradictedreact.md's React-Compiler guidance — a reviewer had to ask which was right;schema-definitions.md's pointer to an issue closed 2026-07-20;query-pattern.md's five near-identical walkthroughs collapsed into one example plus an accessor table (520 → 459).The harvesting-review skill, final state (0.8.0)
Refine, don't accrete leads the skill and outranks its other rules: measure the target file against its size range first, compress or split a file at its limit (repointing every inbound reference, including
.agents/skills/.agents/commandsroutes), cut what the new rule supersedes, and report added/removed line counts — zero deletions is a finding about the harvest. Every run sweeps the destination layer (including.agents/rules) for citation rot, fixed defect-snapshots, and superseded narrow rules, and fixes every hit in the same PR — a punch list is not pruning. A lesson whose root cause is a fragile pattern becomes a rule steering away from the pattern, not a survival guide for it. A lesson owned by an existing skill (creating-changelog-entries,pre-ci, the org plugin'spruning-residues) is routed into that skill instead of paralleldev/prose.Also decided along the way
develop, deliberately (cubic suggestedstable, discussed with @polmichel):git-workflow.mdhas no docs-target-stable rule, the lessons were verified againstdevelop's code, and several describe modules that don't exist onstable. If internal-docs-to-stable should be policy, that's agit-workflow.mdrule to add first.stableretarget (diff-tree node sets fix: show changed nodes in diff tree when their parent is unchanged #10014, merge-recompute invariant fix(recompute): refresh a reader's derived values when its read peer is deleted #9845,get_query_arrows()scope uniqueness constraints to specific objects #10053-cluster,ComputedAttributedrift guard feat: separate user-facing schema (write/read) from internal model [INFP-234] #9814) — re-harvestable later.IPAddressattribute kind #10090, feat(frontend): allow users to customize the sorting of proposed changes list #10104 (bot findings retracted), refactor(core/query): type forwarded query constructor kwargs #10123, refactor(git): use SDK protocol classes for node kinds in tasks #10125, fix(frontend): give every GraphQL call its own request #10136, docs: add a performance tuning page for deployment settings #10114 (already covered by the verify-claims rule), Clone git repositories on their own default branch #10141, fix: skip computed attribute query triggers for kinds no field is read from #10154, fix(testcontainers): stop a cancelled performance run from leaking its compose stack #10149, test(scale): remove broken branch.diff_data call #10144, Serve frontend via FastAPI native app.frontend() #10099, fix: release the urql operation when a GraphQL fetch is aborted #10124, docs: add merge failure and recovery docs #10080, test(regeneration): pin the relationship-traversal narrowing limitation #10089, feat(schema): declare allow_prefix on IPHost attributes and publish it [INFP-551] #10081, IFC-1480: Validate optional and unique attribute parameters #7569, and a set of bare approvals.migrations/query/attribute_add.pymissing the documentedr.status ASCtiebreaker; develop's dashboards carrying 42 undefined-$datasourcereferences (Update Grafana dashboards: admission controller sections, panel fixes #10153 fixed them only onrelease-1.11);changelog/models.py'sset_value_previousbypassing the masking validator; feat(backend): add Redis Streams message bus driver #10133's broker-durability lessons parked until the Redis driver merges; thestable/developruffBLEdivergence.str/Sequencedoc section became the rule against the pattern, the extract skill's error-handling route repointed toexceptions.md,backend/AGENTS.md's list made contiguous, the retry-trigger wording completed, the test examples made reproducible and actually-isolating,vi.resetAllMocksoverclearAllMocks, and the Grafana regeneration command corrected.Context budget
+702/−338 over
develop(40 files, after mergingdevelopback in), and the shape matters more than the total: no new file in.agents/rules/(the only layer injected into every agent turn — three existing rules edited), the twopython.mdsplits load only on their trigger, and every harvest paid with deletions.dev/knowledge/backend/query-pattern.md## Internalssplit is the flagged next changedev/guidelines/backend/python.mddevelop-side additions re-grew it; the next split is its own changedev/guides/frontend/writing-component-tests.mddev/guidelines/backend/testing.mdHow to test
Docs only.
markdown-lint(docs/docs),validate-dev-guideline-links(lychee overdev/**,backend/**), andvalidate-documentation-style(Vale overdocs/) cover these paths in CI; relative links, section anchors, and code-fence balance checked locally across all 37 changed markdown files.🤖 Generated with Claude Code