Skip to content

feat: read a list resource's path parameters from its list block - #90

Merged
ShocOne merged 1 commit into
mainfrom
feat/list-resource-addressing-schema
Aug 14, 2026
Merged

feat: read a list resource's path parameters from its list block#90
ShocOne merged 1 commit into
mainfrom
feat/list-resource-addressing-schema

Conversation

@ShocOne

@ShocOne ShocOne commented Aug 14, 2026

Copy link
Copy Markdown
Member

The problem

A list.ListResource has two schemas: ListResourceConfigSchema for the
list {} block, and the resource schema for each result. The toolkit only ever
filled the second. So a collection path like /orgs/{org}/… had nowhere to read
org from, and emission refused the entity outright.

derive.go:271, :405 and :429 all call ensureParentParameters;
listResource at :440 did not, and render_listresource.go:77 then hard-refused
any list call carrying path parameters.

What changed

  • ir.ListResource.AddressingSchema — the addressing attributes the
    collection path requires, as a tree of their own. Built with the existing
    ensureParentParameters. Every parameter is a parent, because a collection
    path carries no item key to absorb the last one. RequiresReplace is cleared:
    a list block declares a query, and a query has no plan for a modifier to act on.
  • render_listresource.go — builds config nodes through the existing
    joinTree/addressingNames machinery, plans the call against them, and drops
    the refusal.
  • schemaBuilder gains the list/schema package and rendersComputed().
    Every list/schema attribute answers false from IsComputed, so it degrades
    like an action schema. The schema. qualifier was hard-coded; it is now
    sb.pkg().
  • paramFailure — a failed path-parameter conversion reports through the
    method it lands in rather than assuming one. Every lifecycle and invoke method
    carries a resp with Diagnostics; List carries a results stream and no
    resp, so the previously-hard-coded resp.Diagnostics.AddAttributeError would
    not have compiled there.
  • Templates: the config schema, a listConfigModel, req.Config.Get in List,
    the query example supplies the required addressing, and the generated unit test
    matches a parameterised path by pattern and stands a configuration up.

Measured effect

−140 refusals; +140 whole list resources.

refusals before after list resources before after
github 937 827 23 133
jamfpro 319 290 45 74
thousandeyes 344 343 1 2
total 1,600 1,460 69 209

The report diff is precisely what was predicted:

github jamfpro thousandeyes
matches no scalar attribute and the entity has no id attribute 119 27 14
a list resource cannot supply path parameters 42 30 5
+ the element carries no scalar id attribute to publish as the list identity 50 28 18
+ is string in the schema but int32 in the generated SDK 1

All 237 path-parameter list-resource refusals are gone. The 96 new ones are
those entities reaching emission for the first time and hitting their next
refusal — the #80 lesson, read the reasons rather than the total. The one new
type-mismatch is fixed by #88.

tfpfgen provider verify reports no drift on all three; postcheck
(go mod tidy, go build, go vet) passes on all three.

What I checked that is not green, and why it is not this PR

The generated providers' own unit tests fail, and they failed before this change.
Measured on main, scratch/gen/github:

suite packages failing cases panics
list resources 23 23 6
resources 56 62

That is a 100% failure rate before and after; this change adds no new failure
kind, only more instances of pre-existing ones. postcheck does not run
go test, which is why it was never visible. Root causes so far: the mock
response's content type (#89), and internal/fixtures synthesising
tfpfgen-test-created-at into a date-time field — which needs format carried
into the IR, work this tranche has not reached. The panics are
elements := result.GetEnvelope() on a nil payload, downstream of the same.

I did not fold that in: it is repo-wide, multi-cause, and independent of this
change. It wants its own tranche.

Merge ordering

#88 touches paramDeclaration in the same file. Per CLAUDE.md both were cut
fresh from main rather than stacked, so whichever merges second needs a small
rebase there. Happy to do it on request.

Gates

  • gofmt -l internal cmd — empty
  • scripts/repo_hygiene_gate.sh — pass
  • golangci-lint run — 0 issues
  • go build ./... && go vet ./... — pass
  • go test ./... — pass, coverage 91.3% total

New toolkit tests: internal/emit/render_listresource_test.go (4) and
TestUnit_AddressingSchema_TakesEveryPathParameter.

🤖 Generated with Claude Code

A collection path like /orgs/{org}/… had nowhere to read org from: the
toolkit filled only the element schema, so emission refused the entity.
A list resource now declares the addressing its collection path requires
as the configuration of its list block, and reads it from req.Config.

The derivation reuses ensureParentParameters, which the resource and
datasource paths already call; every parameter is a parent, because a
collection path carries no item key. None carries RequiresReplace: a
list block declares a query, and a query has no plan to modify.

A failed path-parameter conversion now reports through the method it
lands in rather than assuming one: every lifecycle and invoke method
carries a resp with Diagnostics, and List carries a results stream.

schemaBuilder gains the list/schema package and the fact that it, like
the action package, declares no Computed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ShocOne
ShocOne force-pushed the feat/list-resource-addressing-schema branch from e11b602 to 5ad1d99 Compare August 14, 2026 14:39
@ShocOne
ShocOne merged commit 7673c2f into main Aug 14, 2026
1 of 2 checks passed
@ShocOne
ShocOne deleted the feat/list-resource-addressing-schema branch August 14, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant