Merge 'release-1.11' to 'develop' with resolved conflicts. - #10342
Conversation
…#9958) * docs(preferences): user-facing docs, changelog, and e2e tests (IFC-2737) Add the user-facing "Managing preferences" page under Deployment & Management > User Management & Security (single page, Web + GraphQL tabs): precedence (user > organisation default > browser), the date-format presets, setting personal preferences and organisation defaults, and the manage_global_preferences gate. Register it in the sidebar after "Managing API tokens". Add the missing changelog fragment for preference-driven date/time rendering (IFC-2721); the existing fragments only covered setting preferences. Add Python e2e coverage: personal round-trip + clear-override, global-default inheritance, and the permission gate. Introduce a shared select_combobox_option helper for the preference forms. Facts grounded in the code on this branch (literal UI labels, the "re-select to clear" reset, the InfrahubSetPreferences/InfrahubEffectivePreferences surface). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(preferences): follow the global-preferences move to the account menu The global preferences page moved from a profile tab to a standalone /global-preferences route behind a permission-gated account-menu item; the docs step and both e2e tests now walk that flow. Also de-flake the tests that never went green: assert the URL with a regex (a string pattern resolves against the base URL and the glob never matched) and open the source tooltip via focus, which React Aria shows immediately, instead of the delay-prone hover. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(e2e): drop work-item IDs from the preference test docstrings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(e2e): expand the unauthorized accordion before asserting the permission message The UnauthorizedScreen renders the detailed message inside a collapsed Accordion, so the text is not in the DOM until the title is clicked. Assert the visible title first, expand it, then check the message. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(e2e): deduplicate the success toast between the two preference saves The second 'Preferences updated' check could match the first save's still-visible toast, letting the reload race (and cancel) the in-flight clear mutation. Wait for the first toast to dismiss, and assert the trigger shows the inherited placeholder before saving the clear. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: preference improvement * remove known limitation --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Baptiste <girard.baptiste@hotmail.fr> Co-authored-by: Saltaferis Dimitrios <d.saltaferis@gmail.com>
…mespace/inheritance update (#10277) * refactor(schema): derive vertex labels from a single definition Node.get_labels() re-implemented the label rules inline rather than using the schema's own get_labels(), and the two had drifted. TemplateSchema.get_labels() appended CoreObjectTemplate on top of an inherit_from that already contained it, so it returned that label twice, and it claimed the label for component subtemplates, which are built on CoreObjectComponentTemplate instead. ProfileSchema.get_labels() had the same defect with CoreProfile. Neither append could ever add a missing label, since the generators always place the base kind in inherit_from. Both methods were unreachable: the labels written at creation came only from the inline copy in Node, so the drift went unnoticed. Dropping the appends, giving BaseNodeSchema the bare-kind default and delegating from Node leaves the labels written for every schema type unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(migrations): relabel generated Profile/Template vertices on a kind update The schema diff reports only nodes and generics, so the Profile{Kind} and Template{Kind} schemas generated from a node never produced a migration of their own. A kind update relabelled the node's own vertices and left theirs untouched: a template kept a stale label set when its kind gained or lost a generic, and a rename left both generated populations answering to kinds that no longer resolved. schema_apply_migrations already holds the previous and the new SchemaBranch, so it now resolves the generated schemas for the kind being migrated and passes them to the migration, which folds them into a single NodeDuplicateQuery run. Reading the real generated schemas keeps the label sets sourced from the generators rather than restated, which matters because a template's labels depend on schema-wide state a single node schema cannot supply. Matching moves from a conjunction of the previous label set to a disjunction of the kinds being migrated, with the target looked up per vertex by kind. A vertex whose label set has already drifted is therefore repaired rather than skipped, and one that merely carries a matched label without being of a mapped kind is ignored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * add changelog * Correct capitalization in changelog entry * fix metadata test it was actually broken since creation and the latest changes to NodeDuplicateQuery just revealed it --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The medium and medium-data presets both listed a 24G Neo4j heap against a 32 GB total memory budget, leaving no room for the 4G page cache and the rest of the stack. Bring both rows down to 16G. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Merge stable into release-1.11
…10254) * fix: close branch-owned edges when renaming an attribute on a branch The rename ended the old attribute by creating a deleted edge beside it. That is the only option for an edge owned by the default branch, which a branch cannot modify, but it was applied to every edge — so a node created on the branch kept the old attribute active and deleted at the same time. Rebasing then re-stamped both edges to the rebase time, leaving the resolution of "the latest edge for this attribute" a tie between them. The rename dispatched again after the rebase could therefore resolve the still-active edge, rename a second time, and leave the node with two copies of the renamed attribute. Edges the branch owns are now closed with a `to` time, the way the default branch already handled them, and only edges owned by another branch are shadowed. The per-edge-type query rendering is gone with it: direction now comes from the stored edge rather than from the schema's declared direction, so the ten generated UNION branches collapse into four subqueries keyed on direction, and the node match uses a label alternation instead of a three-way UNION. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * rewrite changelog * fix: keep the rename node-selection overridable and cover the rerun Inlining the node match into query_init made Migration012RenameTypeAttributeData's render_match() override dead code, dropping the guard that skips nodes already holding the new attribute name. The match moves back behind render_match() so a subclass can still narrow it. The regression test now re-executes the migration and asserts nothing further is created, matching its sibling tests. That is the pass the rebase makes in practice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add a "Format schema files" section to the Create and load schema page: default key-ordering behaviour, --diff / --check, and the opt-in --strip-defaults / --sort-by-order-weight / --backfill-order-weight flags. DO NOT MERGE until an infrahub-sdk release that ships `infrahubctl schema format` is published (feature merged in opsmill/infrahub-sdk-python#1189). Merging earlier would document a command absent from the released CLI. Co-authored-by: Alex Gittings <agitting96@gmail.com>
docs: rework IPAM documentation
`infrahub tasks flush stale-runs` only reset flow runs stuck in RUNNING, so runs picked up by a worker that died before the flow started stayed PENDING forever. Prefect's start_time filter falls back to expected_start_time, so never-started runs are aged correctly by the existing cutoff. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Playwright's `name` option substring-matches by default, and the branch selector renders the current branch name on every page. A base36 random suffix can therefore spell a word the suites locate by, making that locator match two elements and killing the test with a strict-mode violation. That is what took down object-relationships.spec.ts on #10287: the branch was object-relationshipsaveyj8q5g6r, where the prefix's trailing "s" and a suffix starting "ave" spell "save", so getByRole("button", { name: "Save" }) matched both the Save button and the branch selector. It presents as an unrelated test failing for no reason and passing on re-run, which is why it kept being written off as noise. Switch the TypeScript generator to hex, which the pytest helper already used. Measured over 2M generations against the names the suites locate by: base36 produces 168 collisions (about 1 in 12k), hex produces 0. It is not only "save" -- the sample also threw up branchesmainzvsrjh8, ...u6vl6xpathb and ...t6nname02n, colliding with "main", "path" and "name". None of the 436 distinct locator names across both suites is spellable in hex, so this closes the class rather than the one instance. Both helpers now carry the constraint so a wider alphabet does not creep back in. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit 4cf2b30)
The fix rests on the branch suffix staying hexadecimal, but that was
guarded only by the comments added alongside it. Prose already failed once
here: these two helpers silently diverged despite the Python one
documenting itself as a port of the TypeScript one, which is how base36
survived long enough to spell "save" in a branch name.
Assert the suffix matches [0-9a-f]{12} on both sides. Verified by
regression, not just by passing: reverting the TypeScript helper to
Math.random().toString(36) fails both of its cases, and perturbing the
Python helper's output fails its.
The Python test needs a shard marker because CI selects with
-m shard_<name> and an unmarked test is deselected in every shard. It also
inherits the suite's compose stack, since pytest-base-url's autouse
_verify_url pulls in base_url; that costs nothing in CI where the stack is
already running, and there is nowhere else the helper is importable from.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit ecb56d0)
Bump the prefect-redis pin from 0.2.12 to the latest release, 0.2.14. Infrahub only consumes it through the Prefect server env vars (PREFECT_MESSAGING_BROKER/CACHE, PREFECT_SERVER_EVENTS_CAUSAL_ORDERING, PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE), so the change is confined to the Prefect server side. - pyproject.toml: prefect-redis==0.2.12 -> ==0.2.14 - uv.lock: regenerated with uv 0.11.8 (CI's version); prefect 3.7.5 and redis 6.0.0 unchanged, no other package moved except a pendulum marker refresh that was already stale in the lock Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…igration (#10298) NodeRelationshipRemoveMigration overrides SchemaMigration.execute to open its own transaction rather than delegating to the base, which discarded the retry_db_transaction decorator applied to the base method. A transient error inside that transaction failed the migration instead of being replayed. Document the rule where migrations are authored, since an override silently dropping an inherited decorator is easy to repeat. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The stable merge collided on `infrahub tasks flush stale-runs`: release-1.11 moved the purge behind `FlowRunRetention`, while stable widened the state filter to include PENDING via `STALE_FLOW_RUN_STATES`. Keep both — stable's call site alone would not import, since release-1.11 dropped `PrefectTask`. `FlowRunRetention.purge` filters on the same `start_time before cutoff`, so never-started runs still age off Prefect's `expected_start_time` fallback as the original fix intended. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adjacency conflict in `requires-dist`: stable bumped prefect-redis to 0.2.14 and release-1.11's prometheus-client pin sits on the following line. Keep both entries; `uv lock --check` passes against pyproject.toml. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…table test: generate hex branch names so they cannot spell locator words (backport #10291)
Stable to release 1.11
* fix(backend): omit task related nodes with unresolvable kind A Prefect flow run can be tagged with a related node ID that no longer resolves to an active node (deleted definition, stale tag). The kind then stays None and the non-nullable TaskRelatedNode.kind GraphQL field crashed the resolver, breaking the Tasks page. Filter such entries out of the related-nodes accessors so the task is returned without the unrenderable node instead of erroring. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(backend): assert resolvable related node survives kind filtering Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ease-1-11 # Conflicts: # backend/infrahub/task_manager/event/models.py
`stable` fixed `RelatedNodesInfo.get_related_nodes` in `task_manager/models.py` (#9664), filtering out related nodes whose kind never resolved so the non-nullable `TaskRelatedNode.kind` GraphQL field stops crashing the Tasks page. `release-1.11` split that flat module into `task_manager/event/` and `task_manager/flow_run/`. Git's rename detection followed the split to `event/models.py` and reported the conflict there, but `RelatedNodesInfo` actually landed in `flow_run/models.py` — every consumer (`flow_run/enrichment.py`, `reader.py`, `service.py`) imports it from `.models` there, and `event/models.py` does not reference it at all. Drop the incoming block from `event/models.py` (restoring it byte-for-byte to the `release-1.11` version) and apply the two-hunk fix to `flow_run/models.py`, where the target methods were still identical to the merge-base so the patch applies with exact context.
`release-1.11` added `TestRelatedNodesInfo` in #9810; `stable` added the kind filter in #9664. Neither side touched the other's file, so the merge was clean and five of those tests then failed. They assert registration mechanics (`add_node`, `add_nodes`, cross-flow sharing, dedup) but observe through `get_related_nodes`, which now omits nodes whose kind never resolved. `add_node` leaves `kind=None`, so each saw an empty list. Set a kind on the registered nodes, following the idiom already used by `test_get_related_nodes_as_dict` in this file. The assertions are otherwise untouched and no longer depend on whether the accessor filters. Add two tests for the filter's contract, which previously had only component-level coverage: - `test_get_related_nodes_omits_unresolvable_kind` pins the fix across all three accessors. Verified it fails when the filter is reverted. - `test_get_unique_related_node_ids_keeps_unresolved_kind` guards the other direction: `flow_run/enrichment.py` resolves kinds from that list, so filtering it would leave every kind permanently unresolved.
Merge stable into release-1.11
The default test stack carried no com.github.* labels at all, and the cluster stack only had them on database-core2/core3, so containers left behind on the runners could not be traced back to the run that spawned them. com.github.job falls back to GITHUB_JOB because only the three E2E workflow jobs export JOB_NAME, while the integration, functional, docker-integration, benchmark and version-upgrade jobs — the ones that actually build testcontainers stacks — do not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Merge stable into release-1.11
…10250) * refactor: consolidate graph-integrity checks behind verify_graph() Six overlapping graph-integrity checks were split across infrahub.database.validation and tests.helpers.db_validation, each called individually, so a suite had to know all six existed and new suites routinely covered only a subset. They now live in one module behind a single entry point: verify_graph() raises GraphValidationError listing every violation found rather than stopping at the first failing check, and collect_graph_violations() returns them for tests that assert a damaged state. The individual checks are private. An optional kinds filter narrows every check at its MATCH anchor, so a suite can scope a run to the kinds it touches; checks anchored on Attribute or Relationship vertices resolve the label through the Node the vertex hangs off. The duplicate-attributes check no longer takes a branch. It derives the branch set from the graph, so one call covers every branch that touched a node instead of only the one the caller passed, and it prunes to nodes actually holding two same-named Attribute vertices so a healthy graph does almost no work. It also groups per vertex rather than per uuid, since a kind update leaves several vertices sharing one uuid. The three checks that resolve default-branch visibility now use branched_from rather than created_at as the fork point, matching the production read path. A rebased branch does see default-branch edges written after its creation, so created_at under-included them and the checks could miss a violation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: correct the graph checks surfaced by the consolidated verify_graph() Running every check at every call site exposed gaps in the checks themselves. An empty kinds list rendered an empty label expression, so `MATCH (n:)` made every check fail rather than run unfiltered. It now means no filter, as callers expect. The orphaned-edge and duplicate-attribute checks selected a default-branch edge as visible from a branch, then required it to be open, so an edge closed after the branch forked counted as inactive even though the branch still reads it. Both now allow the same `to > branched_from` exception the relationship-edge-count check already applied. The edges-after-delete check compared a branch's edges against the default branch's delete time. A rebase re-stamps every open edge to the fork point, including the ones recording the branch's own deletion, so those edges looked like writes to an already deleted node. An edge on another branch is now only flagged when it was written strictly after the fork point. The orphaned-edge check also carried a deletion timestamp through four projections without ever reading it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: rewrite the orphaned-edge check around the delete that caused it The check resolved, per field and peer, the latest second-level edge visible from the branch that deleted the field, then asked whether it was active. Reading a default branch edge through a branch's fork point made a value the default branch had since replaced look live, so an ordinary update after a branch deleted a field was reported as an orphan. It now starts from the delete itself. Every branch holding a deleted or closed first-level edge for a node and field is a candidate; the edges that branch holds decide whether it deleted the field at all, and the last of them to close is when the field went away. A delete writes the field's edges at that same moment, so what is left open, or carries a later time, is what did not follow the delete. Grouping on the node uuid rather than the vertex replaces the guard for kind updates: those copy the node vertex, and both copies point at the same field, so an edge left open on either of them means the field is still in use. Edges on a branch that forked after the delete are checked too, since that branch inherits it. A rebase re-stamps the edges it carries to the fork point, so only what comes after that was written with the delete in view. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: scope an inherited delete to the branches that can see it A delete only reaches a branch that was cut after it from the branch it happened on. Branches are cut from the default branch, so a delete on one branch is invisible to every other, but the check treated any branch forked later as having inherited it and reported that branch's own writes as orphaned. Two sibling branches, one deleting a field and the other adding to it, were enough to trigger it. The violation also named the branch that did the deleting rather than the branch holding the edge, which pointed at the wrong place to go looking. It now names where the edge lives, and where the delete came from when they differ. The duplicate-attribute check now counts a default-branch edge that closed after a branch forked, which the branch still reads as open. Unlike the orphaned-edge check this resolves one edge per field vertex, so a value the default branch replaced cannot be counted twice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix migration --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
add v1.11.0 release notes
There was a problem hiding this comment.
7 issues found across 127 files
Confidence score: 3/5
backend/infrahub/database/validation.pydoes not exclude deleted or closed relationship versions from the duplicate-path check, so valid attribute or edge updates may be rejected as duplicates — add optional matching and active-edge filters to the Cypher queries.docs/docs/release-notes/infrahub/release-1_11_0.mdxclaims its Breaking changes summary is complete while omitting documented changes, anddocs/sidebars.tsrenames IPAM URLs without updatingdocs/redirects-pending/ipam.yml; reconcile the release content and redirect tracking.docs/docs/ipam/build-your-ipam-schema.mdxreferences an undefined or unloadedServiceGeneric, whiledev/guides/backend/creating-migrations.mdcites a decorator example with the wrong transaction name; align both examples with the actual definitions and implementation.tests/e2e/preferences/test_global_preferences.pydoes not verify that the inherited value is correct, and.vale/styles/spelling-exceptions.txtcontains a duplicatenetmaskentry; strengthen the value assertion and remove the duplicate exception.
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=".vale/styles/spelling-exceptions.txt">
<violation number="1" location=".vale/styles/spelling-exceptions.txt:164">
P3: Custom agent: **Flag AI Slop and Fabricated Changes**
The added `netmask` entry duplicates the existing entry after `Neo4j`. Remove one of the two entries to keep the spelling exception list unique.</violation>
</file>
<file name="backend/infrahub/database/validation.py">
<violation number="1" location="backend/infrahub/database/validation.py:189">
P2: Custom agent: **Check Cypher queries that update attributes/edges for optional matching and active-edge checks**
The duplicate-path check includes deleted or closed relationship versions because it never filters `e` to the active, `to IS NULL` edge. Filter historical edges before grouping so `verify_graph()` reports only duplicate current paths.</violation>
</file>
<file name="dev/guides/backend/creating-migrations.md">
<violation number="1" location="dev/guides/backend/creating-migrations.md:73">
P3: The doc tells the reader to reapply `@retry_db_transaction(name="schema_migration")` and cites `node_relationship_remove.py` as the worked example, but that file's decorator actually uses `name="relationship_remove_schema_migration"` (node_relationship_remove.py:260). Align the doc with the cited example (or drop the explicit name) so the retry metric label matches the code it points to, instead of colliding with the base class's `schema_migration` retry counter.</violation>
</file>
<file name="docs/sidebars.ts">
<violation number="1" location="docs/sidebars.ts:164">
P2: The IPAM sidebar entries are renamed from released page URLs to new ones, but the redirect-tracking document docs/redirects-pending/ipam.yml still lists the old paths (ip-namespaces, building-your-schema, automate-with-resource-manager) as the intended structure. Per the docs AGENTS.md binding rule, renamed/deleted published pages need a redirect entry; update redirects-pending/ipam.yml (and the stale reference in docs/release-notes/infrahub/docs-restructure.mdx) to map the old URLs to the new build-your-ipam-schema / use-namespaces / allocate-ips-and-prefixes pages so the old published URLs keep resolving.</violation>
</file>
<file name="tests/e2e/preferences/test_global_preferences.py">
<violation number="1" location="tests/e2e/preferences/test_global_preferences.py:66">
P3: The test verifies only that an organisation default exists and its source hint appears, not that the correct value is inherited. The tooltip text is `From the organisation default: <value>` and the substring assertion passes for any value, so a regression that inherits the wrong format would not be caught. Assert that the inherited value equals GLOBAL_DATE_FORMAT on the read-only page (and optionally that the ISO browser default is not shown) to give the test its stated purpose.</violation>
</file>
<file name="docs/docs/release-notes/infrahub/release-1_11_0.mdx">
<violation number="1" location="docs/docs/release-notes/infrahub/release-1_11_0.mdx:46">
P2: The "Before upgrading ▸ Breaking changes" summary presents itself as complete ("The full Breaking changes section below explains the impact of each"), and its matching "## Breaking changes" section covers only four items. Several other upgrades-blocking changes exist only in the Full changelog and are absent from both: the GraphQL `extensions.code` string migration (line 488), the restricted_namespaces inheritance restriction which the notes themselves say makes the upgrade fail to complete if violated (line 506), the reserved `node_metadata` name (line 474), and `BuiltinIPPrefix.resource_pool` now returning `CoreIPPool` (line 583). An operator reading the summary would miss required pre-upgrade actions for these. Either add the missing changes to the upfront summary or soften the completeness claim.</violation>
</file>
<file name="docs/docs/ipam/build-your-ipam-schema.mdx">
<violation number="1" location="docs/docs/ipam/build-your-ipam-schema.mdx:159">
P2: The extensions example pairs `IpamIPPrefix` with `peer: ServiceGeneric`, but nothing in this guide defines or loads `ServiceGeneric` — the first example's node is `Service` in the `Customer` namespace (`CustomerService`). Copying the block verbatim will fail schema load. Point the peer at the `CustomerService` node defined in the guide (or instruct the reader to load the Service Catalog schema that provides `ServiceGeneric`).</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
Re-trigger cubic
| async def _check_duplicate_paths(db: InfrahubDatabase, kinds: list[str] | None) -> list[GraphViolation]: | ||
| """Verify that no duplicate paths exist at the database level.""" | ||
| query = """ | ||
| MATCH path = (p)-[e]->(q) |
There was a problem hiding this comment.
P2: Custom agent: Check Cypher queries that update attributes/edges for optional matching and active-edge checks
The duplicate-path check includes deleted or closed relationship versions because it never filters e to the active, to IS NULL edge. Filter historical edges before grouping so verify_graph() reports only duplicate current paths.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/infrahub/database/validation.py, line 189:
<comment>The duplicate-path check includes deleted or closed relationship versions because it never filters `e` to the active, `to IS NULL` edge. Filter historical edges before grouping so `verify_graph()` reports only duplicate current paths.</comment>
<file context>
@@ -98,10 +171,322 @@ async def verify_no_edges_added_after_node_delete(db: InfrahubDatabase) -> None:
+async def _check_duplicate_paths(db: InfrahubDatabase, kinds: list[str] | None) -> list[GraphViolation]:
+ """Verify that no duplicate paths exist at the database level."""
+ query = """
+MATCH path = (p)-[e]->(q)
+WHERE %(kind_filter)s
+WITH
</file context>
| 'ipam/ip-namespaces', | ||
| 'ipam/building-your-schema', | ||
| 'ipam/automate-with-resource-manager', | ||
| 'ipam/build-your-ipam-schema', |
There was a problem hiding this comment.
P2: The IPAM sidebar entries are renamed from released page URLs to new ones, but the redirect-tracking document docs/redirects-pending/ipam.yml still lists the old paths (ip-namespaces, building-your-schema, automate-with-resource-manager) as the intended structure. Per the docs AGENTS.md binding rule, renamed/deleted published pages need a redirect entry; update redirects-pending/ipam.yml (and the stale reference in docs/release-notes/infrahub/docs-restructure.mdx) to map the old URLs to the new build-your-ipam-schema / use-namespaces / allocate-ips-and-prefixes pages so the old published URLs keep resolving.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/sidebars.ts, line 164:
<comment>The IPAM sidebar entries are renamed from released page URLs to new ones, but the redirect-tracking document docs/redirects-pending/ipam.yml still lists the old paths (ip-namespaces, building-your-schema, automate-with-resource-manager) as the intended structure. Per the docs AGENTS.md binding rule, renamed/deleted published pages need a redirect entry; update redirects-pending/ipam.yml (and the stale reference in docs/release-notes/infrahub/docs-restructure.mdx) to map the old URLs to the new build-your-ipam-schema / use-namespaces / allocate-ips-and-prefixes pages so the old published URLs keep resolving.</comment>
<file context>
@@ -161,9 +161,11 @@ const sidebars: SidebarsConfig = {
- 'ipam/ip-namespaces',
- 'ipam/building-your-schema',
- 'ipam/automate-with-resource-manager',
+ 'ipam/build-your-ipam-schema',
+ 'ipam/use-namespaces',
+ 'ipam/allocate-ips-and-prefixes',
</file context>
| > - **Generated OpenAPI clients:** Code that depends on the previous component schema names in `openapi.json` needs to be updated and regenerated. | ||
| > - **API backpressure:** Under sustained overload Infrahub now rejects requests with `429 Too Many Requests` and a `Retry-After` header. The web UI and the Python SDK handle this for you; a custom integration that calls the API directly is expected to handle it itself. | ||
| > | ||
| > The full Breaking changes section below explains the impact of each and the action to take. |
There was a problem hiding this comment.
P2: The "Before upgrading ▸ Breaking changes" summary presents itself as complete ("The full Breaking changes section below explains the impact of each"), and its matching "## Breaking changes" section covers only four items. Several other upgrades-blocking changes exist only in the Full changelog and are absent from both: the GraphQL extensions.code string migration (line 488), the restricted_namespaces inheritance restriction which the notes themselves say makes the upgrade fail to complete if violated (line 506), the reserved node_metadata name (line 474), and BuiltinIPPrefix.resource_pool now returning CoreIPPool (line 583). An operator reading the summary would miss required pre-upgrade actions for these. Either add the missing changes to the upfront summary or soften the completeness claim.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/docs/release-notes/infrahub/release-1_11_0.mdx, line 46:
<comment>The "Before upgrading ▸ Breaking changes" summary presents itself as complete ("The full Breaking changes section below explains the impact of each"), and its matching "## Breaking changes" section covers only four items. Several other upgrades-blocking changes exist only in the Full changelog and are absent from both: the GraphQL `extensions.code` string migration (line 488), the restricted_namespaces inheritance restriction which the notes themselves say makes the upgrade fail to complete if violated (line 506), the reserved `node_metadata` name (line 474), and `BuiltinIPPrefix.resource_pool` now returning `CoreIPPool` (line 583). An operator reading the summary would miss required pre-upgrade actions for these. Either add the missing changes to the upfront summary or soften the completeness claim.</comment>
<file context>
@@ -0,0 +1,637 @@
+> - **Generated OpenAPI clients:** Code that depends on the previous component schema names in `openapi.json` needs to be updated and regenerated.
+> - **API backpressure:** Under sustained overload Infrahub now rejects requests with `429 Too Many Requests` and a `Retry-After` header. The web UI and the Python SDK handle this for you; a custom integration that calls the API directly is expected to handle it itself.
+>
+> The full Breaking changes section below explains the impact of each and the action to take.
+
+### Upgrade preparation
</file context>
| - kind: IpamIPPrefix | ||
| relationships: | ||
| - name: service | ||
| peer: ServiceGeneric |
There was a problem hiding this comment.
P2: The extensions example pairs IpamIPPrefix with peer: ServiceGeneric, but nothing in this guide defines or loads ServiceGeneric — the first example's node is Service in the Customer namespace (CustomerService). Copying the block verbatim will fail schema load. Point the peer at the CustomerService node defined in the guide (or instruct the reader to load the Service Catalog schema that provides ServiceGeneric).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/docs/ipam/build-your-ipam-schema.mdx, line 159:
<comment>The extensions example pairs `IpamIPPrefix` with `peer: ServiceGeneric`, but nothing in this guide defines or loads `ServiceGeneric` — the first example's node is `Service` in the `Customer` namespace (`CustomerService`). Copying the block verbatim will fail schema load. Point the peer at the `CustomerService` node defined in the guide (or instruct the reader to load the Service Catalog schema that provides `ServiceGeneric`).</comment>
<file context>
@@ -0,0 +1,169 @@
+ - kind: IpamIPPrefix
+ relationships:
+ - name: service
+ peer: ServiceGeneric
+ cardinality: one
+ direction: outbound
</file context>
| peer: ServiceGeneric | |
| peer: CustomerService |
| namespace | ||
| namespaces | ||
| nats | ||
| netmask |
There was a problem hiding this comment.
P3: Custom agent: Flag AI Slop and Fabricated Changes
The added netmask entry duplicates the existing entry after Neo4j. Remove one of the two entries to keep the spelling exception list unique.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .vale/styles/spelling-exceptions.txt, line 164:
<comment>The added `netmask` entry duplicates the existing entry after `Neo4j`. Remove one of the two entries to keep the spelling exception list unique.</comment>
<file context>
@@ -153,13 +153,15 @@ menu_placement
namespace
namespaces
nats
+netmask
Nautobot
Neo4j
</file context>
|
|
||
| **Transient database errors.** `SchemaMigration` and `GraphMigration` own their transaction and carry `retry_db_transaction`, so a transient error (a deadlock, or an entity a concurrent migration removed) is replayed on a fresh transaction with backoff and jitter instead of failing the migration; their inner query loops let those errors propagate to the transaction owner. This matters when migrations of the same kind run concurrently (schema path migrations execute as a batch). The catch-all `except` shown above belongs to `ArbitraryMigration`/`execute` overrides that run serially during upgrade and record every error as a failed `MigrationResult`; if you override `execute` to own a transaction on a concurrent path, add `retry_db_transaction` and do not catch retriable errors inside the transaction. See [Database Schema — Transaction Retry](../../knowledge/backend/database-schema.md#transaction-retry). | ||
|
|
||
| **Overriding `execute` discards the decorator.** A `SchemaMigration` subclass that overrides `execute` to open its own transaction must reapply `@retry_db_transaction(name="schema_migration")` — `node_relationship_remove.py` is the worked example. A subclass that only guards a condition and then delegates to `super().execute(...)` is already covered by the base and must not add it again, or the two retries nest. |
There was a problem hiding this comment.
P3: The doc tells the reader to reapply @retry_db_transaction(name="schema_migration") and cites node_relationship_remove.py as the worked example, but that file's decorator actually uses name="relationship_remove_schema_migration" (node_relationship_remove.py:260). Align the doc with the cited example (or drop the explicit name) so the retry metric label matches the code it points to, instead of colliding with the base class's schema_migration retry counter.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At dev/guides/backend/creating-migrations.md, line 73:
<comment>The doc tells the reader to reapply `@retry_db_transaction(name="schema_migration")` and cites `node_relationship_remove.py` as the worked example, but that file's decorator actually uses `name="relationship_remove_schema_migration"` (node_relationship_remove.py:260). Align the doc with the cited example (or drop the explicit name) so the retry metric label matches the code it points to, instead of colliding with the base class's `schema_migration` retry counter.</comment>
<file context>
@@ -68,6 +70,8 @@ Set `minimum_version` to the current `GRAPH_VERSION` (the migration runs when up
**Transient database errors.** `SchemaMigration` and `GraphMigration` own their transaction and carry `retry_db_transaction`, so a transient error (a deadlock, or an entity a concurrent migration removed) is replayed on a fresh transaction with backoff and jitter instead of failing the migration; their inner query loops let those errors propagate to the transaction owner. This matters when migrations of the same kind run concurrently (schema path migrations execute as a batch). The catch-all `except` shown above belongs to `ArbitraryMigration`/`execute` overrides that run serially during upgrade and record every error as a failed `MigrationResult`; if you override `execute` to own a transaction on a concurrent path, add `retry_db_transaction` and do not catch retriable errors inside the transaction. See [Database Schema — Transaction Retry](../../knowledge/backend/database-schema.md#transaction-retry).
+**Overriding `execute` discards the decorator.** A `SchemaMigration` subclass that overrides `execute` to open its own transaction must reapply `@retry_db_transaction(name="schema_migration")` — `node_relationship_remove.py` is the worked example. A subclass that only guards a condition and then delegates to `super().execute(...)` is already covered by the base and must not add it again, or the two retries nest.
+
### Step 2: Bump `GRAPH_VERSION`
</file context>
| **Overriding `execute` discards the decorator.** A `SchemaMigration` subclass that overrides `execute` to open its own transaction must reapply `@retry_db_transaction(name="schema_migration")` — `node_relationship_remove.py` is the worked example. A subclass that only guards a condition and then delegates to `super().execute(...)` is already covered by the base and must not add it again, or the two retries nest. | |
| **Overriding `execute` discards the decorator.** A `SchemaMigration` subclass that overrides `execute` to open its own transaction must reapply `@retry_db_transaction` with a migration-specific name — `node_relationship_remove.py` reapplies it as `@retry_db_transaction(name="relationship_remove_schema_migration")` and is the worked example. A subclass that only guards a condition and then delegates to `super().execute(...)` is already covered by the base and must not add it again, or the two retries nest. |
| # focus, while hover goes through the warm-up delay — the deterministic | ||
| # option for CI. | ||
| await read_only_page.get_by_role("button", name="Where this value comes from").first.focus() | ||
| await expect(read_only_page.get_by_text("From the organisation default")).to_be_visible() |
There was a problem hiding this comment.
P3: The test verifies only that an organisation default exists and its source hint appears, not that the correct value is inherited. The tooltip text is From the organisation default: <value> and the substring assertion passes for any value, so a regression that inherits the wrong format would not be caught. Assert that the inherited value equals GLOBAL_DATE_FORMAT on the read-only page (and optionally that the ISO browser default is not shown) to give the test its stated purpose.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/e2e/preferences/test_global_preferences.py, line 66:
<comment>The test verifies only that an organisation default exists and its source hint appears, not that the correct value is inherited. The tooltip text is `From the organisation default: <value>` and the substring assertion passes for any value, so a regression that inherits the wrong format would not be caught. Assert that the inherited value equals GLOBAL_DATE_FORMAT on the read-only page (and optionally that the ISO browser default is not shown) to give the test its stated purpose.</comment>
<file context>
@@ -0,0 +1,66 @@
+ # focus, while hover goes through the warm-up delay — the deterministic
+ # option for CI.
+ await read_only_page.get_by_role("button", name="Where this value comes from").first.focus()
+ await expect(read_only_page.get_by_text("From the organisation default")).to_be_visible()
</file context>
Why
Bring latest changes from
release-1.11todevelop.Replaces #10236
What changed
The signature of AttributeRenameQuery.query_init changed
**kwargs: dict[str, Any]->**kwargs: Any, and then two removed methods above this one had to be deleted.