Skip to content

Merge stable into release-1.11 - #10078

Merged
pa-lem merged 9 commits into
release-1.11from
stable
Jul 31, 2026
Merged

Merge stable into release-1.11#10078
pa-lem merged 9 commits into
release-1.11from
stable

Conversation

@infrahub-github-bot-app

@infrahub-github-bot-app infrahub-github-bot-app Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Merging stable into release-1.11 after merging pull request #10071.


Summary by cubic

Backports stable fixes into release-1.11: relationship selectors honor common_parent, git sync skips merged/read‑only branches, Jinja2 computed attributes reading number pools render after allocation, and GraphQL id‑only single‑relationship queries skip peer hydration for faster responses. Docs add local evaluation sizing, clarify Neo4j Community single‑core behavior, link hardware requirements from the Community install page, and polish the 1.8.0/1.9.0 release notes for voice, clarity, and “Learn more” links; CI now dispatches releases to opsmill/infrahub-demo-sp to run the demo’s integration tests.

  • New Features

    • GraphQL: for cardinality‑one relationships that request only id, return the preloaded peer id (and kind) without hydrating the peer; supports generic peers and falls back when other fields/metadata are requested.
  • Bug Fixes

    • Forms: relationship selectors filter peers by common_parent (IFC-1646). Hides redundant parent pickers, keeps the filter on UUID searches, clears selections when the parent changes, pre-fills the inline “Add new” form with the chosen parent, and disables the tree explorer when the filter must be enforced.
    • Backend: git repository sync ignores branches whose Infrahub branch is in a terminal status (merged/deleting), so other branches continue syncing.
    • Backend: Jinja2 computed attributes that reference number pool values are deferred until the pool allocates; dependent macros are deferred too, and mixed templates render fully after allocation (covered on GraphQL create). Fixes bug: Jinja2 Computed Attribute Error #7836.

Written for commit 913a48d. Summary will update on new commits.

Review in cubic

pa-lem and others added 3 commits July 28, 2026 16:36
Relationship selectors in object forms now honor the `common_parent` schema
property: options are filtered to peers that share the same parent as the value
picked for the referenced relationship in the same form, instead of listing
every peer.

- Add useCommonParentFilter hook: watches the sibling common_parent field and
  derives a single-hop `<X>__ids` filter (plus a matching RelationshipInput
  parent shape).
- Apply across the many, node, generic, and hierarchical relationship fields.
- Hide the manual parent picker on cardinality-one fields when common_parent is
  set, since the parent is then driven by the sibling field.

Keep the selection consistent with the filter so it can't be bypassed:
- Clear the current selection when the chosen parent changes (a peer valid under
  the old parent no longer satisfies the constraint).
- Pre-fill the inline "Add new" create form with the chosen parent, so a peer
  created there satisfies the constraint instead of being an escape hatch.
- Keep the filter applied on UUID searches (opt-in), and drop the hierarchical
  "Explore" tree tab, which browses a different axis and can't honor the filter.

Fixes IFC-1646.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix: skip merged branches during git repository sync

A git branch mapping to a merged (read-only) Infrahub branch caused
collect_pending_imports to issue a CoreRepositoryUpdate, which the graph
rejects for merged branches. The unhandled error aborted the entire sync
flow on every cron cycle, so no branches or repositories synced at all.

Branches in a terminal status are now skipped during collection, letting
the remaining branches and repositories sync as normal.

Also:
- Add a regression test covering the merged-branch case.
- Stub sdk.branch.all() in the git conftest, shared by the sync tests and
  the lock-scope test. The skip introduces a branch.all() call on the
  sync path, which the dummy SDK requester answers with an empty payload
  and raises KeyError: 'Branch'.
- Add a changelog fragment.

Fixes #9931
…ments (#10071)

* docs: add local development and evaluation sizing to hardware requirements

* docs: address review — recommend 6/8 cores for local eval, drop changelog
iddocohen and others added 6 commits July 29, 2026 17:58
* docs: document Community single-core Neo4j limitation

* docs: address review — clarify Neo4j Community single-core, drop changelog
* docs: link hardware requirements from Community install page

* docs: drop changelog for minor doc link
infrahub-demo-sp already has the receiving update-infrahub.yml and
update-infrahub-sdk.yml workflows, but it was never added to this matrix,
so they have never fired. Adding it means a new Infrahub release opens a
version-bump PR there, whose CI runs the demo's integration suite against
the release.
…mber pool (closes #7836) (#10085)

* test: add failing test for IFC-2095-jinja2-unallocated-pool

Reproduces the Jinja2 computed-attribute crash when a macro formats a
pool-sourced attribute that is not yet allocated during node creation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: skip Jinja2 macros referencing unallocated pool attributes

A computed Jinja2 attribute whose template reads a pool-sourced local
attribute is now left unrendered while that attribute has no allocated
value, instead of rendering against None. The macro is evaluated once
the pool allocation has taken place.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: cover independent macros rendering when a pool is unallocated

Adds a Node.new(process_pools=False) case asserting that a macro which
does not reference the unallocated pool still renders, guarding against
skipping every macro instead of only pool-dependent ones.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: add changelog fragment for jinja2 pool fix

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: reuse Snow schema helper for pool computed-attribute tests

Derives the number-pool + Jinja2 computed-attribute schema from the
shared Snow helper via deepcopy, overriding only the identifier template
to exercise the leading-zero format filter, instead of defining a
bespoke inline schema.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: guard recompute path against unallocated pool variables

_resolve_jinja2_variables can now return None for a pool-sourced
dependency that is not yet allocated; the recompute path skips that
attribute instead of passing None into template rendering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: extract pending-pool-dependency check from variable resolver

Keeps _resolve_jinja2_variables a pure variable-to-value mapping and
moves the "can this macro be rendered yet" decision into a dedicated
predicate, shared by the create and recompute paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: cover GraphQL create and mixed-variable pool macros

Adds a GraphQL create path exercising the reporter's scenario end to end,
and a macro referencing both the pool value and a plain attribute to
confirm every variable renders once the pool is allocated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: move GraphQL pool-macro test to the GraphQL mutation suite

Relocates the GraphQL create test next to the other jinja2-computed-
attribute mutation tests, and extracts the shared Snow schema builder and
number-pool provisioning into tests/helpers/number_pool so both the
core-layer and GraphQL-layer tests reuse them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: build a fresh ComputedAttribute in the number-pool helper

Assigns a new ComputedAttribute rather than mutating an optional field,
so the helper type-checks under ty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: key changelog fragment to GitHub issue 7836

Renames the orphan changelog fragment so towncrier renders the link to
the original issue this fix closes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: defer computed attributes chained on a skipped pool macro

When a computed attribute is skipped because it reads an unallocated pool
value, any computed attribute that references it is now deferred as well,
instead of rendering against the skipped value. Macros are already
iterated in dependency order, so tracking the skipped set is enough to
cascade the skip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: extract referenced-root-fields helper for macro dependencies

Replaces the hand-rolled `variable.split("__")[0]` root extraction, which
was repeated in both the create and recompute macro paths, with a single
named helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: move referenced-root-fields onto InfrahubJinja2Template

The root-field extraction operates only on a template's variables, so it
belongs on the template rather than as a static method on Node. Both the
create and recompute macro paths call it through the template.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…10062)

* perf(graphql): skip peer hydration for id-only single relationships

When a cardinality-one relationship query requests only the peer node's
`id` (no properties, metadata, or additional node fields), return the
peer ID already loaded on the parent instead of hydrating a full peer
Node via NodeDataLoader. This avoids redundant database work on
relationship-heavy queries such as cable-plan reports.

The resolver falls through to the existing NodeDataLoader / query_peers
paths whenever any other field, property, or metadata is requested, so
behavior is unchanged for all other queries.

* fix(graphql): skip id-only relationship shortcut for generic peers

The id-only single-relationship shortcut returns {"id": peer_id} without
the peer kind. For a relationship whose peer is a generic, the GraphQL
node field is an interface whose resolve_type needs the kind, so it fails
with "Unable to identify the type of the instance." Restrict the shortcut
to concrete peers; generic peers fall back to full hydration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZdYyE4JewWbMZAbvWPjQe

* perf(graphql): carry peer kind so generic id-only relationships skip hydration

The id-only single-relationship shortcut had to be disabled for generic
peers: it returned {"id": peer_id} without a kind, and a generic peer
resolves to a GraphQL interface whose resolve_type indexes the type
registry by kind. That excluded a large share of core-schema
relationships from the optimization.

The peer's concrete kind was available all along. The relationship query
already binds the peer vertex and returns peer.uuid, so returning
peer.kind alongside it costs no extra round trip. Thread that kind
through GroupedPeerNodes, PeerWithRelationshipMetadata and Relationship
so the preloaded stub on a node's GraphQL response can carry __kind__,
and let the shortcut serve generic peers from it.

The shortcut declines whenever the kind is absent and the resolver
hydrates as before, so correctness never depends on the enrichment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(graphql): assert generic-peer id-only relationship skips hydration

Add a component test that exercises the id-only single-relationship shortcut
against a cardinality-one relationship whose peer is a generic. It monkeypatches
NodeDataLoader.load to raise, so a regression to the correct-but-slower
hydrating path fails loudly instead of passing silently.

* test(benchmark): add id-only single-relationship benchmark

Add test_query_rel_one_id_only mirroring test_query_rel_one but selecting
only the peer id (repository { node { id } }), so the id-only
single-relationship shortcut is exercised and validated by CodSpeed CI.

* update name, reduce comment

* consolidate tests

* reduce size of huge test file

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Aaron McCarty <aaron@opsmill.com>
…9586)

