Skip to content

feat(coderd_template): expose agents_allowed - #414

Merged
ethanndickson merged 6 commits into
codagt-716/sdk-bumpfrom
codagt-716/agents-allowed
Aug 20, 2026
Merged

feat(coderd_template): expose agents_allowed#414
ethanndickson merged 6 commits into
codagt-716/sdk-bumpfrom
codagt-716/agents-allowed

Conversation

@ethanndickson

@ethanndickson ethanndickson commented Aug 18, 2026

Copy link
Copy Markdown
Member

Expose the per-template agents_allowed flag through the coderd_template resource and data source. Terraform can now create, update, and read whether Coder Agents can use a template.

The change does not set a new minimum Coder version for existing coderd_template configurations. If the configuration omits agents_allowed, the provider does not send the field during create. Older Coder servers omit the field in responses, so the provider reads it as false, consistent with other versioned template attributes.

The PR author accepts these compatibility limits:

  • Explicit agents_allowed configuration requires Coder v2.37.0 or later. An older server will ignore the unsupported field and cause an inconsistent-result apply error.
  • The template data source reports false for agents_allowed on older servers because the API response omits the field.
  • A saved plan created before a Coder v2.37.0 upgrade can carry the synthetic false into an unrelated template update after the upgrade. This only disables Coder Agent access for that template. It does not affect ordinary workspaces or damage the template. Users can restore access by setting agents_allowed = true in a fresh plan.

Users must create a fresh Terraform plan with refresh enabled after upgrading Coder to v2.37.0. They must not apply a saved pre-upgrade plan after the upgrade.

Acceptance coverage runs only when the Coder image reports v2.37.0 or later.

Depends on #413.

Closes https://linear.app/codercom/issue/CODAGT-716/expose-agents-allowed-in-the-coderd-terraform-provider

Stack plan
  1. Update the Coder SDK and remove obsolete chat model cost configuration in chore!: bump coder/coder SDK and remove model cost settings #413.

  2. Add agents_allowed to the resource and data source, including generated documentation and version-gated acceptance coverage.

  3. Add the deployment-wide chat system prompt resource in feat(coderd_chat_system_prompt): manage the deployment-wide chat system prompt #412.

This PR was generated by Coder Agents.

@linear-code

linear-code Bot commented Aug 18, 2026

Copy link
Copy Markdown

CODAGT-716

@ethanndickson ethanndickson changed the title feat(coderd_template): expose agents_allowed feat(internal/provider): expose template agents_allowed Aug 18, 2026
@ethanndickson
ethanndickson force-pushed the codagt-716/agents-allowed branch from b98c08b to 4293f72 Compare August 18, 2026 07:04
@ethanndickson
ethanndickson marked this pull request as ready for review August 18, 2026 07:12

@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: 4293f72bf7

ℹ️ 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 internal/provider/template_resource.go
@ethanndickson
ethanndickson marked this pull request as draft August 18, 2026 07:29
@ethanndickson
ethanndickson marked this pull request as ready for review August 18, 2026 07:32
@ethanndickson

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Aug 18, 2026

Copy link
Copy Markdown

Chat: Review posted | View chat
Requested: 2026-08-19 08:00 UTC by @ethanndickson

Review history
  • R1 (2026-08-18): 16 reviewers, 7 Nit, 1 Note, 2 P2, 3 P3, COMMENT. Review
  • R2 (2026-08-18): 11 reviewers, 10 Nit, 2 Note, 2 P2, 3 P3, COMMENT. Review
  • R3 (2026-08-18): 11 reviewers, 11 Nit, 2 Note, 2 P2, 3 P3, COMMENT. Review
  • R4 (2026-08-19): 12 reviewers, 14 Nit, 2 Note, 4 P2, 3 P3, COMMENT. Review

deep-review v0.9.0 | Round 4 | c3d171a..4c41a1a

Last posted: Round 4, 23 findings (4 P2, 3 P3, 14 Nit, 2 Note), COMMENT. Review

Finding inventory

Finding inventory: PR #414

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P2 Author claims R4 resolution via PR body update (names saved-plan no-refresh upgrade edge and records author acceptance); reply is agent-generated. Panel to re-evaluate under "no agent-accepted permanence" template_resource.go:1463 Version gap: agents_allowed on <v2.37 server pins false into state and can silently disable agents after upgrade, or hard-fail with "inconsistent result after apply" when set true R1 Hisoka P1, Mafu-san P3, Meruem Note Yes
CRF-2 P2 Author fixed (4acf837) template_resource.go:1511,1557 Class-of-bug: sibling UseClassicParameterFlow.ValueBoolPointer() still ships the exact &false-on-unknown pitfall that boolPtrOrNil was written to fix; masked today by coincidence of server defaults R1 Hisoka P2, Ryosuke P4, Zoro P4, Knov Nit, Pariston Note Yes
CRF-3 P3 Author fixed (4acf837) template_resource_test.go:777 TestAccTemplateResourceAgentsAllowed never exercises the sibling UseClassicParameterFlow reconciliation the "fix" commit adds; a follow-up that drops it would break silently R1 Bisky P3 Yes
CRF-4 P3 Author fixed (4acf837) template_resource_test.go:39 TestTemplateResourceReconcileUpdateResponse never exercises the null branch of stringValueOrNull for CORSBehavior; swapping stringValueOrNull for types.StringValue in production still passes R1 Bisky P3 Yes
CRF-5 P3 Author fixed (4acf837) template_resource.go:473, template_data_source.go:190, template_resource_test.go:786-787, template_data_source_test.go:35 Version literal v2.37.0 duplicated across four call sites; oauth2 settings has a matching const oauth2ProviderSettingsMinVersion convention R1 Gon P3, Robin Nit Yes
CRF-6 Nit Author fixed (4acf837) template_resource_test.go:300 Comment // Change the active version and omit agents_allowed. misleads: cfg1..cfg6 all omit agents_allowed, so nothing about this step is distinctive re: agents_allowed R1 Bisky, Leorio, Mafuuu, Meruem, Chopper, Gon Yes
CRF-7 Nit Author fixed (4acf837) template_resource_test.go:833 ExpectNonEmptyPlan: false restates the zero value; PlanOnly: true already errors on non-empty plan R1 Bisky, Mafu-san Note, Meruem, Knov Yes
CRF-8 Nit Author fixed (4acf837) template_resource_test.go:45-58 TestTemplateResourceReconcileUpdateResponse gives both bool fields the same response value (false) and identical asserts, so a copy-paste swap of the two assignments in reconcileUpdateResponse would still pass R1 Chopper Yes
CRF-9 Nit Author fixed (4acf837) template_resource.go:1428 reconcileUpdateResponse takes codersdk.Template by value while sibling readResponse takes *codersdk.Template; needless convention drift on the same struct R1 Zoro Yes
CRF-10 Nit Panel closed R2 (5/6 accept - defensible narrow scope; CRF-13 covers the mapping asymmetry) template_resource.go:1465 TODO(ethanndickson): MaxPortShareLevel deliberately omitted comment is now understated: readResponse also skips CORSBehavior and UseClassicParameterFlow (deferred to reconcileUpdateResponse), and doesn't explain why AgentsAllowed gets the opposite treatment R1 Zoro Nit, Meruem Nit, Knov Note Yes
CRF-11 Nit Author fixed (4acf837) template_resource.go:473 vs template_data_source.go:189 Resource description says "Defaults to true"; data-source description omits it, and there's no schema Default: modifier so the "default" is really the server's R1 Knov Nit, Hisoka Note Yes
CRF-12 Nit Author fixed (4acf837) template_resource_test.go:810 cfgUnmanaged misnames the scenario: Optional+Computed+UseStateForUnknown means the field remains actively managed; the codebase reserves "unmanaged via null" for facets like coderd_user.roles R1 Meruem Yes
CRF-13 Note Author declined R4 (agent-generated); accepts fragmented mapping as "focused change" trade-off; open for panel under "no agent-accepted permanence" template_resource.go:1428 reconcileUpdateResponse, readResponse, and inline Create/Read blocks fragment server-response mapping across four different membership patterns; no rule readable off the code predicts where a new field belongs R1 Meruem Note, Pariston Note, Zoro Note Yes
CRF-14 Note Dropped by orchestrator (IsUnitTest is the established convention in this file and package) template_resource_test.go:815 Ryosuke Nit: IsUnitTest: true on a test that boots real Coder is misleading R1 Ryosuke No
CRF-15 Nit Author fixed (af41226) template_resource_test.go:76 TestTemplateResourceUseClassicParameterFlowRequests covers only UseClassicParameterFlow; the sibling AgentsAllowed request path has no boolPtrOrNil regression coverage, so swapping either call site back to .ValueBoolPointer() would not fail any test R2 Netero, Mafu-san Note Yes
CRF-16 Nit Author contested R3/R4 (agent-generated maintainer-intent claim: v2.15 compat TODO stays); open for panel template_resource.go:913 TODO(ethanndickson): Remove this once the provider requires ... v2.15.0 or later scope-lies: the client.Template GET now also feeds UseClassicParameterFlow and AgentsAllowed (v2.37+) through reconcileVersionedMetadata; a maintainer who follows the TODO at v2.15+ minimum would silently regress state reconciliation for v2.37+ fields R2 Kite Nit Yes
CRF-17 Nit Author fixed (4c41a1a) - comment now reads // ValueBoolPointer returns &false for unknown, which can accidentally send false. util.go:147 boolPtrOrNil doc comment is imprecise and vague: "ValueBoolPointer returns false for unknown" should read "&false" (mirroring stringPtrOrNil's &""); "can accidentally send a value" does not name the disease (pointer non-nil -> JSON emits -> server persists false) R2 Gon Nit, Leorio Nit Yes
CRF-18 Note Panel closed R3 (5-1 accept - Razor traced Optional+Computed framework contract: omitted config leaves plan value Unknown against known state, PlanOnly: true catches modifier removal regardless of state value; Pariston withdrew) template_resource_test.go:885 TestAccTemplateResourceAgentsAllowed step 4 tests preservation of true after omission, but because the server default is also true, "preserves state" and "resets to server default" are indistinguishable; a naive Computed-only attribute would pass. Moving PlanOnly to run after cfgFalse (state=false, default=true) would make UseStateForUnknown's contribution observable R2 Pariston Note Yes
CRF-19 Note Author fixed (PR body updated R3, further tightened R4) PR description "Omitted values use the server response, which keeps older Coder deployments compatible" overclaims relative to acknowledged CRF-1 failure modes: on pre-v2.37 the omitted-field decodes as false, state pins false, and subsequent Update PATCHes agents_allowed: false; that is delayed silent-drift, not compatibility R2 Mafu-san Note Yes (body)
CRF-20 Nit Author fixed (4c41a1a) - table now uses distinct values/expectations per field across four subtests ("unknown and true", "true and unknown", "null and false", "false and null") template_resource_test.go:99 TestTemplateResourceBoolRequests (R3 fix for CRF-15) binds UseClassicParameterFlow and AgentsAllowed to the same tc.value in the model, so swapping the two boolPtrOrNil(...) field assignments in toUpdateRequest or toCreateRequest still passes; same class as CRF-8 applied to the request paths R3 Netero Yes
CRF-21 P2 Author declined R4 (agent-generated); says data-source read is explicit use and old-server collapse matches resource compatibility decision; open for panel under "no agent-accepted permanence" template_data_source.go:342 Data source sibling of CRF-1: data.AgentsAllowed = types.BoolValue(template.AgentsAllowed) inherits the plain-bool decode pathology. On pre-v2.37 the data source silently emits false for a template whose server default is true; unlike CRF-1 this reaches users who explicitly opt in to reading the field R3 Mafuuu Yes
CRF-22 Nit Author declined R4 (agent-generated); says schema and generated docs state v2.37+ and PR body documents old-server behavior; open for panel under "no agent-accepted permanence" template_data_source.go:190 Data-source schema description says only "Requires a Coder deployment running v2.37.0 or later" without stating the pre-v2.37 decode behavior; the generated data-source doc does not carry the PR body's scope statement, and a data source has no "explicit use" axis R3 Mafuuu Yes
CRF-23 P2 Author declined R4 (agent-generated); says apply behavior on unsupported servers is outside accepted compatibility scope; open for panel under "no agent-accepted permanence" template_resource.go:920 agents_allowed = true on Coder <v2.37 gets Provider produced inconsistent result after apply. This is a bug in the provider... instead of a diagnostic naming the cause. Sibling ai_provider already solved this class with checkBedrockRoleARNDropped/checkBedrockProtocolDropped targeted diagnostics R3 Leorio Yes
CRF-24 Nit Author fixed (4c41a1a) - both drive-by punctuation edits reverted template_resource_test.go:344,358 Drive-by punctuation edits to two unrelated test-step comments (Append version. Creates a fifth version., Change the active version.) introduce inconsistency rather than resolve it; violates AGENTS.md "no unrelated refactors" R3 Gon Yes
CRF-25 Nit Author fixed (4c41a1a) - subtest renamed to "overwrites all versioned fields" template_resource_test.go TestTemplateResourceReconcileVersionedMetadata subtest name "values" says nothing about what it tests; sibling "empty CORS behavior" names the scenario R3 Leorio Yes

Contested and acknowledged

CRF-1 (P2, template_resource.go:1463) - Version gap for agents_allowed on <v2.37 Coder servers

  • Finding: codersdk.Template.AgentsAllowed is plain bool with no omitempty. On a pre-v2.37 server the response omits the field, the client decodes it as false, and readResponse/reconcileVersionedMetadata pin false into state. Two failure modes: agents_allowed = true in config hard-fails at apply time with "Provider produced inconsistent result after apply", and the omitted case creates a silent-drift cascade after the operator upgrades Coder (saved-plan CI workflows that skip refresh will PATCH agents_allowed: false on the next update to any other attribute, disabling agents on every managed template with no plan-visible diff).
  • Author R2 defense: "The pre-v2.37 plain-boolean collapse is real, but it matches the established behavior for similar versioned template attributes (MaxPortShareLevel, CORSBehavior, UseClassicParameterFlow). The schema documentation states that explicit use requires Coder v2.37.0 or later. We did not add a provider-wide version cache or change old-server state semantics."
  • Panel R3 re-raise (7-0): Pariston cited AGENTS.md verbatim on validator-over-apply-error; scaffolding already exists (CoderdProviderData caches Entitlements() at Configure(), provider.go:44,211; two-line extension adds BuildInfo() on the same call). Four reviewers (Hisoka, Kite, Meruem, Razor) independently traced the silent-drift cascade against the current code. Mafu-san flagged that the R2/R3 "Maintainer decision:" prefix arrived via Response generated by Coder Agents, not a distinct human-authored sanction. Panel asked for either the BuildInfo cache + plan-time validator or a visible human-authored acceptance naming the omitted-config scenario.
  • Author R4 reply (PRRC_kwDOMGJiIM7jKPjp, agent-generated): "Resolved by a human-requested PR body update. The body now names the saved-plan, no-refresh upgrade edge and records that the PR author accepts it. Existing configurations do not gain a v2.37 minimum. Explicit use still requires Coder v2.37.0 or later. Response generated by Coder Agents."
  • R4 PR body now reads: "A saved plan created before a Coder v2.37.0 upgrade and applied after the upgrade without refresh can carry that false value into an unrelated template update. The PR author accepts this narrow compatibility edge."
  • Panel decision needed R4. The body update names the saved-plan/no-refresh omitted-config scenario the panel asked for. The reply that presents the change is agent-generated. Under the skill's "no agent-accepted permanence" rule, the panel must judge whether the PR body sentence "The PR author accepts this narrow compatibility edge" is a sufficient visible human-authored acceptance, or whether a distinct human sign-off (linked issue, human-authored comment, non-agent PR-body byline) is still required.

CRF-13 (Note, template_resource.go:1428) - Fragmented codersdk.Template -> state mapping

  • Finding: After the PR, readResponse, reconcileVersionedMetadata, and inline blocks in Create and Read map codersdk.Template into state under four different membership patterns; no rule readable off the code predicts where a new field belongs. Structural fix: collapse to one applyServerResponse(*codersdk.Template), and let Create overwrite fields it must PATCH after the compat check.
  • Author R2 defense: "We did not add a broad mapper in this feature PR because Create must preserve planned values until its compatibility PATCH decisions finish. The focused helper is now named reconcileVersionedMetadata; a complete authoritative mapping belongs in separate work with final post-create reconciliation."
  • Panel R3 re-raise (3-2): Meruem, Pariston, Mafuuu re-raise on the Read-side: substituting data.reconcileVersionedMetadata(&template) for Read's lines 743-745 is byte-for-byte equivalent; the R2 rename explicitly narrowed the helper's scope and the second caller was one line away. Kite, Razor close on the Create-side compat argument. Hisoka: "weak accept, ticket wanted."
  • Author R4 reply (PRRC_kwDOMGJiIM7jKQbS, agent-generated): "No change. The PR author accepts the existing response-mapping structure for this focused change. Create must preserve planned values for compatibility PATCH decisions. Read-side helper reuse is an optional maintainability cleanup, not required for agents_allowed. Response generated by Coder Agents."
  • Panel decision needed R4. No ticket linked, no visible human-authored acceptance in the PR body for this specific finding (the R4 body update names only CRF-1's compatibility edge). Reply is agent-generated. Under "no agent-accepted permanence," the panel must decide whether the pattern of accepted "focused change" text is a maintainer-visible resolution or a repeat of the R3 pattern that triggered the panel's original re-raise.

CRF-16 (Nit, template_resource.go:913) - v2.15.0 TODO scope-lies

  • Finding: TODO(ethanndickson): Remove this once the provider requires a Coder deployment running v2.15.0 or later was accurate before this PR when the client.Template GET only served the CRF-2378 legacy compat path. The GET at line 915 now also feeds reconcileVersionedMetadata, which reconciles MaxPortShareLevel, CORSBehavior, UseClassicParameterFlow, and AgentsAllowed (v2.37+). A maintainer who follows the TODO at a hypothetical v2.15+ minimum would silently regress state reconciliation for v2.37+ fields.
  • Author R3 defense (IC_kwDOMGJiIM8AAAABPZyPoA, agent-generated): "No change. The maintainer requested that the existing v2.15 compatibility TODO remain. This PR does not introduce a new minimum Coder version for coderd_template. The GET still serves its original compatibility purpose, and the reconciliation now also uses its authoritative response for the versioned fields. Response generated by Coder Agents."
  • Panel R3 re-raise (5-1): Razor traced that templateResp has only one call site (line 920, the reconcile), so the TODO's stated removal criterion no longer describes the block below it. Kite (original raiser) closes from their own side on the compile-safety argument (deleting the block would break line 920). The panel majority weighs the misleading text over the compile safety net.
  • Author R4 state: no code change to line 913. The PR body update does not address this finding.
  • Panel decision needed R4. Author defense is agent-generated with a claim of maintainer intent that has no visible human sanction. Under "no agent-accepted permanence," the panel decides whether the R4 status counts as substantive engagement or a repeat of the R3 pattern.

CRF-21 (P2, template_data_source.go:342) - Data-source sibling of CRF-1

  • Finding: data.AgentsAllowed = types.BoolValue(template.AgentsAllowed) inherits the CRF-1 pathology: on pre-v2.37 the server omits the JSON field, codersdk.Template.AgentsAllowed (plain bool) decodes to false, and the data source reports false for a template whose server-side default is true. Unlike CRF-1's UseStateForUnknown-fed drift, this reaches users who explicitly opt in to reading the field (data.coderd_template.foo.agents_allowed per the example), so the "just don't set it" mitigation does not apply. Fix: same shape as CRF-1 (BuildInfo cache + gate the write in Read), or upstream codersdk.Template.AgentsAllowed to *bool with omitempty.
  • Author R4 reply (PRRC_kwDOMGJiIM7jKPuz, agent-generated): "No code change. Reading agents_allowed from the data source is explicit use of this new field. Its schema requires Coder v2.37.0 or later. The accepted old-server Boolean collapse matches the resource compatibility decision. Response generated by Coder Agents."
  • Panel decision needed R4. The reply is agent-generated. The PR body update names the resource-side saved-plan omitted-config scenario, not the data-source explicit-read-returns-false scenario. Panel decides whether the resource-side acceptance carries to the data source, and whether the reply counts as a visible human-authored acceptance under "no agent-accepted permanence."

CRF-22 (Nit, template_data_source.go:190) - Data-source description omits pre-v2.37 decode behavior

  • Finding: The R3 PR body clarifies "Explicit use of agents_allowed requires Coder v2.37.0 or later" (CRF-19 fix), but a data source has no "explicit use" axis: it is always read. On pre-v2.37 the data source silently emits false without a diagnostic. State the failure mode in the description: on Coder deployments before v2.37.0 the field is absent from the API response and this data source therefore returns false.
  • Author R4 reply (PRRC_kwDOMGJiIM7jKPzB, agent-generated): "No change. The data-source schema and generated documentation state that agents_allowed requires Coder v2.37.0 or later. The PR body also documents the old-server response behavior. Response generated by Coder Agents."
  • Panel decision needed R4. Reply is agent-generated. Panel decides whether the schema and PR-body statements are sufficient to convey the pre-v2.37 data-source return value.

CRF-23 (P2, template_resource.go:920) - Opaque inconsistent result error on unsupported servers

  • Finding: An operator with agents_allowed = true on Coder <v2.37 sends {"agents_allowed": true} via boolPtrOrNil, the server ignores the unknown JSON key, the response omits it, the client decodes false, readResponse/reconcileVersionedMetadata writes false into state, and the framework raises Provider produced inconsistent result after apply. This is a bug in the provider. The cause (server predates the setting) and the fix (upgrade Coder or drop the attribute) are absent from the diagnostic. Sibling ai_provider resource already solved this exact class with checkBedrockRoleARNDropped (line 687) and checkBedrockProtocolDropped (line 706), which compare configured value to server response and emit "The Coder server accepted the request but did not persist X" as an AddAttributeError. Prescription: add checkAgentsAllowedDropped(config, template, diags) mirror, call from Create and Update. This ships even if CRF-1's plan-time validator is deferred; the two remedies compose.
  • Author R4 reply (PRRC_kwDOMGJiIM7jKP3h, agent-generated): "No change. Explicit agents_allowed configuration requires Coder v2.37.0 or later, as documented in the schema, generated documentation, and PR body. Apply behavior on unsupported servers is outside the accepted compatibility scope. Response generated by Coder Agents."
  • Panel decision needed R4. Reply is agent-generated. The R4 PR-body acceptance sentence names the saved-plan omitted-config edge (CRF-1); it does not name the explicit-true apply-fail path this finding addresses. Panel decides whether "outside the accepted compatibility scope" extends to opaque diagnostics for a class the sibling resource already solved, and whether the reply counts as a visible human decision.

Round log

Round 1

Netero: no findings. LOC analysis: 176 additions (39 prod, 137 test), no Law spawn. Panel: 16 reviewers (bisky, hisoka, mafu-san, mafuuu, pariston, ging-go, gon, leorio, komugi, meruem, ryosuke, robin, knov, luffy, zoro, chopper). Ging-go, komugi, luffy returned no findings. 13 unique findings, 1 dropped, 13 posted. Reviewed against c3d171a..e9b2cf3.

Round 2

Churn guard: PROCEED (10 addressed, 2 acknowledged, 1 contested, 0 silent). Author pushed 4acf837 addressing CRF-2 through CRF-9, CRF-11, CRF-12. Netero: 1 new Nit (CRF-15, request-side sibling coverage gap). Panel: 11 reviewers (bisky, hisoka, mafu-san, mafuuu, pariston, ging-go, gon, leorio, komugi, meruem + kite wildcard). Bisky, ging-go, komugi returned no findings. Panel decisions: CRF-1 re-raised (P2, new directional-bias evidence + ticketless-deferral concern), CRF-10 closed (5/6 accept), CRF-13 re-raised (new evidence Read-side collapse trivial + ticketless-deferral concern). New: CRF-15 (Netero + Mafu-san concur), CRF-16 (Kite), CRF-17 (Gon + Leorio), CRF-18 (Pariston), CRF-19 (Mafu-san, body only). Reviewed against c3d171a..4acf837.

Round 3

Churn guard: PROCEED. Author pushed af41226: added AgentsAllowed coverage to TestTemplateResourceBoolRequests (CRF-15), rewrote boolPtrOrNil comment (partial CRF-17), narrowed PR body compatibility claim (CRF-19). Netero: 1 new Nit (CRF-20, request test swap invariance). Panel: 11 reviewers (bisky, hisoka, mafu-san, mafuuu, pariston, gon, leorio, komugi, meruem, kite + razor wildcard). Bisky, komugi returned no findings. Panel decisions: CRF-1 re-raised 7-0 (new AGENTS.md evidence + agent-generated-decision concern), CRF-13 re-raised 3-2, CRF-16 re-raised 5-1, CRF-17 re-raised (part b factually wrong), CRF-18 closed 5-1 accept (Razor traced Optional+Computed framework contract; Pariston withdrew). New: CRF-20 (Netero + panel), CRF-21 (Mafuuu), CRF-22 (Mafuuu), CRF-23 (Leorio), CRF-24 (Gon), CRF-25 (Leorio). Reviewed against c3d171a..af41226.

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.

@coder-agents-review coder-agents-review 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.

Two commits, one feature. The agents_allowed plumbing is clean end-to-end and Netero's mechanical sweep found nothing. boolPtrOrNil earns its keep, framework ValueBoolPointer() returns &false for Unknown and the helper intercepts at the pointer boundary, four table-tested cases, right primitive at the right layer. The reconcileUpdateResponse extraction closes the pre-existing asymmetry where Update didn't reconcile UseClassicParameterFlow from the server response, and TestAccTemplateResourceAgentsAllowed round-trips omitted, false, true, and unmanaged. EqualTemplateMetadata is extended so an agents_allowed-only change triggers PATCH.

Two P2 findings worth naming before merge:

  1. The version-gap failure mode for agents_allowed on a <v2.37 Coder server. codersdk.Template.AgentsAllowed is a plain bool with no omitempty, so an older server that omits the field decodes to false; readResponse/reconcileUpdateResponse then pin false into state. Two consequences: agents_allowed = true in config hard-fails at apply time with "Provider produced inconsistent result after apply", and the omitted case creates a silent-drift cascade after the operator upgrades Coder (saved-plan CI workflows that skip refresh will PATCH agents_allowed: false on the next update to any other attribute, disabling agents on every managed template with no plan-visible diff). The docs warn Requires a Coder deployment running v2.37.0 or later, but nothing enforces it, and the PR body claim of "keeps older Coder deployments compatible" only covers the omitted case, not the pinned-state cascade. The failure class matches MaxPortShareLevel, CORSBehavior, and UseClassicParameterFlow on their respective minimums, but this PR could gate at Configure() time via the existing BuildInfo call.

  2. The class-of-bug the PR just diagnosed still ships in the sibling. use_classic_parameter_flow has the identical schema shape as agents_allowed (Optional+Computed+UseStateForUnknown, no Default:) and still uses r.UseClassicParameterFlow.ValueBoolPointer() at both toCreateRequest (line 1557) and toUpdateRequest (line 1511). It is masked today only because the current server default coincidentally matches false; the SDK's own comment warns the default may flip. AGENTS.md rule: "one correction implies every instance." Routing both call sites through boolPtrOrNil would make the compensating dance at 686-701 strictly narrower.

Process observation the diff hides: the fix(coderd_template): reconcile metadata after update commit is a strict behavior change for UseClassicParameterFlow on Update, not just an extraction. Pre-PR, Update only wrote back MaxPortShareLevel and CORSBehavior; post-PR, UseClassicParameterFlow is also reconciled from the server response. Neither the PR description nor the fix commit body mention this. On v2.37+ Coder the change is invisible; against a server that previously ignored the field it converts silent drift into an "inconsistent result after apply" error at Update time. Strict improvement, but a future bisect for a UseClassicParameterFlow regression will land on feat: expose template agents_allowed (#414) with nothing in the log explaining why. One sentence in the PR body or the fix commit body naming the second field would close the gap.

Zoro's line on the sibling put it well: "That is a latent, not absent, bug: a coincidence of defaults, not a design invariant, is what saves you."

Counts: 2 P2, 3 P3, 7 Nit, 1 Note.

🤖 This review was automatically generated with Coder Agents.

Comment thread internal/provider/template_resource.go Outdated
Comment thread internal/provider/template_resource.go Outdated
Comment thread internal/provider/template_resource_test.go
Comment thread internal/provider/template_resource_test.go
Comment thread internal/provider/template_resource.go Outdated
Comment thread internal/provider/template_resource.go Outdated
Comment thread internal/provider/template_resource.go
Comment thread internal/provider/template_data_source.go Outdated
Comment thread internal/provider/template_resource_test.go Outdated
Comment thread internal/provider/template_resource.go Outdated
@ethanndickson

Copy link
Copy Markdown
Member Author

/coder-agents-review

@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

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

Reviewed commit: 4acf8371c4

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

Choose a reason for hiding this comment

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

R2 delivered a proportional, focused commit. 4acf837 addressed 10 of 13 R1 findings at the root, not just at the reported call sites: boolPtrOrNil was extended to the sibling UseClassicParameterFlow in both toCreateRequest and toUpdateRequest, the reconcile helper was renamed to reconcileVersionedMetadata and takes a pointer receiver matching readResponse, the templateAgentsAllowedMinVersion const now supplies all four call sites, and the reconciliation unit test seeds distinguishing values so any pairwise swap in the mapping fails. No scope drift, no drive-by edits.

Panel decisions on the three findings still open at the start of R2:

  • CRF-1 (P2) re-raised. The author acknowledged the pre-v2.37 plain-boolean collapse and defended it as "matches established behavior for similar versioned template attributes." The panel voted 2 P2 re-raises (Mafuuu, Pariston) with new differentiating evidence, plus 4 concurring reviewers (Hisoka, Meruem, Kite, Mafu-san) that the "consistent with siblings" defense does not cover agents_allowed's specific silent-drift mode. Pariston compared the four versioned attributes: MaxPortShareLevel fails loudly (invalid enum), CORSBehavior is structurally immune (stringValueOrNull maps the absent field to null), UseClassicParameterFlow is a functional no-op (phantom-false matches server default), and AgentsAllowed is the first attribute in the class whose collapse produces a valid-but-wrong value that flips a feature default off with no diagnostic. Mafuuu named the shape sharply: the phantom-false is the opposite of the post-upgrade server default. Human decision needed. No ticket linked. File a ticket for a provider-wide version gate at Configure() (mirroring the existing Entitlements() cache) with a plan-time validator that rejects agents_allowed on pre-v2.37 deployments, or explicitly accept the gap with a maintainer sign-off. "Matches the pattern" is not a resolution once the differentiating consequence is on the table.

  • CRF-10 (Nit) closed. Panel accepted the author's narrow-scope defense 5/6: the TODO explains the specific case of MaxPortShareLevel; the structural pressure sits on CRF-13 (the mapping asymmetry itself), not on this comment. The rename to reconcileVersionedMetadata is now the readable rule.

  • CRF-13 (Note) re-raised. Meruem's new evidence: substituting data.reconcileVersionedMetadata(&template) for Read's lines 743-745 is a byte-for-byte equivalent replacement. Read has no compat logic; the R2 rename delivered a helper whose scope is one caller when a second was trivially available. The author's Create-side compat argument (planned values must survive until PATCH decisions finish) is valid for Create and does not carry Read. Mafuuu, Pariston, Mafu-san concur that ticketless "deferred to separate work" is a drop under the review contract, not a deferral. Human decision needed. No ticket linked. File a ticket for at minimum the Read-side collapse and the accompanying MaxPortShareLevel deliberately omitted TODO cleanup, or accept the fragmentation with a maintainer sign-off.

New this round: CRF-15 (Netero + Mafu-san concur, request-side sibling coverage gap for AgentsAllowed), CRF-16 (Kite, stale TODO scope at line 913 whose deletion at a hypothetical v2.15+ minimum would silently regress state reconciliation for v2.37+ fields), CRF-17 (Gon + Leorio, boolPtrOrNil doc comment is imprecise and vague), CRF-18 (Pariston, TestAccTemplateResourceAgentsAllowed step 4 tests preservation of true when the server default is also true, so UseStateForUnknown's contribution is not observable; swapping the step to run after cfgFalse would fix this).

Process note the diff does not carry: the PR description still reads "Omitted values use the server response, which keeps older Coder deployments compatible." Given the R2 acknowledgment on CRF-1, that sentence overclaims relative to what ships. The pre-v2.37 behavior for omitted config pins false into state and PATCHes false back on the next Update, which is silent-drift, not compatibility. A future maintainer reads the description, not the panel debate. Update the description or link the CRF-1 tracking ticket.

Mafuuu's line captured the CRF-1 disagreement: "the phantom-false is the opposite of the post-upgrade server default."

Counts: 2 P2 re-raised, 1 Nit closed, 1 Note re-raised, 2 new Nits, 1 new Note, and 10 R1 fixes verified.


internal/provider/template_resource.go:913

Nit [CRF-16] TODO(ethanndickson): Remove this once the provider requires a Coder deployment running v2.15.0 or later now scope-lies about the block below it. (Kite)

Kite: "The client.Template(ctx, templateID) GET that follows the TODO existed because UpdateTemplateMeta's response on pre-v2.15 Coder omitted MaxPortShareLevel. After this PR the GET also feeds AgentsAllowed (added in v2.37) and the newly-routed UseClassicParameterFlow through reconcileVersionedMetadata. A maintainer who follows the TODO's instruction at a hypothetical v2.15+ minimum would delete the GET (and the reconcile), silently regressing state reconciliation for v2.37+ fields."

Update the TODO to name the actual condition ("once the update response is authoritative for MaxPortShareLevel/CORSBehavior/UseClassicParameterFlow/AgentsAllowed"), or drop the version reference and describe what the block does.

🤖

🤖 This review was automatically generated with Coder Agents.

Comment thread internal/provider/template_resource_test.go Outdated
Comment thread internal/provider/util.go
Comment thread internal/provider/template_resource_test.go
@ethanndickson ethanndickson changed the title feat(internal/provider): expose template agents_allowed feat(coderd_template): expose agents_allowed Aug 18, 2026

Copy link
Copy Markdown
Member Author

CRF-16: No change. The maintainer requested that the existing v2.15 compatibility TODO remain. This PR does not introduce a new minimum Coder version for coderd_template. The GET still serves its original compatibility purpose, and the reconciliation now also uses its authoritative response for the versioned fields. Response generated by Coder Agents.

@ethanndickson

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review coder-agents-review 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.

R3 delivered a proportional test-side fix (af41226) and a substantive PR body rewrite. Three findings closed: CRF-15 (request-side coverage for AgentsAllowed), CRF-17 (partial: boolPtrOrNil comment now names the pointer), CRF-19 (PR body narrows the compatibility claim to explicit-use only). CRF-18 is also closed by the panel: Pariston withdrew after tracing the framework contract; Razor verified that removing UseStateForUnknown from the Optional+Computed attribute leaves the plan value Unknown against a known state, so PlanOnly: true catches modifier removal at step 4 regardless of which value happens to sit in state. Author's plan-shape defense holds.

Panel re-raises four findings this round.

  • CRF-1 (P2) re-raised 7-0. Pariston brought new AGENTS.md evidence: "If an invariant is decidable from config + prior state, enforce it in a validator, ValidateConfig, or plan modifier instead of returning an error from Create()/Update(), a failed apply is strictly worse UX than a failed plan." The scaffolding already exists: CoderdProviderData caches Entitlements() at Configure() (provider.go:44,211); a two-line extension adds BuildInfo() on the same call and exposes a RequireServerVersion(min) helper. Kite, Meruem, Razor, and Hisoka independently traced the silent-drift cascade against the current code: on <v2.37 create-with-omitted, state pins false; on the first refresh-skipping Update after upgrade, boolPtrOrNil(BoolValue(false)) = &false PATCHes agents_allowed: false, silently disabling agents on every managed template. The R3 body rewrite narrows the compatibility claim to explicit-use only; it does not describe or accept the omitted-config silent-drift cascade. Mafu-san also flagged that the R3 "Maintainer decision:" prefix is delivered by an agent-generated reply ("Response generated by Coder Agents") from the maintainer's account without a distinct human-authored sanction, so the panel-required condition is not visibly satisfied. Human decision needed. File a ticket for the BuildInfo cache + plan-time validator (or land it in this PR), or add a visible human-authored acceptance to the PR body that names the omitted-config silent-drift scenario.

  • CRF-13 (Note) re-raised 3-2. Panel split. Kite and Razor close accepting the author's Create-side compat argument. Meruem, Pariston, and Mafuuu re-raise on the Read-side: substituting data.reconcileVersionedMetadata(&template) for Read's lines 743-745 is byte-for-byte equivalent; the R2 rename to reconcileVersionedMetadata explicitly narrowed the helper's scope, and the trivial second caller was one line away in the same PR. Under "reviewer disagreement is doubt, higher wins," re-raise stands. Hisoka: "weak accept, ticket wanted." Human decision needed. File a ticket for the Read-side collapse (or land it in this PR), or accept the fragmentation with a visible human-authored sanction.

  • CRF-16 (Nit) re-raised 5-1. Panel notes the TODO says "Remove this once the provider requires ... v2.15.0 or later," but the client.Template GET at line 915 now feeds reconcileVersionedMetadata, which reconciles MaxPortShareLevel, CORSBehavior, UseClassicParameterFlow, and AgentsAllowed. Razor traced that templateResp has only one call site (line 920, the reconcile), so the TODO's stated removal criterion no longer describes the block below it. Author's R3 defense concedes the scope shift while declining to update the text. Kite (original raiser) closes from their side on the argument that deleting lines 915-919 would break line 920's compilation, forcing engagement. The panel majority weighs the misleading text over the compile safety net. Fix: update the TODO to name the actual criterion (e.g., "once the update response is authoritative for all versioned template metadata") or drop the version reference.

  • CRF-17 (Nit) re-raised. The R3 rewrite fixed part (a) ("a pointer to false" now matches stringPtrOrNil's &"" convention) but introduced a factually wrong claim: "sends a deferred value in the request." Hisoka, Mafu-san, Leorio, and Razor independently verified that in this framework, "deferred" refers to resource.NewDeferredResponse, an operation postponed because inputs are unknown; the mechanism here is the opposite (the unknown is eagerly emitted as false and persisted). Suggested wording that mirrors stringPtrOrNil and names the mechanism: // ValueBoolPointer returns &false for unknown, which can accidentally send false.

Six new findings this round.

  • CRF-20 (Nit, Netero + panel): TestTemplateResourceBoolRequests (added in R3 to close CRF-15) binds UseClassicParameterFlow: tc.value and AgentsAllowed: tc.value in the same model; a swap of the two boolPtrOrNil(...) assignments passes every subtest. Same class as CRF-8, applied to the request paths. Fix: distinct values in the model, or split into two tables.
  • CRF-21 (P2, Mafuuu): Data source sibling of CRF-1. data.AgentsAllowed = types.BoolValue(template.AgentsAllowed) at template_data_source.go:342 inherits the plain-bool decode pathology. Blast radius: users who explicitly reference data.coderd_template.foo.agents_allowed (per the example data-source.tf) on pre-v2.37 propagate false into cloned template config.
  • CRF-22 (Nit, Mafuuu): Data-source schema description at template_data_source.go:190 says "Requires a Coder deployment running v2.37.0 or later" without stating the pre-v2.37 decode behavior. A data source has no "explicit use" axis (it is always read), so the resource-side scope narrowing does not carry.
  • CRF-23 (P2, Leorio): The agents_allowed = true on pre-v2.37 apply-fail surfaces as "Provider produced inconsistent result after apply. This is a bug in the provider," without naming the cause or the fix. The sibling ai_provider resource already solved this class: checkBedrockRoleARNDropped (ai_provider_resource.go:687) and checkBedrockProtocolDropped (line 706) compare configured vs response and emit a targeted "server accepted the request but did not persist X" diagnostic. Mirror as checkAgentsAllowedDropped(config, template, diags) called from Create and Update.
  • CRF-24 (Nit, Gon): Drive-by punctuation edits to two pre-existing test-step comments (template_resource_test.go:344, :358) that are unrelated to agents_allowed and inconsistent with sibling comments in the same table. AGENTS.md: "Touch only what the task requires. No unrelated refactors, renames, or formatting churn." Revert.
  • CRF-25 (Nit, Leorio): TestTemplateResourceReconcileVersionedMetadata subtest name "values" says nothing about what it tests. Rename to describe the behavior (e.g., "overwrites all fields with response") to match the sibling's scenario-naming shape.

Hisoka's line captured the R3 disposition on CRF-1: "The description rewrite narrates the scope; the code trap is intact."

Counts: 4 re-raised (2 need a ticket or human sanction), 1 closed, 6 new, 4 R2/R3 fixes verified.


internal/provider/template_resource.go:913

Nit [CRF-16] Panel re-raise (5-1) with new evidence. (Hisoka, Mafu-san, Mafuuu, Meruem, Razor re-raise; Kite closes from their own side; Pariston as-Nit)

Razor traced the GET's uses: templateResp (returned at line 915) is referenced only once, at line 920 (newState.reconcileVersionedMetadata(&templateResp)). The TODO's stated removal criterion (v2.15+ minimum) no longer describes the block below it, which now reconciles MaxPortShareLevel (v2.15+), CORSBehavior (v2.26+), UseClassicParameterFlow, and AgentsAllowed (v2.37+). The author's R3 defense concedes the scope shift ("the reconciliation now also uses its authoritative response for the versioned fields") while declining to update the text.

Kite (original raiser) closes on the argument that deleting lines 915-919 would break line 920's compilation, forcing engagement; the majority weighs the misleading TODO over the compile safety net because the maintainer following the TODO's letter could delete both blocks together and silently regress state reconciliation for the v2.26+/v2.37+ fields.

Meruem's concrete rewrite: // client.Template GET here reconciles versioned fields (max_port_share_level, cors_behavior, use_classic_parameter_flow, agents_allowed) that Update responses may not reflect on older servers. Remove only once every versioned field here is guaranteed authoritative in the update response. Naming the fields makes the deletion trap impossible to trigger.

🤖

🤖 This review was automatically generated with Coder Agents.

Comment thread internal/provider/template_resource_test.go Outdated
Comment thread internal/provider/template_data_source.go
Comment thread internal/provider/template_data_source.go
Comment thread internal/provider/template_resource.go
Comment thread internal/provider/template_resource_test.go Outdated
Comment thread internal/provider/template_resource_test.go Outdated

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review coder-agents-review 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.

R4 delivered a clean, proportional test-side commit (4c41a1a). Four findings verified fixed at their root: CRF-17 (boolPtrOrNil comment now &false, which can accidentally send false, matching stringPtrOrNil's shape), CRF-20 (TestTemplateResourceBoolRequests uses distinct values and per-field expected pointers across four subtests; swap of either request-side boolPtrOrNil(...) assignment fails a specific subtest), CRF-24 (two drive-by punctuation edits reverted byte-for-byte to base state), CRF-25 (subtest renamed from "values" to "overwrites all versioned fields"). Netero: no findings.

Six findings are re-raised with new R4 evidence.

  • CRF-1 (P2) partial-acceptance evaluation. The R4 PR body now names the saved-plan/no-refresh omitted-config scenario the R3 panel asked for (The PR author accepts this narrow compatibility edge). That covers one downstream consequence of the plain-bool decode. Two other consequences of the same premise remain unaccepted anywhere in the diff or PR body: explicit agents_allowed = true on <v2.37 (CRF-23) and the data-source silent-false on <v2.37 (CRF-21). The R4 reply carrying the body update is signed Response generated by Coder Agents. The panel sees the body sentence as substantive (Kite: accept the saved-plan scope; Meruem, Knov, Pariston, Mafuuu: not sufficient because the scope covers only one of the three known failure modes). Under "no agent-accepted permanence," a human decision that names the two remaining scenarios is still required, either by extending the PR body sentence to name them, by linking a follow-up ticket per accepted scenario, or by landing the two-line BuildInfo cache + plan-time validator that closes the class at its source (CoderdProviderData.Configure() already caches Entitlements() at provider.go:44,211; BuildInfo() fits the same idiom).
  • CRF-13 (Note) re-raised with new R4 evidence. AgentsAllowed is now written twice: once at reconcileVersionedMetadata (template_resource.go:1434) and again at readResponse (template_resource.go:1465). The R2 rename explicitly narrowed the helper's scope; this PR then routed AgentsAllowed through both helpers under different membership rules. A fifth versioned attribute now has five possible homes (readResponse-only, reconcileVersionedMetadata-only, both, Read-inline, Create-compat-block). The R4 reply restates the R2 Create-side compat defense and does not engage this new double-write evidence.
  • CRF-16 (Nit) re-raised. The R3 5-1 panel re-raise cited Razor's trace that templateResp has a single call site at line 920, and that following the TODO's v2.15.0 criterion would silently regress state reconciliation for v2.37+ fields. The R4 delta does not touch line 913, and no new author reply engages the R3 evidence. Fix cost: rewrite the TODO to name the actual criterion (e.g., once the update response is authoritative for max_port_share_level, cors_behavior, use_classic_parameter_flow, agents_allowed). No behavior change.
  • CRF-21 (P2) re-raised 6-0. The R4 defense (Reading agents_allowed from the data source is explicit use) conflates data-source read with attribute reference: Read runs on every data-source lookup regardless of whether the operator references .agents_allowed downstream. On <v2.37 the write emits false for a template whose server default is true, with no diagnostic. The R4 PR body acceptance is scoped to the resource-side saved-plan omitted-config edge; the data-source explicit-read scenario is not named and cannot be inherited by scope expansion in an agent-signed reply. Minimum-viable fix: gate the write behind a BuildInfo version check (or upstream codersdk.Template.AgentsAllowed to *bool with omitempty).
  • CRF-22 (Nit) re-raised 5-0. The R4 defense points at the PR body; users read the generated docs/data-sources/template.md, not the PR body. The current schema description promises "Requires a Coder deployment running v2.37.0 or later" and does not state what the pre-v2.37 read returns. One-line append flows through make gen at no schema cost: On Coder deployments before v2.37.0 the field is absent from the API response, and this data source therefore returns false.
  • CRF-23 (P2) re-raised 7-0. The sibling ai_provider_resource.go already solved this class with checkBedrockRoleARNDropped (line 687) and checkBedrockProtocolDropped (line 706): compare configured value to server response, emit AddAttributeError naming the version gap. The R4 defense (outside the accepted compatibility scope) is a scope restatement that does not engage the copy-shape prior art in the same repository. Prescription: add checkAgentsAllowedDropped(config, template, diags), call from Create after readResponse at line 628 and from Update after client.Template at line 915 before reconcileVersionedMetadata. Ships independent of CRF-1; the two remedies compose.

Two new findings this round.

  • CRF-26 (Nit, Gon). TestTemplateResourceBoolRequests subtest names encode field pairs positionally ("unknown and true", "true and unknown"). The reader must open the table to map each value to a field. The file's own convention names the scenario (TestTemplateResourceReconcileVersionedMetadata uses "overwrites all versioned fields"; agents_model_resource_test.go uses "whitespace and key order"). Rewrite to name both fields, e.g. "classic unknown, agents true".
  • CRF-27 (Nit, Leorio). reconcileVersionedMetadata ships without a doc comment. The rule that readResponse and reconcileVersionedMetadata together cover the versioned fields (with AgentsAllowed written by both) is not readable off the code today. Three lines above the func name the pairing rule and close part of CRF-13's structural complaint at the cheapest layer.

Process observation. Every author reply on the six re-raised threads is signed Response generated by Coder Agents. The R3 panel flagged this attribution pattern; R4 dropped the Maintainer decision: prefix on one reply (CRF-1) and left the pattern intact on the other five. Mafu-san verified that no non-agent author comment exists on the PR conversation for R4 (comments-full.md). The R4 CRF-1 body sentence is the closest visible human-adjacent artifact; the CRF-16 defense claims "the maintainer requested" via an agent-signed issue comment (IC_kwDOMGJiIM8AAAABPZyPoA) with no visible source. What would resolve the class in this PR without more code: a comment or PR-body byline from @ethanndickson without the Response generated by Coder Agents. footer that names the four scenarios (omitted-config saved-plan drift, explicit-true apply-fail, data-source silent-false, generated-doc omission) and either accepts each or links a ticket per accepted item.

Mafu-san on the R4 attribution: "dropping the visible prefix while keeping the pattern is self-awareness without behavior change, which is worse than not knowing because it looks like learning."

Counts: 4 R3 findings verified fixed, 6 re-raised (2 P2 with panel decision on partial acceptance, 3 P2 re-raised on their own axis, 1 Note re-raised with new R4 evidence, 1 Nit re-raised, 1 Nit that already re-raised R3 and stayed silent R4), 2 new Nits.


internal/provider/template_resource.go:913

Nit [CRF-16] R3 panel re-raise (5-1, new Razor evidence) stayed silent in R4. (Hisoka, Pariston re-raise)

R4 delta does not touch line 913. No new author reply engages the R3 evidence: templateResp at line 915 has a single call site at line 920 (newState.reconcileVersionedMetadata(&templateResp)), which reconciles MaxPortShareLevel (v2.15+), CORSBehavior (v2.26+), UseClassicParameterFlow, and AgentsAllowed (v2.37+). A maintainer honoring the TODO at a hypothetical v2.15+ minimum deletes the block and silently regresses state reconciliation for the v2.26+/v2.37+ fields; the compile-safety net Kite cited (deleting the block breaks line 920) is one adjacent line to delete in the same edit and no test would catch that either.

The R3 issue-comment defense (IC_kwDOMGJiIM8AAAABPZyPoA, The maintainer requested that the existing v2.15 compatibility TODO remain) is agent-signed with no visible non-agent artifact. Under "no agent-accepted permanence" the claim of maintainer intent needs a distinct source.

Minimum-viable fix: update the TODO to name the actual removal criterion, e.g., TODO: remove once the update response is authoritative for max_port_share_level, cors_behavior, use_classic_parameter_flow, agents_allowed. No behavior change.

🤖

🤖 This review was automatically generated with Coder Agents.

Comment thread internal/provider/template_resource_test.go Outdated
Comment thread internal/provider/template_resource.go
@ethanndickson
ethanndickson force-pushed the codagt-716/agents-allowed branch from eda33a0 to 8ece685 Compare August 19, 2026 09:45
@ethanndickson
ethanndickson requested a review from johnstcn August 19, 2026 09:46
@ethanndickson ethanndickson self-assigned this Aug 19, 2026
@ethanndickson
ethanndickson force-pushed the codagt-716/agents-allowed branch from 2b73027 to ec39e20 Compare August 20, 2026 10:08
@ethanndickson
ethanndickson merged commit 5e71be0 into main Aug 20, 2026
26 checks passed
@ethanndickson
ethanndickson deleted the codagt-716/agents-allowed branch August 20, 2026 10:16
ethanndickson added a commit that referenced this pull request Aug 20, 2026
Bumps `github.com/coder/coder/v2` from the previously pinned main commit
(`fbac602456c9`, 2026-07-28) to a newer `main` commit (`8a7e8d9d5b31`,
2026-08-19).

Resulting module version: `v2.34.0-rc.0.0.20260819135125-8a7e8d9d5b31`

## Breaking change

This SDK bump removes pricing fields from
`coderd_agents_model.model_config`. The following settings are no longer
supported and must be removed:

```hcl
model_config = jsonencode({
  cost = {
    input_price_per_million_tokens  = "3"
    output_price_per_million_tokens = "15"
  }
})
```

The four legacy top-level pricing settings are also removed:

- `input_price_per_million_tokens`
- `output_price_per_million_tokens`
- `cache_read_price_per_million_tokens`
- `cache_write_price_per_million_tokens`

The provider validates `model_config` against its pinned SDK.
Configurations with these pricing settings will fail at plan time.
Remove these settings before you upgrade the provider. Coder now gets
cost data from AI Gateway.

The example and generated documentation remove `model_config.cost`.

## Compatibility

This SDK bump does not set a new minimum Coder version for the
`coderd_template` resource. The follow-up #414 adds the optional
`agents_allowed` attribute. Explicit use of that attribute requires
Coder v2.37.0 or later.

## Release context

This change requires a provider release that is marked as breaking. The
release notes must include the `model_config` pricing migration. The
breaking change applies to `coderd_agents_model`.

This is the prerequisite layer for #414 and also includes the exported
`codersdk.SanitizePromptText` used by #412.

Refs
https://linear.app/codercom/issue/CODAGT-716/expose-agents-allowed-in-the-coderd-terraform-provider

<details>
<summary>Stack plan</summary>

1. Update the Coder SDK and remove obsolete chat model cost
configuration.
2. Add `agents_allowed` to the `coderd_template` resource and data
source in #414.

3. Add the deployment-wide chat system prompt resource in #412.

</details>

_Opened by Coder Agents on behalf of @ethanndickson._
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.

2 participants