Skip to content

docs(runbooks): add procedure to rename the default farm's code after upgrade - #731

Merged
mforce merged 2 commits into
mainfrom
docs/rename-default-farm-code
Sep 8, 2026
Merged

mforce merged 2 commits into
mainfrom
docs/rename-default-farm-code

Conversation

@mforce

@mforce mforce commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Summary

A database provisioned before multi-farm tenancy (v0.0.4 or earlier) gets default-farm from 20260818235944_AddAccountSlug on upgrade. Nothing asks for a code at migration time, and no verb, endpoint or Settings field renames one afterwards. This adds a section to the farm-provisioning runbook for the one operator-level path: a guarded UPDATE on Accounts.

  • guard on both id and current slug, bumps Version by hand (aggregate rule)
  • states what survives: refresh cookies and access tokens bind to the account id, so sessions keep working
  • states what goes stale until next login: SPA remembered farm code and per-farm palette cache (cosmetic)
  • reserved names listed explicitly, since login does not check Account.ReservedSlugs and the DB write checks nothing
  • no audit row is written; record the change in the deployment repo

Docs only. No product change, so no GLOSSARY / Help update.

Verified against code

  • Account.ReservedSlugs for the reserved list
  • AuthCookies.RefreshCookieNameFor(Guid accountId) for the session-survival claim
  • Login.tsx prefill: only when exactly one remembered code
  • ListAccountsCliCommand output columns

… upgrade

A database provisioned before multi-farm tenancy gets 'default-farm' from
20260818235944_AddAccountSlug, and no verb or Settings field changes it.
Document the guarded UPDATE, the Version bump, what survives (sessions bind
to the account id) and what goes stale (SPA remembered-code and palette
caches).
@coderabbitai

coderabbitai Bot commented Sep 8, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: d4439e61-d170-4de9-9130-6ac4718000c6


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…ent container

The Cluckwork image ships no psql. Add the compose-stack form (exec into
the db service) and the managed-Postgres form (throwaway client on the
pinned postgres image, URL from an env var).
@mforce

mforce commented Sep 8, 2026

Copy link
Copy Markdown
Owner Author

Follow-up: #732 files a rename-account verb that would replace the raw-SQL section here with a domain-checked, audited path. This PR stays the interim procedure.

@mforce
mforce merged commit 2f6e242 into main Sep 8, 2026
9 checks passed
@mforce
mforce deleted the docs/rename-default-farm-code branch September 8, 2026 22:40
mforce added a commit that referenced this pull request Sep 9, 2026
…s code (#732)

The post-lock fence compared the locked row's slug against the code the
operator named. That is not an identity. A blocked writer that renames the
farm away and back again commits two renames and leaves the code the lookup
read, so the fence passed and the rename overwrote both of them.

The lookup now snapshots Slug AND Version in the same combined read, and the
locked row must match both before anything is written. Neither half is
redundant: Version catches the away-and-back schedule, and the slug comparison
catches a code change that never advanced Version, which is what a raw UPDATE
outside the domain does. The cost is deliberate and recorded. Version also
advances for a Farm Settings save or a suspend, so a rename racing one of those
now returns Account.SlugStale and the operator re-runs. SingleAttemptExecution
and the rename/audit atomicity are unchanged.

Two integration tests pin the fence, one per shape a blocked writer can commit,
and deleting either half of the fence reds exactly one of them.

Also in this increment:

- The verb's stderr guard counted one member name, so the synchronous sibling
  of that member passed it. It now counts every direct use of the stderr stream
  and asserts the single occurrence sits inside the sanitized sink.
- Recorded that uppercase stored codes are out of scope, with the evidence:
  commit 2f6e242 constrained #731's raw-SQL procedure to the domain's lowercase
  syntax and warned that an uppercase code there was one nobody could sign in
  with. No bypass is added.
- The glossary names six system actors and includes the rename verb's.
- The decision's enforcement inventory names RenameAccountDocsTests and no
  longer claims the runbook prose and glossary wording are unenforced.
- Three new documentation guards cover the three items above; each was mutated
  red and restored.
mforce added a commit that referenced this pull request Sep 9, 2026
Closes #732. Reverses epic #530 decision 10, which deferred the rename
and recorded the farm code as immutable for that epic.

## What ships

A `rename-account --slug <current> --new-slug <new> [--reason <text>]`
one-shot verb, and the domain path behind it.

- **`Account.Rename`** validates through the same `TryValidateSlug`
provisioning uses, returns `Result` rather than throwing, and bumps
`Version` on a real change. Renaming a farm to the code it already has
is a **no-op**: success, no `Version` bump, no audit row — because
`Version` is the token a Farm Settings save holds open against.
- **`AccountRenameService`** resolves the code to an id, resolves the
tenant, takes the tenant-keyed `FOR UPDATE`, then **re-compares the
locked row's slug against the code the operator named**. The lookup and
the lock are two separate statements, so without that fence a rename
committed in between is silently overwritten. `IX_Accounts_Slug` is the
authority on the destination code and the `DbUpdateException` catch is
the guarantee; the pre-read in front of it is convenience only. The
audit row is written inside the transaction, so it lands with the rename
or not at all.
- **Audit vocabulary** `Account.Rename` in all three locales, offered in
the Audit filter.
- **Help and glossary** in `en`/`es`/`tl` stop saying the code cannot
change, and name the new `(rename-account)` system actor.

## #731's SQL section is replaced

`docs/runbooks/provisioning-a-new-farm.md` § *Renaming the default
farm's code* no longer teaches a hand-guarded `UPDATE "Accounts"`
through `psql`. That procedure bumped `Version` by hand, validated
neither the pattern nor the reserved set, wrote **no audit row** (it
told the operator to record the change in the deployment repo instead),
and needed a `postgres:` image literal in tracked prose to run the
client at all. The section now documents the verb, with blast radius,
prerequisites, verification, and one line per error code.
`docs/decisions/732-farm-code-rename.md` records the reasoning.

## Two accepted costs, both named in the decision record

1. **A retired code is immediately reusable.** There is no retired-code
list, so `--slug` targets whoever holds that code *now* — which may not
be the farm you meant. The verb's help and the runbook both say to run
`list-accounts` immediately before renaming, and
`AccountRenameServiceTests` pins the reuse behaviour so it is a recorded
fact. #530's sketch of this work assumed a retired-code list; shipping
without one is the deliberate difference.
2. **Client-side caches go stale.** The sign-in form's remembered code
and the per-farm palette cache still name the old code until the next
explicit sign-in. Both are cosmetic. Sessions are unaffected — tokens
bind to the account id — and `RenameVerb_LeavesAnExistingSessionWorking`
asserts it rather than reasoning about it.

## Test counts

- .NET: **2304 → 2333** (`2304 + 29`). Domain +11, Integration +18 (6
service, 10 CLI, 1 `Version` race, 1 minimal-config), Application and
AppHost unchanged.
- Web: **2706 → 2709** (`2706 + 3`).

## Mutation ledger — all rows run this session

Every row below was planted, rebuilt with `dotnet build Cluckwork.sln
--configuration Release --no-restore`, run, restored and rebuilt. **None
is implementer-attested-only; all were executed.**

| # | Result | Evidence |
|---|---|---|
| C | GREEN (control) | comment-only edit; `git grep "the same
accountability payload" -- tests` prints nothing |
| 1 | RED | `Assert.Equal() Failure: Values differ / Expected: 1 /
Actual: 0` |
| 1b | RED | `Assert.IsType() Failure: Value is null` — both stale
snapshots saved |
| 2 | RED | `Expected: 0 / Actual: 1` — a no-op advanced `Version` |
| 3 | RED | `Assert.True() Failure` on `result.IsFailure` in the
reserved loop |
| 4 | RED | `Assert.False(outcome.Success)` — **without the post-lock
fence the stale command overwrites the committed winner** |
| 5 | RED | `Assert.False(outcome.Changed)` fired first |
| 6 | RED | `Sequence contains no elements` — committed with no trail |
| 7 | RED | `Audit events require a resolved actor…` (#500 fail-closed)
|
| 8 | RED | `23505: duplicate key value violates unique constraint
"IX_Accounts_Slug"` escapes instead of `Account.SlugTaken` |
| 9 | **GREEN, by design** | pre-read deleted; the friendly error still
arrives from the index catch. Row 8 proves that catch with a race the
pre-read cannot reach, so the two layers are independently pinned |
| 10 | RED | `expected success, got Accounts.NotFound` — locked read
selects `WHERE "Id" = Guid.Empty` |
| 11a | **GREEN, by design** | the locked read is a real second layer |
| 11b | RED | `NullReferenceException` at the stale-slug comparison once
that layer is removed too |
| 12 | RED | `Collections differ` naming `"rename-account"` missing |
| 13 | RED | `verb(s) classified OneShot but never run here:
rename-account` |
| 14 | RED | `Server emits but the client is missing: Account.Rename` |
| 15 | RED | parity `expected [ 'auditAction.Account.Rename' ] to deeply
equal []`, and the locale test caught the English fallback masking it |
| surface 2 | RED | `auditAction.Account.Rename should have a key
mapping: expected undefined to be truthy` |

`git grep -n -e MUTANT -e 'DEBUG-' -- src tests` prints nothing.

## Notes for the reviewer

- **One translation substitution.** `es` uses `"Código de granja
cambiado"`, not the runbook's proposed `"Se cambió el código de la
granja"`: `es.ts:48` establishes the noun as `Código de granja` (no
article), and the three sibling audit labels are terse participial
phrases. `tl` kept as proposed — it already uses `tl.ts:54`'s `Code ng
bukid`.
- **Four tenant-bypass rows, not two.** The guard also flagged
`RenameAsync` twice as a *forwards-bypass* caller of the two private
reads. All four identities were pasted exactly as the guard printed
them; the diff is `20 insertions(+)` with no churn on rows I did not
author, and no pre-existing row showed stale.
- **`new { from = … }` compiles**, so the unescaped form is used, as 2c
directed. `nameof(Account)` renders `Account` — asserted by
`Rename_ChangesTheCode_…`'s `EntityType` check.
- **Flake observed, not fixed.** One G5 run after `npm ci` showed `Tests
2 failed | 2707 passed (2709)` in `StockPage.test.tsx` on two
async-supersession cases. Both passed in isolation (`73 passed`) and on
a full G5 re-run (`2709 passed`). That file and every Stock source file
are untouched by this branch.

---------

Co-authored-by: mforce <mforce@users.noreply.github.com>
mforce pushed a commit that referenced this pull request Sep 12, 2026
🤖 I have created a release *beep* *boop*
---


## [0.1.0](v0.0.4...v0.1.0)
(2026-09-12)


### ⚠ BREAKING CHANGES

* log in by farm code, with per-account email identity
([#532](#532)) (#564)

### Features

* **accounts:** add Account.Slug (farm code), suspend/reactivate,
list-accounts verb
([#531](#531))
([3fe9754](3fe9754))
* **accounts:** provision additional farms
([#581](#581))
([006f298](006f298))
* add Aspire local development AppHost
([#567](#567))
([2c9e6b9](2c9e6b9))
* add configurable worker sale allocation
([#619](#619))
([0955095](0955095))
* add searchable entity pickers
([#642](#642))
([60d2053](60d2053))
* **api:** provision-account takes an optional --timezone at creation
([#603](#603))
([#694](#694))
([a0aee39](a0aee39))
* **audit:** show the sales-line audit payload as a readable Details
column ([#745](#745))
([#749](#749))
([d26d389](d26d389))
* **auth:** add ApplicationUser.StepUpLogoutEpoch column
([#338](#338))
([#554](#554))
([18306ee](18306ee))
* certify over-cap simulation fixture bands
([#633](#633))
([a67b2e1](a67b2e1)),
closes [#627](#627)
* **cli:** rename-account verb to change a farm code
([#732](#732))
([#733](#733))
([4b70559](4b70559))
* **customers:** edit existing customer details
([#625](#625))
([#626](#626))
([062a55c](062a55c))
* **jobs:** single-runner leader gate for the durable job worker
([#271](#271))
([#555](#555))
([4148f9b](4148f9b))
* let owners change user email addresses
([#605](#605))
([842347b](842347b))
* log in by farm code, with per-account email identity
([#532](#532))
([#564](#564))
([68adb62](68adb62))
* **ratelimit:** distributed IP-keyed auth limiters
([#544](#544))
([#558](#558))
([ec14972](ec14972))
* **ratelimit:** distributed per-account report concurrency cap with
local-ceiling fallback
([#545](#545))
([#559](#559))
([1522e4e](1522e4e))
* **sales:** mark discounted lines, total the discount, and show it in
the Orders list ([#723](#723),
[#724](#724))
([#741](#741))
([1a07441](1a07441))
* **sales:** record list, old and new price in the order-line audit
payload ([#722](#722))
([#742](#742))
([97c866f](97c866f))
* **sales:** refuse an over-ceiling confirm from a Sales user
([#727](#727))
([#766](#766))
([8c0792a](8c0792a))
* **sales:** show what each order still owes, and filter the list to
unpaid ([#771](#771))
([ca59d68](ca59d68))
* **sales:** snapshot the list price on the order line and show the
discount ([#734](#734))
([cffed5e](cffed5e))
* **sales:** snapshot the product name and unit in the order-line audit
payload ([#747](#747))
([#748](#748))
([0481c06](0481c06))
* scope Worker reads to assigned flocks
([#388](#388))
([#611](#611))
([5884a9a](5884a9a))
* shared-state ports with Redis + in-process fallback
([#543](#543))
([#552](#552))
([f767fa9](f767fa9))
* suspend-account / reactivate-account operator verbs
([#534](#534))
([#573](#573))
([d0be26c](d0be26c))
* **tenancy:** write-side tenant guard + single-assignment TenantContext
([#546](#546))
([#561](#561))
([f371f1d](f371f1d))
* **web:** dashboard rework — capture-status tiles, 14-day trend, stock
as a stacked bar
([#654](#654))
([396ba23](396ba23))
* **web:** date-range filters on audit and expenses, and the stock lot
filter gets its bounded toolbar
([#666](#666),
[#667](#667),
[#653](#653))
([94b188f](94b188f))
* **web:** elevation hierarchy and sentence-case labels
([#651](#651),
[#652](#652))
([#661](#661))
([28db4c7](28db4c7))
* **web:** Expenses and Audit keep a clear-filters control while rows
are still showing
([#679](#679))
([#697](#697))
([b859982](b859982))
* **web:** expenses filters by a date range like its sibling screens
([#667](#667))
([f13858f](f13858f))
* **web:** key the farm brand palette per farm
([#586](#586))
([#600](#600))
([7183a43](7183a43))
* **web:** let operators forget remembered farms
([#598](#598))
([577d94e](577d94e))
* **web:** one-line provenance, bounded date filters, and empty states
that invite action
([#653](#653),
[#655](#655))
([#668](#668))
([80b53f4](80b53f4))
* **web:** prefill the farm code from ?farm= and remember it
([#535](#535))
([#588](#588))
([b7f5cc6](b7f5cc6))
* **web:** split authenticated routes into lazy chunks
([#620](#620))
([5089271](5089271))
* **web:** the audit log filters by a date range, and says which window
is empty ([#666](#666))
([63027e0](63027e0))
* **web:** typeset numbers as numbers and refresh the Help glossary
([#650](#650),
[#657](#657))
([af4fe11](af4fe11))


### Bug fixes

* **api:** order same-instant audit events by a durable monotonic key
([#700](#700))
([8fcf084](8fcf084))
* **api:** print the farm code from bootstrap-admin
([#589](#589))
([#594](#594))
([34032ac](34032ac))
* **audit:** show the price a line sold for, not its list price
([#759](#759))
([e6b37d0](e6b37d0))
* **audit:** store catalog enums by name and guard the add-item
transaction shape
([#751](#751))
([23609ff](23609ff))
* **auth:** reject invalid account claims
([#622](#622))
([8d6c7fe](8d6c7fe))
* **auth:** require step-up for durable user access
([#360](#360))
([#607](#607))
([f767dce](f767dce))
* **ci:** bound the npm audit calls and give the web job room to finish
([#686](#686))
([153b7a8](153b7a8))
* **ci:** escalate the audit bound to SIGKILL, so it actually bounds
([#686](#686))
([a0c8f4e](a0c8f4e))
* **ci:** fail closed on invalid vulnerability config
([#621](#621))
([1690db8](1690db8))
* **ci:** lockfix covers the two AppHost lock files, derived from the
sln
([efb05e6](efb05e6))
* **ci:** lockfix covers the two AppHost lock files, derived from the
sln
([8986d77](8986d77))
* **ci:** remove invalid XML comment from nuget.lockfix.config
([#541](#541))
([5f1bc0a](5f1bc0a))
* **ci:** the advisory vuln gate no longer blocks on an unusable report
([#686](#686))
([aaf6934](aaf6934))
* **ci:** the advisory vuln gate no longer blocks on an unusable report
([#686](#686))
([64f1f53](64f1f53))
* **i18n:** tl help text names the saleable flag and unit-system setting
what their labels call them
([#688](#688))
([#696](#696))
([bfd24d7](bfd24d7))
* **infra:** AccountId must be a non-nullable Guid or both tenant write
layers refuse ([#673](#673))
([#695](#695))
([2470c4e](2470c4e))
* require step-up for flock scope changes
([#609](#609))
([4151f89](4151f89))
* **sales:** keep a line's discount markers agreeing while its price is
edited ([#752](#752))
([#753](#753))
([c159b4b](c159b4b))
* **sales:** say which kind of missing list price a line has
([#774](#774))
([489180e](489180e))
* scope legacy logout to selected farm
([#624](#624))
([fae8d82](fae8d82))
* **seed:** drain the daily-entry lock sweep so deep simulation fixtures
validate ([#644](#644))
([730fa23](730fa23)),
closes [#638](#638)
* **tenancy:** AccountId is a concurrency token, so the database refuses
a detached cross-tenant write
([#562](#562))
([4d1dfa3](4d1dfa3))
* **tenancy:** AspNetUserRoles carries a tenant column, so a role write
naming another farm's user is refused
([#670](#670))
([fc0552a](fc0552a))
* **tests:** bump the image-pin allow-list counts for the AppHost
LocalPorts tests
([#593](#593))
([58d3056](58d3056))
* **tests:** the OTLP collector survives a lost port race and ignores
traffic that is not an export
([#672](#672),
[#676](#676))
([#677](#677))
([965c737](965c737))
* **web:** a scoped audit view filtered to nothing names both the record
and the range ([#666](#666))
([41bbfe1](41bbfe1))
* **web:** an abandoned dialog attempt's success no longer hijacks the
replacement on Customers, Daily Entry, Flocks, Grades and Products
([#703](#703))
([#705](#705))
([85605db](85605db))
* **web:** an abandoned dialog attempt's success no longer hijacks the
replacement on Inventory, Expenses, History and Stock
([#703](#703))
([#706](#706))
([60a4997](60a4997))
* **web:** an abandoned edit's success no longer hijacks the dialog that
replaced it on Users
([#703](#703))
([#710](#710))
([778faab](778faab))
* **web:** an abandoned order attempt's success no longer hijacks the
dialog that replaced it
([#702](#702))
([522c699](522c699))
* **web:** capture screens open on the flock you last used, and
assigning one no longer guesses
([#646](#646))
([#699](#699))
([7f8f317](7f8f317))
* **web:** constrain dialog session helpers to declared scopes
([#715](#715))
([389e3c8](389e3c8))
* **web:** date validation gets one boundary table instead of one case
per review round
([#666](#666))
([215f830](215f830))
* **web:** keep a paged window and an item panel on the user's newest
intent ([#645](#645))
([d81bccf](d81bccf))
* **web:** keep Sales order panels closed after pending writes
([#711](#711))
([f0f7492](f0f7492))
* **web:** keep Sales panels closed after pending Open reads
([#716](#716))
([620411f](620411f))
* **web:** make login take the cross-tab cookie lock so a racing refresh
cannot restore the wrong session
([#648](#648))
([ff18beb](ff18beb))
* **web:** make the entity picker read as a search field and focus it on
open ([#736](#736))
([66ef667](66ef667)),
closes [#735](#735)
* **web:** page truncated customer and movement tables with usePagedList
([7cfe4d6](7cfe4d6))
* **web:** reconcile Sales line edits with refreshed orders
([#717](#717))
([d7dd2c9](d7dd2c9))
* **web:** the audit date filter accepts low-numbered years, and its
empty state covers every narrowing
([#666](#666))
([af52d25](af52d25))
* **web:** the audit date filter rejects impossible dates, and its
history guard actually guards
([#666](#666))
([8d51846](8d51846))
* **web:** the expense range bounds are not capped at today, which the
month-end default exceeds
([#667](#667))
([7e01864](7e01864))
* **web:** the help text calls the expiry field what the field calls
itself ([#666](#666))
([2fd1f3c](2fd1f3c))
* **web:** the stock lot date range sits in the bounded toolbar
([#653](#653))
([43dec5e](43dec5e))


### Refactoring

* **web:** extract SalesPage's dialog-write wrapper into a shared
useDialogAction hook
([#703](#703))
([#704](#704))
([60ee9d9](60ee9d9))


### Documentation

* add k6 preparation steps to the dev-database fixture runbook
([#643](#643))
([a4f1f09](a4f1f09))
* add runbook for loading the simulation fixture into a dev database
([#639](#639))
([2d143b8](2d143b8))
* **agents:** a PR closes its issue from the body, not the title
([#744](#744))
([39be13c](39be13c))
* **agents:** drop the commit and push gate, and require screenshots on
UI changes ([#757](#757))
([6225172](6225172))
* **agents:** find guards by grepping registry readers; amend issues a
PR overtakes ([#580](#580))
([fe3fde8](fe3fde8))
* **agents:** the Playwright specs have been in CI since 2026-08-08
([#768](#768))
([68ee612](68ee612))
* **aspire:** record the second local database and pin the AppHost
dashboard ports ([#623](#623))
([713b941](713b941))
* compress AGENTS.md to one paragraph per rule, and draw the two orders
that matter ([#551](#551))
([997ae8a](997ae8a))
* item 7 names each screen's actual initial filter value
([#666](#666))
([70a53d8](70a53d8))
* multi-farm tenancy decision record and AGENTS/GLOSSARY sync
([#537](#537))
([#601](#601))
([2c34771](2c34771))
* name the scoped filtered-empty key and state the
[#653](#653) relationship
plainly ([#666](#666))
([0e93dac](0e93dac))
* note that a PackageReference in Directory.Build.props is invisible to
the dependency graph
([4845724](4845724))
* **plans:** commit the
[#722](#722) and
[#745](#745) design records
([#754](#754))
([c942fcd](c942fcd))
* record [#579](#579) as
won't-fix — suspension is immediate for use, not issuance
([#582](#582))
([7a3be40](7a3be40))
* record the [#508](#508)
audit ordering key and the tracked-file guard lesson
([#701](#701))
([08964e9](08964e9))
* **runbooks:** add procedure to rename the default farm's code after
upgrade ([#731](#731))
([2f6e242](2f6e242))
* screenshots of the running SPA in the README
([#550](#550))
([711488a](711488a))
* **sim:** commit the dashboard screenshot, capture the palette matrix,
and record the
[#651](https://github.com/mforce/cluckwork/issues/651)/[#652](https://github.com/mforce/cluckwork/issues/652)
conventions ([#660](#660),
[#662](#662),
[#663](#663),
[#664](#664))
([#665](#665))
([930ea30](930ea30))
* specify searchable entity picker
([#641](#641))
([91d4300](91d4300))
* split the README into audience-scoped docs and adopt repo-template
scaffolding ([#548](#548))
([b3f3fcf](b3f3fcf))
* surface Aspire local development workflow
([#568](#568))
([a343baa](a343baa))
* **web:** record the per-screen idempotency-key policies and runWrite's
refresh contract
([#703](#703))
([#707](#707))
([8bee651](8bee651))
* **web:** the date-cap help text covers every stocked item, not only
feed ([#666](#666),
[#667](#667))
([c8433c5](c8433c5))
* **web:** the help text claims only what is true of recording, and says
nothing about filter caps
([#666](#666),
[#667](#667))
([e2f63d1](e2f63d1))
* **web:** the help text describes the date-range filters that shipped
([#666](#666),
[#667](#667))
([c3275b7](c3275b7))
* **web:** the help text stops describing a cap the filters no longer
have ([#666](#666),
[#667](#667))
([49654cd](49654cd))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: cluckwork-lockfix[bot] <309265648+cluckwork-lockfix[bot]@users.noreply.github.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.

1 participant