* docs: polish 1.9.0 release notes — voice, clarity, learn-more links

Apply a voice and clarity pass to the 1.9.0 release notes:

- Voice: drop the marketing opener, remove a forbidden word and an
  idiom, replace product-as-agent value claims, cut vendor-positioning
  phrasing.
- Clarity for an international audience: split over-packed sentences,
  expand SIEM and hfid on first use, replace residual colloquialisms.
- Educational: add a "why" to namespace restrictions; add six
  "Learn more" links from feature sections to their docs pages.
- Fixes: correct the "are can be forwarded" grammar error and resolve
  the infrahub-sdk version placeholder to 1.20.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: polish 1.8.0 release notes — voice, clarity, learn-more links

Apply the same voice and clarity pass to the 1.8.0 notes:

- Voice: drop the marketing opener and filler ("now simpler",
  "continues to evolve", "enhance the day-to-day experience"), fix a
  first-person "we can now".
- Clarity: fix the File Object terminology drift and a comma splice,
  add four "Learn more" links to the feature docs.
- Correctness: fix the duplicate "Second" migration step (-> Third),
  two grammar errors ("helps speeding up", "command need to run"),
  and a stray semicolon in the MIME-type list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: replace figurative "carry/carries" in 1.9.0 notes

"carries the event as JSON" -> "contains"; "Webhooks can now carry ...
headers" -> "send". Direct verbs per the voice rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Yvonne <yvonne@opsmill.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Damien Garros <damien@opsmill.com>
@pa-lem
pa-lem merged commit 1e696cb into release-1.11 Jul 31, 2026
325 checks passed
pa-lem added a commit that referenced this pull request Jul 31, 2026
* fix(frontend): filter relationship selectors by common_parent (#10039)

Relationship selectors in object forms now honor the `common_parent` schema
property: options are filtered to peers that share the same parent as the value
picked for the referenced relationship in the same form, instead of listing
every peer.

- Add useCommonParentFilter hook: watches the sibling common_parent field and
  derives a single-hop `<X>__ids` filter (plus a matching RelationshipInput
  parent shape).
- Apply across the many, node, generic, and hierarchical relationship fields.
- Hide the manual parent picker on cardinality-one fields when common_parent is
  set, since the parent is then driven by the sibling field.

Keep the selection consistent with the filter so it can't be bypassed:
- Clear the current selection when the chosen parent changes (a peer valid under
  the old parent no longer satisfies the constraint).
- Pre-fill the inline "Add new" create form with the chosen parent, so a peer
  created there satisfies the constraint instead of being an escape hatch.
- Keep the filter applied on UUID searches (opt-in), and drop the hierarchical
  "Explore" tree tab, which browses a different axis and can't honor the filter.

Fixes IFC-1646.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: skip merged branches during git repository sync (#9938)

fix: skip merged branches during git repository sync

A git branch mapping to a merged (read-only) Infrahub branch caused
collect_pending_imports to issue a CoreRepositoryUpdate, which the graph
rejects for merged branches. The unhandled error aborted the entire sync
flow on every cron cycle, so no branches or repositories synced at all.

Branches in a terminal status are now skipped during collection, letting
the remaining branches and repositories sync as normal.

Also:
- Add a regression test covering the merged-branch case.
- Stub sdk.branch.all() in the git conftest, shared by the sync tests and
  the lock-scope test. The skip introduces a branch.all() call on the
  sync path, which the dummy SDK requester answers with an empty payload
  and raises KeyError: 'Branch'.
- Add a changelog fragment.

Fixes #9931

* docs: add local development and evaluation sizing to hardware requirements (#10071)

* docs: add local development and evaluation sizing to hardware requirements

* docs: address review — recommend 6/8 cores for local eval, drop changelog

* docs: document Community single-core Neo4j limitation (#10072)

* docs: document Community single-core Neo4j limitation

* docs: address review — clarify Neo4j Community single-core, drop changelog

* docs: link hardware requirements from Community install page (#10073)

* docs: link hardware requirements from Community install page

* docs: drop changelog for minor doc link

* ci: dispatch Infrahub releases to infrahub-demo-sp (#10076)

infrahub-demo-sp already has the receiving update-infrahub.yml and
update-infrahub-sdk.yml workflows, but it was never added to this matrix,
so they have never fired. Adding it means a new Infrahub release opens a
version-bump PR there, whose CI runs the demo's integration suite against
the release.

* fix: render Jinja2 computed attributes sourced from an unallocated number pool (closes #7836) (#10085)

* test: add failing test for IFC-2095-jinja2-unallocated-pool

Reproduces the Jinja2 computed-attribute crash when a macro formats a
pool-sourced attribute that is not yet allocated during node creation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: skip Jinja2 macros referencing unallocated pool attributes

A computed Jinja2 attribute whose template reads a pool-sourced local
attribute is now left unrendered while that attribute has no allocated
value, instead of rendering against None. The macro is evaluated once
the pool allocation has taken place.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: cover independent macros rendering when a pool is unallocated

Adds a Node.new(process_pools=False) case asserting that a macro which
does not reference the unallocated pool still renders, guarding against
skipping every macro instead of only pool-dependent ones.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: add changelog fragment for jinja2 pool fix

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: reuse Snow schema helper for pool computed-attribute tests

Derives the number-pool + Jinja2 computed-attribute schema from the
shared Snow helper via deepcopy, overriding only the identifier template
to exercise the leading-zero format filter, instead of defining a
bespoke inline schema.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: guard recompute path against unallocated pool variables

_resolve_jinja2_variables can now return None for a pool-sourced
dependency that is not yet allocated; the recompute path skips that
attribute instead of passing None into template rendering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: extract pending-pool-dependency check from variable resolver

Keeps _resolve_jinja2_variables a pure variable-to-value mapping and
moves the "can this macro be rendered yet" decision into a dedicated
predicate, shared by the create and recompute paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: cover GraphQL create and mixed-variable pool macros

Adds a GraphQL create path exercising the reporter's scenario end to end,
and a macro referencing both the pool value and a plain attribute to
confirm every variable renders once the pool is allocated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: move GraphQL pool-macro test to the GraphQL mutation suite

Relocates the GraphQL create test next to the other jinja2-computed-
attribute mutation tests, and extracts the shared Snow schema builder and
number-pool provisioning into tests/helpers/number_pool so both the
core-layer and GraphQL-layer tests reuse them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: build a fresh ComputedAttribute in the number-pool helper

Assigns a new ComputedAttribute rather than mutating an optional field,
so the helper type-checks under ty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: key changelog fragment to GitHub issue 7836

Renames the orphan changelog fragment so towncrier renders the link to
the original issue this fix closes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: defer computed attributes chained on a skipped pool macro

When a computed attribute is skipped because it reads an unallocated pool
value, any computed attribute that references it is now deferred as well,
instead of rendering against the skipped value. Macros are already
iterated in dependency order, so tracking the skipped set is enough to
cascade the skip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: extract referenced-root-fields helper for macro dependencies

Replaces the hand-rolled `variable.split("__")[0]` root extraction, which
was repeated in both the create and recompute macro paths, with a single
named helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: move referenced-root-fields onto InfrahubJinja2Template

The root-field extraction operates only on a template's variables, so it
belongs on the template rather than as a static method on Node. Both the
create and recompute macro paths call it through the template.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* perf(graphql): skip peer hydration for id-only single relationships (#10062)

* perf(graphql): skip peer hydration for id-only single relationships

When a cardinality-one relationship query requests only the peer node's
`id` (no properties, metadata, or additional node fields), return the
peer ID already loaded on the parent instead of hydrating a full peer
Node via NodeDataLoader. This avoids redundant database work on
relationship-heavy queries such as cable-plan reports.

The resolver falls through to the existing NodeDataLoader / query_peers
paths whenever any other field, property, or metadata is requested, so
behavior is unchanged for all other queries.

* fix(graphql): skip id-only relationship shortcut for generic peers

The id-only single-relationship shortcut returns {"id": peer_id} without
the peer kind. For a relationship whose peer is a generic, the GraphQL
node field is an interface whose resolve_type needs the kind, so it fails
with "Unable to identify the type of the instance." Restrict the shortcut
to concrete peers; generic peers fall back to full hydration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZdYyE4JewWbMZAbvWPjQe

* perf(graphql): carry peer kind so generic id-only relationships skip hydration

The id-only single-relationship shortcut had to be disabled for generic
peers: it returned {"id": peer_id} without a kind, and a generic peer
resolves to a GraphQL interface whose resolve_type indexes the type
registry by kind. That excluded a large share of core-schema
relationships from the optimization.

The peer's concrete kind was available all along. The relationship query
already binds the peer vertex and returns peer.uuid, so returning
peer.kind alongside it costs no extra round trip. Thread that kind
through GroupedPeerNodes, PeerWithRelationshipMetadata and Relationship
so the preloaded stub on a node's GraphQL response can carry __kind__,
and let the shortcut serve generic peers from it.

The shortcut declines whenever the kind is absent and the resolver
hydrates as before, so correctness never depends on the enrichment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(graphql): assert generic-peer id-only relationship skips hydration

Add a component test that exercises the id-only single-relationship shortcut
against a cardinality-one relationship whose peer is a generic. It monkeypatches
NodeDataLoader.load to raise, so a regression to the correct-but-slower
hydrating path fails loudly instead of passing silently.

* test(benchmark): add id-only single-relationship benchmark

Add test_query_rel_one_id_only mirroring test_query_rel_one but selecting
only the peer id (repository { node { id } }), so the id-only
single-relationship shortcut is exercised and validated by CodSpeed CI.

* update name, reduce comment

* consolidate tests

* reduce size of huge test file

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Aaron McCarty <aaron@opsmill.com>

* docs: polish 1.8.0 and 1.9.0 release notes (voice, clarity, links) (#9586)

* docs: polish 1.9.0 release notes — voice, clarity, learn-more links

Apply a voice and clarity pass to the 1.9.0 release notes:

- Voice: drop the marketing opener, remove a forbidden word and an
  idiom, replace product-as-agent value claims, cut vendor-positioning
  phrasing.
- Clarity for an international audience: split over-packed sentences,
  expand SIEM and hfid on first use, replace residual colloquialisms.
- Educational: add a "why" to namespace restrictions; add six
  "Learn more" links from feature sections to their docs pages.
- Fixes: correct the "are can be forwarded" grammar error and resolve
  the infrahub-sdk version placeholder to 1.20.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: polish 1.8.0 release notes — voice, clarity, learn-more links

Apply the same voice and clarity pass to the 1.8.0 notes:

- Voice: drop the marketing opener and filler ("now simpler",
  "continues to evolve", "enhance the day-to-day experience"), fix a
  first-person "we can now".
- Clarity: fix the File Object terminology drift and a comma splice,
  add four "Learn more" links to the feature docs.
- Correctness: fix the duplicate "Second" migration step (-> Third),
  two grammar errors ("helps speeding up", "command need to run"),
  and a stray semicolon in the MIME-type list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: replace figurative "carry/carries" in 1.9.0 notes

"carries the event as JSON" -> "contains"; "Webhooks can now carry ...
headers" -> "send". Direct verbs per the voice rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Yvonne <yvonne@opsmill.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Damien Garros <damien@opsmill.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Alex Gittings <agitting96@gmail.com>
Co-authored-by: iddocohen <iddocohen@gmail.com>
Co-authored-by: Pete Crocker <pete@petecrocker.com>
Co-authored-by: Pol Michel <40861490+polmichel@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Aaron McCarty <aaron@opsmill.com>
Co-authored-by: Yvonne <yvonne@bluecanyon.us>
Co-authored-by: Yvonne <yvonne@opsmill.com>
Co-authored-by: Damien Garros <damien@opsmill.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants