Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content/docs/contracts/example-cases.json
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@
"content/docs/source/api-reference/openapi/accounts.json": "1a5a04f9ec358a15b8339b7029c9fed5fe69c6f042c8b03b6b4f03f3aafdeeed",
"content/docs/source/api-reference/openapi/content.json": "f790ee44d1b881709e393a65500bec23493e21a391c7b66555e0c78750f95239",
"content/docs/source/api-reference/openapi/research.json": "f301a714e994e99b1dbcfc63ee18824537cf42813d8df3906ac7c2436a481ae0",
"content/docs/source/api-reference/openapi/releases.json": "d8e37689800283d88c02f0a728e5678c75873aec1b2da49df1ce8388e09a5e93",
"content/docs/source/api-reference/openapi/releases.json": "6294c1dfb36539d3279a2d4ae8b1f650dfcaf81f2611f44a5dfb928c3b141e22",
"content/docs/source/api-reference/openapi/social.json": "5bd167a78cf6a17c46724486e2921882be20969ea32f3c0297f5b7e7ba9a30aa",
"content/docs/source/api-reference/openapi/context.json": "7784ee1d8c4b6753cc47bf518f468effa58d50fb9d0289009edf0caad3d05a67",
"content/docs/source/api-reference/openapi/projects.json": "b059cf8baa83a7f73a3c15db19f54fa56e46a3840e91bd42979b83550f543ace",
Expand Down
4 changes: 2 additions & 2 deletions content/docs/contracts/operation-inventory.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"apiSourceCommit": "f56b6ae184b85e97ca3b7f1692378fea7a0b222b",
"apiSourceCommit": "1e7f42692fad476cf17744338b6e9412dbb26b6b",
"evidence": "Static source only; tool discovery and OAuth host verification remain separate. Conditional registration and scope filters mean this is not a promised catalog count.",
"operations": [
{
Expand Down Expand Up @@ -3765,7 +3765,7 @@
"content/docs/source/api-reference/openapi/context.json": "7784ee1d8c4b6753cc47bf518f468effa58d50fb9d0289009edf0caad3d05a67",
"content/docs/source/api-reference/openapi/players.json": "4a4c90583fe1de6487444581b293a32b1cc04622fc929965ab90f365feb8bc94",
"content/docs/source/api-reference/openapi/projects.json": "b059cf8baa83a7f73a3c15db19f54fa56e46a3840e91bd42979b83550f543ace",
"content/docs/source/api-reference/openapi/releases.json": "d8e37689800283d88c02f0a728e5678c75873aec1b2da49df1ce8388e09a5e93",
"content/docs/source/api-reference/openapi/releases.json": "6294c1dfb36539d3279a2d4ae8b1f650dfcaf81f2611f44a5dfb928c3b141e22",
"content/docs/source/api-reference/openapi/research.json": "f301a714e994e99b1dbcfc63ee18824537cf42813d8df3906ac7c2436a481ae0",
"content/docs/source/api-reference/openapi/sandbox.json": "c61a2bb965b9c9a1eade2e226fdc8af0cb1aa2213f23236d8607d13b65dbec15",
"content/docs/source/api-reference/openapi/sessions.json": "85af56cc150374b28c25541c45db15849c71fdeb6288cf90dc2beb08f494e83e",
Expand Down
2 changes: 1 addition & 1 deletion content/docs/manifest.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions content/docs/source/api-reference/openapi/releases.json
Original file line number Diff line number Diff line change
Expand Up @@ -2700,7 +2700,7 @@
"post": {
"operationId": "postValuation",
"summary": "Run valuation",
"description": "Generate a catalog from a Spotify artist in one call. Resolves the artist's releases, captures current Spotify play counts (spending the account's credits), materializes a catalog from the resulting snapshot (idempotent - see [Create catalog](/api-reference/songs/catalogs-create)), and returns the catalog with its estimated value band. The catalog is owned by the calling account unless organization_id names one of the caller's organizations to own it instead, in which case every member of that organization sees it. The calling account is always taken from the credentials, never the body, and it is the account whose credits are spent. The searched artist is also linked to the caller's roster (so a funnel signup lands with a populated `GET /api/artists` it can confirm); when the catalog's songs already resolve a canonical artist that one is used, otherwise the searched Spotify artist is linked directly. Synchronous: the request waits for the capture to land (typically under two minutes). Each run also persists a row in the catalog's valuation history, readable via [Get Catalog Valuations](/api-reference/songs/catalog-valuations).",
"description": "Generate a catalog from a Spotify artist in one call. Resolves the artist's releases, captures current Spotify play counts (spending the account's credits), materializes a catalog from the resulting snapshot (idempotent - see [Create catalog](/api-reference/songs/catalogs-create)), and returns the catalog with its estimated value band. Credentials are authenticated before the request body is handled. The effective account defaults to the authenticated account; an authorized account_id override runs the valuation for the specified account instead. The effective account's credits fund the measurement, and it owns the catalog unless organization_id selects an organization it is authorized to use as catalog owner. Organization access is checked for the effective account. The searched artist is also linked to the effective account's roster (so a funnel signup lands with a populated `GET /api/artists` it can confirm); when the catalog's songs already resolve a canonical artist that one is used, otherwise the searched Spotify artist is linked directly. Synchronous: the request waits for the capture to land (typically under two minutes). The returned band is a current computed estimate; this operation does not persist a valuation-history row. Saved history and account-scoped history readback remain unfinished; see [Valuation history availability](/api-reference/songs/catalog-valuations).",
"security": [
{
"apiKeyAuth": []
Expand Down Expand Up @@ -4384,7 +4384,7 @@
"organization_id": {
"type": "string",
"format": "uuid",
"description": "Optional. ID of an organization to own the resulting catalog instead of the calling account. Every member of that organization then sees it in their own [Get Catalogs](/api-reference/songs/catalogs) response. The caller must be a member of the organization; otherwise the request is rejected with 403. Credits are still spent by the calling account, and the searched artist is still linked to the caller's roster. Omit to own the catalog personally, which is the default."
"description": "Optional. ID of an organization to own the resulting catalog instead of the effective account (the authenticated account by default, or the account selected by an authorized account_id override). Access is allowed when the effective account is that organization or is a member of it; otherwise the request is rejected with 403. Credits are still spent by the effective account, and the searched artist is still linked to its roster. Omit to use the effective account as catalog owner."
},
"account_id": {
"type": "string",
Expand Down
4 changes: 2 additions & 2 deletions content/docs/source/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17094,7 +17094,7 @@ This operation requires one of the security alternatives in the specification be
"post": {
"operationId": "postValuation",
"summary": "Run valuation",
"description": "Generate a catalog from a Spotify artist in one call. Resolves the artist's releases, captures current Spotify play counts (spending the account's credits), materializes a catalog from the resulting snapshot (idempotent - see [Create catalog](https://docs.recoupable.dev/api-reference/songs/catalogs-create)), and returns the catalog with its estimated value band. The catalog is owned by the calling account unless organization_id names one of the caller's organizations to own it instead, in which case every member of that organization sees it. The calling account is always taken from the credentials, never the body, and it is the account whose credits are spent. The searched artist is also linked to the caller's roster (so a funnel signup lands with a populated `GET /api/artists` it can confirm); when the catalog's songs already resolve a canonical artist that one is used, otherwise the searched Spotify artist is linked directly. Synchronous: the request waits for the capture to land (typically under two minutes). Each run also persists a row in the catalog's valuation history, readable via [Get Catalog Valuations](https://docs.recoupable.dev/api-reference/songs/catalog-valuations).",
"description": "Generate a catalog from a Spotify artist in one call. Resolves the artist's releases, captures current Spotify play counts (spending the account's credits), materializes a catalog from the resulting snapshot (idempotent - see [Create catalog](https://docs.recoupable.dev/api-reference/songs/catalogs-create)), and returns the catalog with its estimated value band. Credentials are authenticated before the request body is handled. The effective account defaults to the authenticated account; an authorized account_id override runs the valuation for the specified account instead. The effective account's credits fund the measurement, and it owns the catalog unless organization_id selects an organization it is authorized to use as catalog owner. Organization access is checked for the effective account. The searched artist is also linked to the effective account's roster (so a funnel signup lands with a populated `GET /api/artists` it can confirm); when the catalog's songs already resolve a canonical artist that one is used, otherwise the searched Spotify artist is linked directly. Synchronous: the request waits for the capture to land (typically under two minutes). The returned band is a current computed estimate; this operation does not persist a valuation-history row. Saved history and account-scoped history readback remain unfinished; see [Valuation history availability](https://docs.recoupable.dev/api-reference/songs/catalog-valuations).",
"security": [
{
"apiKeyAuth": []
Expand Down Expand Up @@ -17204,7 +17204,7 @@ This operation requires one of the security alternatives in the specification be
"organization_id": {
"type": "string",
"format": "uuid",
"description": "Optional. ID of an organization to own the resulting catalog instead of the calling account. Every member of that organization then sees it in their own [Get Catalogs](https://docs.recoupable.dev/api-reference/songs/catalogs) response. The caller must be a member of the organization; otherwise the request is rejected with 403. Credits are still spent by the calling account, and the searched artist is still linked to the caller's roster. Omit to own the catalog personally, which is the default."
"description": "Optional. ID of an organization to own the resulting catalog instead of the effective account (the authenticated account by default, or the account selected by an authorized account_id override). Access is allowed when the effective account is that organization or is a member of it; otherwise the request is rejected with 403. Credits are still spent by the effective account, and the searched artist is still linked to its roster. Omit to use the effective account as catalog owner."
},
"account_id": {
"type": "string",
Expand Down
31 changes: 31 additions & 0 deletions tests/unsupported-operation-discovery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,34 @@ test("existing help URLs retain unfinished outcomes and scoped alternatives", ()
expect(music.body).toContain(path);
}
});


test("valuation estimates do not advertise unfinished history persistence or readback", () => {
const spec = JSON.parse(readFileSync(join(source, "api-reference/openapi/releases.json"), "utf8"));
const description = spec.paths["/api/valuation"].post.description as string;
expect(description).not.toMatch(/each run.*persists|readable via \[Get Catalog Valuations\]/i);
expect(description).toContain("does not persist a valuation-history row");
expect(description).toContain("/api-reference/songs/catalog-valuations");
const availability = readFileSync(join(source, "api-reference/songs/catalog-valuations.mdx"), "utf8");
expect(availability).toContain("Saved catalog valuation history is not available");
expect(spec.paths["/api/catalogs/{catalogId}/valuations"]).toBeUndefined();
const published = readFileSync(join(source, "llms-full.txt"), "utf8");
expect(published).not.toContain("Each run also persists a row in the catalog's valuation history");
expect(published).toContain("does not persist a valuation-history row");
});


test("valuation descriptions agree on the authorized effective account", () => {
const spec = JSON.parse(readFileSync(join(source, "api-reference/openapi/releases.json"), "utf8"));
const description = spec.paths["/api/valuation"].post.description as string;
const properties = spec.components.schemas.RunValuationRequest.properties;
expect(properties.account_id.description).toContain("authenticated account has access to the target account");
expect(description).toContain("defaults to the authenticated account");
expect(description).toContain("authorized account_id override");
for (const text of [description, properties.organization_id.description]) {
expect(text).toContain("effective account");
expect(text).not.toMatch(/never the body|every member|caller must be a member|calling account.*credits|caller's roster/i);
}
expect(properties.organization_id.description).toContain("is that organization or is a member");
expect(properties.organization_id.description).toContain("403");
});
Loading