🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

feat: add agent runtime hour license claims and entitlement feature - #27459

Merged
jaaydenh merged 3 commits into
mainfrom
codagt-837-agent-runtime-license-claims
Jul 29, 2026
Merged

feat: add agent runtime hour license claims and entitlement feature#27459
jaaydenh merged 3 commits into
mainfrom
codagt-837-agent-runtime-license-claims

Conversation

@jaaydenh

@jaaydenh jaaydenh commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

closes CODAGT-837

Licenses can now carry three agent runtime hour claims: agent_runtime_hours_allocation, agent_runtime_hours_limit_soft, and agent_runtime_hours_limit_hard (unit: hours). They surface as the new usage-period feature agent_runtime_hours in GET /api/v2/entitlements, where limit carries the allocation and the new optional soft_limit / hard_limit fields on codersdk.Feature carry the thresholds.

Invalid combinations reject the entire license via validateClaims (both at upload and when computing entitlements for stored licenses): soft/hard without allocation, negative allocation, soft outside 0 <= soft < allocation, or hard < allocation.

Soft and hard limits are not comparison inputs in Feature.Compare; they ride along with whichever license wins (newest iat, existing behavior). None of the three claim names is a feature name, so old servers ignore them via the existing unknown-claim tolerance, protecting rollout of licenses minted with the new claims.

The claim name constants defined in enterprise/coderd/license are the canonical contract for github.com/coder/license (X1).

Part of CODAGT-837. Blocks B4 (usage wiring + warnings), C1 (hard-limit admission gate), F1 (licenses page), A4 (managed-agent coexistence), X1 (licensor).

Out of scope, handled by follow-up issues: Actual usage wiring, threshold warnings, admission gating, premium defaults, and FE surfacing beyond regenerated types.

Implementation plan and decision log

Decisions (confirmed by jaayden, 2026-07-23)

  1. Claim names / unit:
    • agent_runtime_hours_allocation - allocation (unit: hours, int64)
    • agent_runtime_hours_limit_soft - soft limit
    • agent_runtime_hours_limit_hard - hard limit
    • None of the three claim names is itself a FeatureName; all three map to the single new usage-period feature agent_runtime_hours (FeatureAgentRuntimeHours), mirroring how managed_agent_limit_soft mapped onto managed_agent_limit. Old servers therefore ignore all three claims via the FeatureNamesMap check.
  2. Reject-license. Invalid claim combinations reject the whole license via validateClaims (upload returns 400 via ParseClaimsIgnoreNbf; already-stored licenses produce an Invalid license ... parsing claims entitlements error and contribute nothing).

Design notes

  • codersdk.Feature had a SoftLimit field until 051ed34 ("feat: convert soft_limit to limit", feat: convert soft_limit to limit #22048) collapsed managed-agent soft/hard into a single limit. This reintroduces soft/hard as optional fields without changing managed-agent behavior.
  • Existing usage-period machinery populates UsagePeriod from nbf/exp (usagePeriodStart/usagePeriodEnd in LicensesEntitlements); reused unchanged, consistent with managed agents.
  • Entitlements.AddFeature replaces whole Feature structs (no merging), so soft/hard automatically ride along with the winning license. No Feature.Compare logic change; doc updates plus tests pin that soft/hard are not comparison inputs.
  • The feature name itself is not accepted as a claim; the allocation must come from the dedicated claim so it is validated against soft/hard (prevents a validation bypass where a direct feature-name claim could win precedence with unvalidated thresholds).
  • The generic "enabled but not entitled/expired" warning loop skips the feature, mirroring FeatureManagedAgentLimit; usage-based warnings arrive with B4.
  • No premium default for this feature (unlike managed agents).

Changes

  1. codersdk/deployment.go: new FeatureAgentRuntimeHours (in FeatureNames, UsesLimit(), UsesUsagePeriod(), keeping it out of FeatureSet expansion); Feature.SoftLimit/Feature.HardLimit (soft_limit/hard_limit, omitempty); doc updates for UsagePeriod and Compare.
  2. enterprise/coderd/license/license.go: canonical claim constants; validation helper called from validateClaims; al-la-carte loop maps the allocation claim to the feature and attaches soft/hard from the companion claims; skips for the companion claims and the raw feature name; generic warning loop skip.
  3. enterprise/coderd/coderdenttest: AgentRuntimeHours(allocation) builder.
  4. Tests:
    • TestAgentRuntimeHoursLicenses: entitled/grace round-trips (including JSON field assertions), allocation-only, explicit zero, IssuedAtRanking mirror, soft/hard ride-along with a newer allocation-only license, direct feature-name claim ignored, unknown-claims compatibility (old-server simulation).
    • TestAgentRuntimeHoursClaimValidation: table of valid/invalid claim combinations against ParseClaims, plus stored-license entitlements error.
    • TestPostLicense: API-level 400 rejection and a happy-path POST + GET /api/v2/entitlements round-trip.
    • TestFeatureComparison: soft/hard ignored in comparison; newest iat wins over larger soft/hard.
  5. make gen: regenerated site/src/api/typesGenerated.ts, coderd/apidoc/*, docs/reference/api/*.

Verification

  • go test ./enterprise/coderd/license/ ./codersdk/ and go test ./enterprise/coderd/ -run 'TestPostLicense|TestEntitlements' pass.
  • golangci-lint clean on changed packages; make lint/emdash clean; FE tsc --noEmit clean.
  • Independent agent review of the diff found no blockers; its minor findings (direct feature-name claim validation bypass, precedence test gap, missing API happy-path test) were addressed.

Note

Generated by Coder Agents on behalf of @jaaydenh (Linear CODAGT-837 agent session).

Licenses can now carry three claims for agent runtime hours:
agent_runtime_hours_allocation, agent_runtime_hours_limit_soft, and
agent_runtime_hours_limit_hard (unit: hours). They surface as the new
usage-period feature agent_runtime_hours in GET /api/v2/entitlements,
where limit carries the allocation and the new optional soft_limit and
hard_limit fields carry the thresholds.

Invalid claim combinations (soft/hard without allocation, negative
allocation, soft outside 0 <= soft < allocation, hard < allocation)
reject the entire license, following the validateClaims precedent.

Soft and hard limits are not comparison inputs in Feature.Compare; they
ride along with whichever license wins (newest iat, existing behavior).
Old servers ignore all three claims since none of them is a feature
name, protecting rollout of licenses minted with the new claims.

Part of CODAGT-837. The claim name constants defined here are the
canonical contract for github.com/coder/license (X1).
@linear-code

linear-code Bot commented Jul 23, 2026

Copy link
Copy Markdown

CODAGT-837

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Docs preview

Check off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here.

@jaaydenh

Copy link
Copy Markdown
Contributor Author

/coder-agents-review
@codex review

@coder-agents-review

coder-agents-review Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Chat: Review posted | View chat
Requested: 2026-07-27 12:09 UTC by @jaaydenh
Spend: $46.46 / $100.00

Review history
  • R1 (2026-07-23): 18 reviewers, 4 Nit, 4 P3, 1 P4, COMMENT. Review
  • R2 (2026-07-27): 14 reviewers, 5 Nit, 1 Note, 4 P3, 1 P4, APPROVE. Review

deep-review v0.9.0 | Round 2 | 671173b..ccd4572

Last posted: Round 2, 11 findings (4 P3, 1 P4, 5 Nit, 1 Note), APPROVE. Review

Finding inventory

Finding inventory - PR #27459

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P3 Author fixed (ccd4572) coderdenttest.go:244 Exported AgentRuntimeHours test builder has zero callers and is untested R1 Netero Yes
CRF-2 P3 Author fixed (ccd4572) license.go:709 allocation=0 with positive hard passes validation; feature ships disabled but with a hard ceiling R1 Mafuuu P3, Knov P3 Yes
CRF-3 P3 Author fixed (ccd4572) license.go:658 Rollout invariant "no claim name is a feature name" is load-bearing but unpinned by any test R1 Chopper Yes
CRF-4 P3 Author fixed (ccd4572) license.go:300 Three-claim knowledge duplicated across validator, remap/skip block, and struct build; sites can drift R1 Ryosuke P3, Robin Note Yes
CRF-5 P4 Author fixed (ccd4572) license.go:576 New warning-suppression branch is executed but no test asserts the warning is absent R1 Bisky Yes
CRF-6 Nit Author fixed (ccd4572) deployment.go:202 Doc comment starts with AgentRuntimeHours, not the symbol name FeatureAgentRuntimeHours R1 Gon, Leorio Yes
CRF-7 Nit Author fixed (ccd4572) deployment.go:392 HardLimit has no own doc comment, so generated API schema leaves hard_limit description blank R1 Meruem Nit, Leorio Note Yes
CRF-8 Nit Author fixed (ccd4572) license.go:681 Error vars drop Hours, breaking the AgentRuntimeHours naming pattern R1 Gon Yes
CRF-9 Nit Author fixed (ccd4572) license.go:681 ErrMissingAgentRuntimeAllocation message says "agent runtime limit claims", vaguer than the guard R1 Gon Yes
CRF-10 Nit Open license.go:729 Inconsistent receiver style: validateAgentRuntimeHours is a method on Features but decodeAgentRuntimeHours/isAgentRuntimeHoursClaim are free functions R2 Ryosuke Yes
CRF-11 Note Open license.go:648 Claim string literal values are unpinned by any test; a value rename stays green while silently breaking minted licenses R2 Chopper Yes
CRF-12 Nit Open commit ccd4572 Fix commit scope fix(enterprise/coderd/license) does not contain every changed file (AGENTS.md); change is cross-cutting R2 Leorio Body

Round log

Round 2

Churn guard PROCEED: 9 addressed, 0 silent, in commit ccd4572 (head 3463d7e..ccd4572). Panel (14: Netero first-pass + Bisky, Hisoka, Mafu-san, Mafuuu, Pariston, Ging-go, Gon, Leorio, Ryosuke, Knov, Chopper, Kurapika, Komugi, and wildcard Zoro). Netero clean. All nine R1 findings verified fixed at root cause on encounter (CRF-5 mutation-tested load-bearing by Bisky and Mafu-san, which also resolved Netero's doubt about the assertion). New code (decodeAgentRuntimeHours refactor, zero-allocation guard, new tests) reviewed. New findings: CRF-10 (Nit, receiver-style inconsistency), CRF-11 (Note, unpinned claim literal values), CRF-12 (Nit, commit scope; body). No P0/P1. Event APPROVE; 9 resolved threads confirmed and resolved. Reviewed against 671173b..ccd4572.

Round 1

Panel (18: Netero first-pass + Bisky, Hisoka, Mafu-san, Mafuuu, Pariston, Ging-go, Gon, Leorio, Kurapika, Knov, Ryosuke, Chopper, Melody, Komugi, Robin, Luffy, and wildcards Meruem, Razor). Netero clean at mechanical floor (P3 + Note only), so panel proceeded. 4 P3, 1 P4, 4 Nit. No P0/P1; event COMMENT. Reviewed against 671173b..3463d7e.

Design-level Notes recorded but not posted as line findings (covered in review body): whole-license rejection blast radius on a bad claim combo (author's confirmed reject-license stance, fail-loud; Pariston/Hisoka/Mafuuu), claim-name string contract drift with the licensor X1 (Pariston/Hisoka), soft_limit/hard_limit served on the unauthenticated GET /entitlements endpoint (same disclosure class as existing limit; Kurapika), soft/hard are inert data with no reader today (correct scope per B4/C1/F1; Luffy/Razor), and the dead UsesLimit() entry for this feature (harmless, mirrors managed agents; Ryosuke).

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Komugi flake/determinism
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 3463d7e242

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-scoped groundwork. Three flat license claims (agent_runtime_hours_allocation, _limit_soft, _limit_hard) map onto one usage-period feature agent_runtime_hours, mirroring the managed-agent path rather than inventing a new mechanism. The panel verified the load-bearing invariants hold: validation runs on every parse path (ParseClaims and ParseClaimsIgnoreNbf both route through validateClaims), the raw feature-name claim is skipped so an unvalidated allocation cannot win Feature.Compare precedence, soft/hard ride along with the winning license via AddFeature whole-struct replacement (never merged), and the feature is correctly excluded from Premium/Enterprise defaults. Bisky on the tests: "this test suite is lovely, and this time it's real." Test density is 83.4% and the assertions check real numbers and wire keys, not mocks echoing themselves.

Severity count: 4 P3, 1 P4, 4 Nit. No P0/P1, so this is a COMMENT, not a request for changes. The strongest finding is a validation gap this PR itself introduces (allocation=0 accepting a positive hard ceiling); the rest are coverage, maintainability, naming, and doc-generation edges.

Design observations the human should weigh, none blocking and none needing a code change here:

  • Whole-license rejection blast radius: a single malformed threshold rejects the entire license (400 on upload; HasLicense=false and every feature dropped for a stored license). This is the confirmed reject-license stance (decision 2) and fails loud rather than shipping a wrong limit; no field-minted license can carry these brand-new claim names, so the practical window is a future licensor bug. Worth confirming the blast radius is acceptable versus degrading to ignoring only the malformed feature.
  • Cross-repo name contract: the claim constants are declared canonical for github.com/coder/license (X1) but matched by exact string with no mechanical link. A rename or typo on either side falls through the unknown-claim tolerance and the feature silently vanishes. Worth generating or checking the licensor's bounds against these same constants when X1 lands, rather than hand-duplicating.
  • soft_limit/hard_limit are served on GET /api/v2/entitlements, which is registered outside apiKeyMiddleware and is unauthenticated. Same disclosure class as the limit/enabled/entitlement already exposed there, so nothing new, but the enforcement follow-ups should not treat these thresholds as secret.
  • soft/hard are inert data today (no reader in production; B4/C1/F1 are follow-ups). Correct scope, flagged so nobody reads three numbers off the entitlements response and assumes something enforces them.
  • FeatureAgentRuntimeHours is added to UsesLimit() but that arm never fires (the UsesUsagePeriod() case precedes it). Harmless and consistent with FeatureManagedAgentLimit, which sets both; removing it would change nothing.

🤖 This review was automatically generated with Coder Agents.

Comment thread enterprise/coderd/license/license.go
Comment thread enterprise/coderd/license/license.go
Comment thread enterprise/coderd/license/license.go Outdated
// hard limit claims can be set with Feature using
// license.ClaimAgentRuntimeHoursLimitSoft and
// license.ClaimAgentRuntimeHoursLimitHard.
func (opts *LicenseOptions) AgentRuntimeHours(allocation int64) *LicenseOptions {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-1] The new exported AgentRuntimeHours test builder has zero callers and is itself untested. (Netero)

Its sibling ManagedAgentLimit (same file, line 237) has three production-test callers ... Every test added in this PR bypasses the builder and constructs the map directly

Because no test exercises it, a wrong mapping in the helper (for example pointing at the soft-limit claim) would ship undetected. Either delete it or use it in the new tests so it is covered. Assuming the usage-wiring follow-ups will call it is a deferral without a caller in this diff.

🤖

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove if its not used

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in ccd4572. Removed the AgentRuntimeHours builder. Every test constructs license.Features directly, so it had no callers and no coverage; the usage-wiring follow-ups can add it back with a caller.

Generated with Coder Agents on behalf of @jaaydenh.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified fixed in ccd4572. The unused AgentRuntimeHours builder is removed; tests construct license.Features directly with the claim constants, so no dangling reference remains.

🤖

Comment thread enterprise/coderd/license/license.go
Comment thread codersdk/deployment.go Outdated
Comment thread codersdk/deployment.go
Comment thread enterprise/coderd/license/license.go Outdated
Comment thread enterprise/coderd/license/license.go Outdated
@jaaydenh
jaaydenh marked this pull request as ready for review July 27, 2026 11:33
@jaaydenh
jaaydenh requested a review from a team as a code owner July 27, 2026 11:33
…ndings

- Remove the unused AgentRuntimeHours license test builder.
- Reject agent runtime hours soft and hard limit claims when the
  allocation is 0, since a zero allocation disables the feature and a
  zero hard limit would read as a ceiling that blocks all agent runtime.
- Move claim-to-feature decoding into decodeAgentRuntimeHours so the
  loop no longer remaps and attaches limits in separate places.
- Pin the rollout invariant that no agent runtime hours claim name is a
  feature name.
- Assert the entitlement warning is suppressed for agent runtime hours.
- Rename the error vars to carry Hours and name the offending claims.
- Document HardLimit so the generated API schema describes it.

Copy link
Copy Markdown
Contributor Author

/coder-agents-review
@codex review

All nine R1 findings are addressed in ccd4572, with replies on each thread. Summary:

  • CRF-1: removed the unused AgentRuntimeHours test builder.
  • CRF-2: soft and hard limit claims are rejected when the allocation is 0, with a dedicated error and new test coverage for allocation=0, hard>0.
  • CRF-3: pinned the "no claim name is a feature name" invariant with a test over the real constants.
  • CRF-4: claim decoding collapsed into decodeAgentRuntimeHours, leaving the validator and the decoder as the only two sites.
  • CRF-5: SingleLicenseNotEntitled now asserts the warning is absent; verified red without the production skip.
  • CRF-6 to CRF-9: doc comment name, HardLimit doc plus make gen, error var renames, and error message wording.

Generated with Coder Agents on behalf of @jaaydenh.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: ccd457237d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round 2. All nine round-1 findings are fixed at the root cause and pinned, verified on the current code rather than trusted from the replies. The zero-allocation gap (CRF-2) is closed symmetrically with an explicit allocation == 0 && (hasSoft || hasHard) guard ahead of the bound checks, and ZeroAllocationWithPositiveHard pins the exact scenario. The three-site claim knowledge (CRF-4) is collapsed into a single decodeAgentRuntimeHours plus an isAgentRuntimeHoursClaim skip, which also eliminated the load-bearing claim-consumption ordering the old inline code depended on. CRF-5 was the one that could have been faked, so Bisky and Mafu-san both deleted the suppression branch and reran: the test failed with the warning present, so the NotContains assertion is genuinely load-bearing. The rollout invariant (CRF-3) is now pinned by ClaimNamesAreNotFeatureNames, and the four doc/naming nits are all resolved. Coverage of the three new functions reads 100% of statements. Bisky on the tests: "Usually this much jewelry is costume. I went through every stone. They're real."

The fix commit is proportional: no unrequested refactor rode along beyond the decodeAgentRuntimeHours/isAgentRuntimeHoursClaim pair that CRF-4 asked for, and the commit message maps one-to-one onto the diff.

Approving. Two minor new items and one process nit, none blocking:

  • CRF-10 (Nit): the three claim functions disagree on receiver style. Inline.
  • CRF-11 (Note): the claim string literal values are not pinned by any test, so a value rename (not a name rename) would stay green while silently breaking minted licenses. Inline, cheap to close.
  • CRF-12 (Nit, process): the fix commit subject fix(enterprise/coderd/license): ... uses a scope that does not contain every changed file. Per AGENTS.md, a scope must be a real filesystem path containing every changed file; this commit also touches codersdk/deployment.go, coderd/apidoc/*, docs/reference/api/schemas.md, site/src/api/typesGenerated.ts, and enterprise/coderd/coderdenttest/coderdenttest.go. Drop the scope for this cross-cutting change (fix: address agent runtime hours review findings); the feat commit and PR title already get this right.

Carryover design notes from round 1 still stand and still need no code change: soft/hard remain inert data until B4/C1/F1 (Leorio flags that the hard_limit doc says "enforcement ceiling" as present fact while nothing enforces it yet, borderline against the neighboring usage_period wording); GET /api/v2/entitlements remains unauthenticated but soft/hard are the same license-quota disclosure class already served there; and the ride-along-not-merge behavior (a newer allocation-only license nulls an older license's thresholds) is the single load-bearing assumption B4 must design around, now pinned by NewerIssuedAtWinsOverSoftHardLimits.

🤖 This review was automatically generated with Coder Agents.

Comment thread enterprise/coderd/license/license.go
Comment thread enterprise/coderd/license/license.go
@jaaydenh
jaaydenh requested review from ibetitsmike and johnstcn July 28, 2026 08:08

@johnstcn johnstcn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just prose nits and one observation.

Comment thread codersdk/deployment.go
Comment thread codersdk/deployment.go Outdated
Comment thread codersdk/deployment.go Outdated
Comment thread codersdk/deployment_test.go Outdated
Comment thread enterprise/coderd/license/license.go
Comment thread enterprise/coderd/license/license.go Outdated
Comment thread enterprise/coderd/license/license_test.go Outdated
Comment thread enterprise/coderd/license/license_test.go Outdated
Comment thread enterprise/coderd/license/license.go Outdated
// runtime hour claims. Invalid combinations reject the entire license rather
// than ignoring the feature, since these claims form a contract with the
// license issuer.
func (f Features) validateAgentRuntimeHours() error {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Observation: why not roll the validation into decoding? Or is the separation of decoding and validation a pre-existing convention?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is in validation, then its a fail fast and loudly situation when the license is uploaded. I thought that was better for avoiding invalid combinations of the soft limit, hard limit, and runtime allocation. As far as I can tell decoding doesn't have a clear way to surface like validation does. The thinking is that this helps when there is more complexity in the licenses.

@jaaydenh
jaaydenh merged commit 06ceb42 into main Jul 29, 2026
32 of 33 checks passed
@jaaydenh
jaaydenh deleted the codagt-837-agent-runtime-license-claims branch July 29, 2026 06:58
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants