Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: add per-license Products section with Coder Agents price gates - #28051

Merged
jaaydenh merged 76 commits into
mainfrom
license-page-t2yd
Aug 18, 2026
Merged

feat: add per-license Products section with Coder Agents price gates#28051
jaaydenh merged 76 commits into
mainfrom
license-page-t2yd

Conversation

@jaaydenh

@jaaydenh jaaydenh commented Aug 12, 2026

Copy link
Copy Markdown
Contributor
Screenshot 2026-08-17 at 3 43 51 PM

Each license card now always expands to a Products section: a Coder Workspaces box showing active seat usage, and, on Premium licenses, a Coder Agents box driven by the agent_runtime_hours_* license claims and the merged agent_runtime_hours entitlement. The card header gains a Type column (Trial/Standard), and the left header label now shows the feature set only (Premium/Enterprise).

The Coder Agents box renders five states: no allocation (dashed purple upgrade CTA), unlimited allocation (-1 sentinel), normal usage, allocation exceeded (red border and red "Agent hours exceeded" status; concurrent chats stay Unlimited), and hard limit exceeded (red "Hard limit exceeded" status; concurrent chats capped at 5, mirroring the backend's maxConcurrentRootAgents, which is not exposed via the API). Usage and overage indicators only render on the license whose allocation matches the merged entitlement and which is currently effective, following the existing AI Governance winning-license pattern via a generalized isLicenseApplicableForFeatureUsage helper; AI Governance add-on behavior is unchanged.

Stacked on #27985 (base branch runtime-hours-entitlements); do not merge before it.

Notes for review:

  • feat: report agent runtime hours usage in entitlements #27985 now grandfathers claim-less Premium licenses into a zero-hour agent_runtime_hours allocation, so the merged entitlement (disabled, limit: 0) and its measured actual are always present for Premium deployments. The upgrade card's "Agent hours used" row therefore renders universally; the Premium story pins that state.

  • Agent hours usage now renders with exactly one decimal (e.g. 16,264.3, 42.0), derived from feat: report agent runtime hours usage in entitlements #27985's new actual_ms field and floored to tenths with integer math. The same floored value drives the exceeded checks, so the displayed number and the red state flip at the same instant; a fraction past the allocation now trips "Agent hours exceeded" (20,000.1 > 20,000), pinned by the PremiumWithAgentHoursExceededByFraction story. The allocation denominator stays whole (it comes from the whole-hour license claim).

…ldens with generators

make fmt/go (gci) regroups the imports in smtp_internal_test.go, and
make gen/golden-files re-renders the AI budget notification goldens with
HTML-escaped apostrophes. Both were committed out of sync with the
repo's pinned tools, so every local pre-commit run failed its unstaged
check. No behavior change.
…ents

The usage generator writes hb_agent_runtime_v1 rows with created_at at
the UTC hourly bucket start and exactly one row per bucket, but nothing
in the schema enforced either invariant. A duplicate bucket row under a
different id would be double-counted by any consumer summing runtime_ms,
and a misaligned created_at would skew which usage period a bucket is
attributed to.

Replace the non-unique partial index idx_usage_events_agent_runtime with
a unique index of the same shape and add an hour-alignment CHECK
constraint. generateBucket treats a unique violation on the bucket index
as another replica having won the race, mirroring the existing
ON CONFLICT (id) no-op for committed rows.
…able runtime hours claims

Two coupled changes to the license/entitlements layer.

Measurement diagnostics: extract a measureUsage helper that owns the
usage-query failure policy. A query failure now publishes the stable
codersdk.LicenseManagedAgentUsageUnavailableErrorText on the
entitlements Errors channel (keeping the alertable coderd_license_errors
gauge counting) while the raw cause goes to the coderd log through the
new FeatureArguments.Logger. A nil usage closure becomes a hard
developer error, and a failure with a dead context still aborts the
whole refresh. The managed agent count closure switches from
AsSystemRestricted to the narrower AsUsagePublisher subject. The
dashboard recognizes diagnostic texts and renders them muted, without
the exceedance heading or a sales link.

Claim tolerance: unusable agent_runtime_hours_* claim combinations no
longer reject the whole license. decodeAgentRuntimeHours drops the
unusable claims, reports them in a stable
LicenseAgentRuntimeHoursClaimsIgnoredWarningText warning (deduplicated
across licenses), and logs the affected license and claims;
validateAgentRuntimeHours and its license-invalidating errors are
removed. Rejecting a signed license over a cosmetic threshold claim
would drop the deployment to unlicensed.

Part of the stack for #27796.
Populate FeatureAgentRuntimeHours.Actual on every entitlements refresh
for licenses that grant the feature. A new
GetTotalUsageHBAgentRuntimeV1 query sums runtime_ms over the license's
usage period, reading usage_events directly: hb_agent_runtime_v1 is
exactly one row per hourly bucket deployment-wide, enforced by the
unique partial index idx_usage_events_agent_runtime.

The measurement reuses the shared measureUsage policy through a new
AgentRuntimeMsFn closure (usage publisher subject): failures publish
the stable LicenseAgentRuntimeUsageUnavailableErrorText and log the
cause. Usage is floored to whole hours, matching the unit of the
agent_runtime_hours_* claims, and at most one warning is emitted:
reaching the allocation supersedes the advisory soft limit. The
dashboard renders the soft-limit advisory muted without a sales link
and treats the runtime usage-unavailable text as a diagnostic.

Closes CODAGT-852.
…mplate goldens with generators"

This reverts commit ed531d9d365720b4e394f4b422ea9776886c56a3.

The gen/fmt drift it patched over came from main commit 07f79af
(fix: markdown rendering improvements) having landed out of sync with
its generators; main has since reverted that commit entirely in
8c2f7ad (#27979), so the sync is obsolete and conflicts with the
regenerated goldens on latest main.
…s unlimited

An agent_runtime_hours_allocation claim of exactly -1 now grants the
agent_runtime_hours feature enabled with a nil Limit, which the
entitlements API serves as an omitted "limit" field, the shape the UI
already renders as Unlimited. Threshold claims alongside it are dropped
with the existing claims-ignored warning, and any other negative
allocation remains unusable.
An unlimited (-1) allocation decodes to an enabled agent_runtime_hours
feature with a nil Limit, so the warning write-back now guards the
allocation dereference: no thresholds can exist for an unlimited
license, so no runtime hours warning is ever emitted. Actual usage is
still measured and published. Feature.Compare is unchanged; the
metered-beats-unlimited-on-exact-tie edge is pinned by a test and
documented on decodeAgentRuntimeHours.
The expanded arbiter-scoping commentary is not needed on the insert
query; the duplicate-bucket behavior is documented on the migration and
in generateBucket where it is handled.
…ments

Resolves LicenseBannerView.stories.tsx by adopting the base branch's
convention: data-variant assertions are dropped (visual snapshots cover
mutedness), so the runtime hour stories keep only their text and
sales-link assertions.
…000567

Main landed its own 000565 and 000566 (oauth2 client type constraint and
auth method backfill) after this branch was cut, making the migration
number a duplicate that fails migrate setup.
…ments

Adopts the base branch's trimmed comment style for the shared license
warning constants and diagnostics tests, keeping the runtime-hours
constants and the soft-limit prefix-coupling note; typesGenerated.ts is
regenerated.
A nil Limit on a usage period feature means unlimited, so Feature.Compare now ranks it above any set limit when issued-at and end dates tie. Also types the LicenseBanner map callbacks as LicenseBannerMessage instead of using as const assertions.
… per-license Products section with Coder Agents price gates

Each license card now always expands to a Products section: a Coder
Workspaces box with active seat usage, and (on Premium licenses) a Coder
Agents box driven by the agent_runtime_hours_* license claims and merged
agent_runtime_hours entitlement.

The Coder Agents box renders five states: no allocation (dashed purple
upgrade CTA), unlimited (-1 sentinel), normal usage, allocation exceeded
(red border, red 'Agent hours exceeded' status, chats stay Unlimited),
and hard limit exceeded (red 'Hard limit exceeded' status, chats capped
at 5, mirroring the backend's maxConcurrentRootAgents). Usage and
overage indicators follow the AI Governance winning-license pattern via
a generalized isLicenseApplicableForFeatureUsage helper.

The header gains a Type column (Trial/Standard) and the left label now
shows the feature set only (Premium/Enterprise).
@linear-code

linear-code Bot commented Aug 12, 2026

Copy link
Copy Markdown

CODAGT-808

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea1ef4f51a

ℹ️ 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".

Comment thread site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseCard.tsx Outdated
Comment thread site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseCard.tsx Outdated
@jaaydenh jaaydenh changed the title feat(site/src/pages/DeploymentSettingsPage/LicensesSettingsPage): add per-license Products section with Coder Agents price gates feat: add per-license Products section with Coder Agents price gates Aug 13, 2026
…ime claims

The backend decodes agent_runtime_hours_* claims for every license
regardless of feature set, so an Enterprise license carrying an
allocation now renders the Coder Agents product instead of being hidden
by the Premium-only condition.

Feature.Compare tie-breaks equal issued-at values on the usage period
end, so the winning-license predicate now matches the complete merged
usage period (iat/nbf/exp) plus the validated soft and hard thresholds,
not issued-at alone. The hard-limit claim validation moved into the
effective threshold computation shared by both checks.

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 9a1e2c46eb

ℹ️ 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".

@jaaydenh
jaaydenh marked this pull request as ready for review August 13, 2026 14:27
@coderagents

coderagents Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Documentation Check

This PR surfaces new user-facing licensing UI by default (no experiment flag): each license card now expands to a Products section showing Coder Workspaces seat usage and, for Premium licenses, a Coder Agents box that tracks agent_runtime_hours usage against the license allocation, including unlimited (-1), exceeded, and hard-limit states plus an upgrade CTA. The current licensing docs only describe seat consumption, so they no longer match the screen.

Updates Needed

  • docs/admin/licensing/index.md - Document the new Products section on each license card: the Coder Workspaces seat-usage box and the Premium Coder Agents box tracking agent runtime hours against the license allocation (normal, unlimited, "Agent hours exceeded", and "Hard limit exceeded" states, plus the upgrade CTA). The existing seat-consumption description and the licenses-screen.png screenshot are now incomplete for this layout.

New Documentation Needed

  • docs/reference/glossary.md - Add an entry for agent runtime hours (the Premium metered allocation driven by the agent_runtime_hours_* license claims / agent_runtime_hours entitlement). It's a new Coder Premium concept now visible in the UI and isn't in the glossary; keep it distinct from the existing Agent Workspace Build metering entry.

Note

Update: the backing entitlement PR #27985 has merged and this PR now targets main directly (no longer stacked). The deferral condition no longer applies, so the agent runtime hours docs should land with this PR (or a companion docs PR) before it merges. main currently only has auto-generated API schema entries (docs/reference/api/schemas.md), which don't cover the licensing UI or glossary; both items above remain open.


Automated review via Coder Agents

@ibetitsmike ibetitsmike left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Mux reviewed this pull request on Mike's behalf.

Reviewed exact head 9a1e2c46eb52f4b5b12547302237c50db9887781 against the PR merge-base with runtime-hours-entitlements.

Code review

Standards: PASS. The applicability helper, card decomposition, naming, types, comments, and primitive reuse follow repository conventions. I found no new standards or code-smell findings.

Spec: PASS. I traced winning-license selection across iat, nbf, and exp, plus allocation and threshold matching. Positive, unlimited, no-allocation, exceeded, and hard-limit states render consistently with the merged entitlement. Fractional usage display and destructive boundaries use the same floored tenths value, AI Governance behavior is preserved, and the Workspaces card uses active-seat data. I found no new actionable findings.

Frontend review

FE1 PASS
FE2 PASS
FE3 PASS
FE4 PASS
FE5 PASS
FE6 PASS
FE7 PASS
FE8 PASS
FE9 PASS
FE10 PASS

Storybook interactions cover keyboard access, tooltip focus and dismissal, collapsible expansion, license applicability, Enterprise claims, and all Coder Agents price-gate states. All prior review findings are addressed at this head.

@ibetitsmike ibetitsmike left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Mux approved this pull request on Mike's behalf.

Approved after code review and FE1 through FE10 frontend review found no actionable issues at this exact head.

@jaaydenh

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ad5e7d0b4

ℹ️ 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".

Base automatically changed from runtime-hours-entitlements to main August 18, 2026 05:40

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1863dc2286

ℹ️ 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".

…t usage at the allocation boundary as exceeded

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: c26d4c0581

ℹ️ 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".

@jaaydenh
jaaydenh merged commit 995d7fe into main Aug 18, 2026
26 checks passed
@jaaydenh
jaaydenh deleted the license-page-t2yd branch August 18, 2026 13:07
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 18, 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