Follow-up from #1920 / PR #1921 (cross-model review finding, adjudicated out-of-scope there).
Resource.parsePath resolves URL attribute-suffix routes (e.g. GET /Widget/id.label) by reading this.attributes directly:
(this as any).attributes?.find((a) => a.name === suffix)
A programmatic Resource that declares only static properties (no attributes Array) has attributes === undefined, so attribute-suffix routing silently doesn't resolve for it. This is a pre-existing gap (not introduced by #1921, which only touched schema derivation), surfaced now that #1921 makes static properties a first-class schema source.
Why not fixed in #1921
parsePath is a per-request hot path. The schema-derivation surfaces (#1921) use resolveAttributes(...), which projects properties → attributes on each call when attributes is empty — fine on the cold registration/introspection paths, but projecting on every request in parsePath is not acceptable.
Suggested approach
Cache the projected attribute Array on the class the first time it's needed (e.g. a lazily-computed #resolvedAttributes memo, invalidated on schema reload), then have parsePath (and any other per-request .attributes reader) use the memo. resolveAttributes from resources/jsonSchemaTypes.ts is the projection to reuse.
Acceptance
GET /X/id.field resolves for a programmatic Resource declaring static properties.
- No per-request projection cost (memoized).
- A test covering attribute-suffix routing on a programmatic
static properties Resource.
Issue generated by kAIle (Claude Opus 4.8).
Follow-up from #1920 / PR #1921 (cross-model review finding, adjudicated out-of-scope there).
Resource.parsePathresolves URL attribute-suffix routes (e.g.GET /Widget/id.label) by readingthis.attributesdirectly:A programmatic Resource that declares only
static properties(noattributesArray) hasattributes === undefined, so attribute-suffix routing silently doesn't resolve for it. This is a pre-existing gap (not introduced by #1921, which only touched schema derivation), surfaced now that #1921 makesstatic propertiesa first-class schema source.Why not fixed in #1921
parsePathis a per-request hot path. The schema-derivation surfaces (#1921) useresolveAttributes(...), which projectsproperties → attributeson each call whenattributesis empty — fine on the cold registration/introspection paths, but projecting on every request inparsePathis not acceptable.Suggested approach
Cache the projected attribute Array on the class the first time it's needed (e.g. a lazily-computed
#resolvedAttributesmemo, invalidated on schema reload), then haveparsePath(and any other per-request.attributesreader) use the memo.resolveAttributesfromresources/jsonSchemaTypes.tsis the projection to reuse.Acceptance
GET /X/id.fieldresolves for a programmatic Resource declaringstatic properties.static propertiesResource.Issue generated by kAIle (Claude Opus 4.8).